From: Mark Wielaard Date: Mon, 30 Dec 2013 21:00:57 +0000 (+0100) Subject: libdwfl: Add dwfl_core_file_attach and dwfl_linux_proc_attach. X-Git-Tag: elfutils-0.158~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=19108019192ab273c53ae324be448d29dac806ca;p=thirdparty%2Felfutils.git libdwfl: Add dwfl_core_file_attach and dwfl_linux_proc_attach. Rewrite __libdwfl_attach_state_for_pid and __libdwfl_attach_state_for_core as public functions and don't call them from dwfl_linux_proc_report and dwfl_core_file_report anymore. This lets the user attach state explicitly independ from how the dwfl modules have been reported. Since attaching state is an explicit action now the error can be returned directly and we don't need to keep track of process_attach_error. dwfl_linux_proc_attach lets the user can tell libdwfl whether caller takes care of ptrace attaching and stopping the threads under inspection, or whether the callback needs to take care of that and detaching again. Signed-off-by: Mark Wielaard --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 2b677595a..6e779c8e3 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,8 @@ +2013-12-30 Mark Wielaard + + * libdw.map (ELFUTILS_0.158): Add dwfl_core_file_attach and + dwfl_linux_proc_attach. + 2013-12-20 Mark Wielaard * libdw.map (ELFUTILS_0.158): Add dwfl_getthread_frames. diff --git a/libdw/libdw.map b/libdw/libdw.map index 08c4ddcc4..d0e473174 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -288,4 +288,7 @@ ELFUTILS_0.158 { dwfl_module_getsymtab_first_global; dwfl_module_addrinfo; dwfl_module_getsym_info; + + dwfl_core_file_attach; + dwfl_linux_proc_attach; } ELFUTILS_0.157; diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 6c983b2b4..2190899ee 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,35 @@ +2013-12-30 Mark Wielaard + + * argp-std.c (parse_opt): Call dwfl_linux_proc_attach and + dwfl_core_file_attach explicitly. + * core-file.c (dwfl_core_file_report): Don't call + __libdwfl_attach_state_for_core implicitly. + * dwfl_begin.c (dwfl_begin): Remove setting of process_attach_error. + * dwfl_frame.c (dwfl_pid): Set errno to DWFL_E_NO_ATTACH_STATE, not + process_attach_error. + (dwfl_getthreads): Likewise. + (getthread): Likewise. + * libdwfl.h (dwfl_core_file_report): Update documentation. + (dwfl_linux_proc_report): Likewise. + (dwfl_core_file_attach): New function declaration. + (dwfl_linux_proc_attach): Likewise. + * libdwflP.h (struct Dwfl): Remove process_attach_error. + (__libdwfl_attach_state_for_pid): Removed declaration. + (__libdwfl_attach_state_for_core): Likewise. + (dwfl_core_file_attach): New internal declaration. + (dwfl_linux_proc_attach): Likewise. + (attach_state_for_core): Renamed to... + (dwfl_core_file_attach): ...this. Change return type. + (__libdwfl_attach_state_for_core): Removed. + * linux-pid-attach.c (struct pid_arg): Add assume_ptrace_stopped. + (pid_set_initial_registers): Check assume_ptrace_stopped before + calling ptrace. + (pid_thread_detach): Likewise. + (__libdwfl_attach_state_for_pid): Renamed to... + (dwfl_linux_proc_attach): ...this. Adjust return type. + * linux-proc-maps.c (dwfl_linux_proc_report): Don't call + __libdwfl_attach_state_for_pid implicitly. + 2013-12-28 Mark Wielaard * linux-proc-maps.c (dwfl_linux_proc_find_elf): Don't return special diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c index cf178eee4..3a2d2a59e 100644 --- a/libdwfl/argp-std.c +++ b/libdwfl/argp-std.c @@ -170,6 +170,11 @@ parse_opt (int key, char *arg, struct argp_state *state) int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg)); if (result != 0) return fail (dwfl, result, arg); + + result = INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false); + if (result != 0) + /* Non-fatal to not be able to attach to process. */ + failure (dwfl, result, _("cannot attach to process")); opt->dwfl = dwfl; } else @@ -296,6 +301,11 @@ parse_opt (int key, char *arg, struct argp_state *state) return fail (dwfl, result, opt->core); } + result = INTUSE(dwfl_core_file_attach) (dwfl, core); + if (result < 0) + /* Non-fatal to not be able to attach to core. */ + failure (dwfl, result, _("cannot attach to core")); + /* From now we leak FD and CORE. */ if (result == 0) diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c index 92745bd68..4ce63c4e6 100644 --- a/libdwfl/core-file.c +++ b/libdwfl/core-file.c @@ -559,13 +559,6 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) clear_r_debug_info (&r_debug_info); - if (listed > 0) - { - /* Possible error is ignored, DWFL still may be useful for non-unwinding - operations. */ - __libdwfl_attach_state_for_core (dwfl, elf); - } - /* We return the number of modules we found if we found any. If we found none, we return -1 instead of 0 if there was an error rather than just nothing found. */ diff --git a/libdwfl/dwfl_begin.c b/libdwfl/dwfl_begin.c index 490da9054..44c16a921 100644 --- a/libdwfl/dwfl_begin.c +++ b/libdwfl/dwfl_begin.c @@ -44,7 +44,6 @@ dwfl_begin (const Dwfl_Callbacks *callbacks) { dwfl->callbacks = callbacks; dwfl->offline_next_address = OFFLINE_REDZONE; - dwfl->process_attach_error = DWFL_E_NO_ATTACH_STATE; } return dwfl; diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c index 28008e903..e45cf14c8 100644 --- a/libdwfl/dwfl_frame.c +++ b/libdwfl/dwfl_frame.c @@ -200,7 +200,7 @@ dwfl_pid (Dwfl *dwfl) { if (dwfl->process == NULL) { - __libdwfl_seterrno (dwfl->process_attach_error); + __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE); return -1; } return dwfl->process->pid; @@ -235,7 +235,7 @@ dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg), Dwfl_Process *process = dwfl->process; if (process == NULL) { - __libdwfl_seterrno (dwfl->process_attach_error); + __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE); return -1; } @@ -306,7 +306,7 @@ getthread (Dwfl *dwfl, pid_t tid, Dwfl_Process *process = dwfl->process; if (process == NULL) { - __libdwfl_seterrno (dwfl->process_attach_error); + __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE); return -1; } diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h index 67785ea30..2bb4f455a 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -361,16 +361,13 @@ extern int dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, supply non-NULL EXECUTABLE, otherwise dynamic libraries will not be loaded into the DWFL map. This might call dwfl_report_elf on file names found in the dump if reading some link_map files is the only way to ascertain those - modules' addresses. dwfl_attach_state is also called for DWFL, - dwfl_core_file_report does not fail if the dwfl_attach_state call has failed. - Returns the number of modules reported, or -1 for errors. */ + modules' addresses. Returns the number of modules reported, or -1 for + errors. */ extern int dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable); /* Call dwfl_report_module for each file mapped into the address space of PID. - dwfl_attach_state is also called for DWFL, dwfl_linux_proc_report does - not fail if the dwfl_attach_state call has failed. Returns zero on success, -1 if dwfl_report_module failed, - or an errno code if opening the kernel binary failed. */ + or an errno code if opening the proc files failed. */ extern int dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid); /* Similar, but reads an input stream in the format of Linux /proc/PID/maps @@ -717,6 +714,23 @@ bool dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid, void *dwfl_arg) __nonnull_attribute__ (1, 4); +/* Calls dwfl_attach_state with Dwfl_Thread_Callbacks setup for extracting + thread state from the ELF core file. Returns the pid number extracted + from the core file, or -1 for errors. */ +extern int dwfl_core_file_attach (Dwfl *dwfl, Elf *elf); + +/* Calls dwfl_attach_state with Dwfl_Thread_Callbacks setup for extracting + thread state from the proc file system. Uses ptrace to attach and stop + the thread under inspection and detaches when thread_detach is called + and unwinding for the thread is done, unless ASSUME_PTRACE_STOPPED is + true. If ASSUME_PTRACE_STOPPED is true the caller should make sure that + the thread is ptrace attached and stopped before unwinding by calling + either dwfl_thread_getframes or dwfl_getthread_frames. Returns zero on + success, -1 if dwfl_attach_state failed, or an errno code if opening the + proc files failed. */ +extern int dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, + bool assume_ptrace_stopped); + /* Return PID for the process associated with DWFL. Function returns -1 if dwfl_attach_state was not called for DWFL. */ pid_t dwfl_pid (Dwfl *dwfl) diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 63615a8a5..710e69923 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -108,7 +108,6 @@ struct Dwfl Dwfl_Module *modulelist; /* List in order used by full traversals. */ Dwfl_Process *process; - Dwfl_Error process_attach_error; GElf_Addr offline_next_address; @@ -531,14 +530,6 @@ extern void __libdwfl_process_free (Dwfl_Process *process) extern void __libdwfl_frame_unwind (Dwfl_Frame *state) internal_function; -/* Call dwfl_attach_state for PID, return true if successful. */ -extern bool __libdwfl_attach_state_for_pid (Dwfl *dwfl, pid_t pid) - internal_function; - -/* Call dwfl_attach_state for CORE, return true if successful. */ -extern bool __libdwfl_attach_state_for_core (Dwfl *dwfl, Elf *core) - internal_function; - /* Align segment START downwards or END upwards addresses according to DWFL. */ extern GElf_Addr __libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start) internal_function; @@ -657,6 +648,7 @@ INTDECL (dwfl_addrmodule) INTDECL (dwfl_addrsegment) INTDECL (dwfl_addrdwarf) INTDECL (dwfl_addrdie) +INTDECL (dwfl_core_file_attach) INTDECL (dwfl_core_file_report) INTDECL (dwfl_getmodules) INTDECL (dwfl_module_addrdie) @@ -685,6 +677,7 @@ INTDECL (dwfl_standard_find_debuginfo) INTDECL (dwfl_link_map_report) INTDECL (dwfl_linux_kernel_find_elf) INTDECL (dwfl_linux_kernel_module_section_address) +INTDECL (dwfl_linux_proc_attach) INTDECL (dwfl_linux_proc_report) INTDECL (dwfl_linux_proc_maps_report) INTDECL (dwfl_linux_proc_find_elf) diff --git a/libdwfl/linux-core-attach.c b/libdwfl/linux-core-attach.c index cc11467b2..1002788e1 100644 --- a/libdwfl/linux-core-attach.c +++ b/libdwfl/linux-core-attach.c @@ -306,30 +306,36 @@ static const Dwfl_Thread_Callbacks core_thread_callbacks = NULL, /* core_thread_detach */ }; -static Dwfl_Error -attach_state_for_core (Dwfl *dwfl, Elf *core) +int +dwfl_core_file_attach (Dwfl *dwfl, Elf *core) { Ebl *ebl = ebl_openbackend (core); if (ebl == NULL) - return DWFL_E_LIBEBL; + { + __libdwfl_seterrno (DWFL_E_LIBEBL); + return -1; + } size_t nregs = ebl_frame_nregs (ebl); if (nregs == 0) { + __libdwfl_seterrno (DWFL_E_NO_UNWIND); ebl_closebackend (ebl); - return DWFL_E_NO_UNWIND; + return -1; } GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem); if (ehdr == NULL) { + __libdwfl_seterrno (DWFL_E_LIBELF); ebl_closebackend (ebl); - return DWFL_E_LIBELF; + return -1; } assert (ehdr->e_type == ET_CORE); size_t phnum; if (elf_getphdrnum (core, &phnum) < 0) { + __libdwfl_seterrno (DWFL_E_LIBELF); ebl_closebackend (ebl); - return DWFL_E_LIBELF; + return -1; } pid_t pid = -1; Elf_Data *note_data = NULL; @@ -388,14 +394,16 @@ attach_state_for_core (Dwfl *dwfl, Elf *core) if (pid == -1) { /* No valid NT_PRPSINFO recognized in this CORE. */ + __libdwfl_seterrno (DWFL_E_BADELF); ebl_closebackend (ebl); - return DWFL_E_BADELF; + return -1; } struct core_arg *core_arg = malloc (sizeof *core_arg); if (core_arg == NULL) { + __libdwfl_seterrno (DWFL_E_NOMEM); ebl_closebackend (ebl); - return DWFL_E_NOMEM; + return -1; } core_arg->core = core; core_arg->note_data = note_data; @@ -404,31 +412,10 @@ attach_state_for_core (Dwfl *dwfl, Elf *core) if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks, core_arg)) { - Dwfl_Error error = dwfl_errno (); - assert (error != DWFL_E_NOERROR); free (core_arg); ebl_closebackend (ebl); - return error; - } - return DWFL_E_NOERROR; -} - -bool -internal_function -__libdwfl_attach_state_for_core (Dwfl *dwfl, Elf *core) -{ - if (dwfl->process != NULL) - { - __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT); - return false; + return -1; } - Dwfl_Error error = attach_state_for_core (dwfl, core); - assert ((dwfl->process != NULL) == (error == DWFL_E_NOERROR)); - dwfl->process_attach_error = error; - if (error != DWFL_E_NOERROR) - { - __libdwfl_seterrno (error); - return false; - } - return true; + return pid; } +INTDEF (dwfl_core_file_attach) diff --git a/libdwfl/linux-pid-attach.c b/libdwfl/linux-pid-attach.c index 70bd666af..21ff4b99e 100644 --- a/libdwfl/linux-pid-attach.c +++ b/libdwfl/linux-pid-attach.c @@ -44,6 +44,8 @@ struct pid_arg pid_t tid_attached; /* Valid only if TID_ATTACHED is not zero. */ bool tid_was_stopped; + /* True if threads are ptrace stopped by caller. */ + bool assume_ptrace_stopped; }; static bool @@ -239,7 +241,8 @@ pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg) struct pid_arg *pid_arg = thread_arg; assert (pid_arg->tid_attached == 0); pid_t tid = INTUSE(dwfl_thread_tid) (thread); - if (! ptrace_attach (tid, &pid_arg->tid_was_stopped)) + if (! pid_arg->assume_ptrace_stopped + && ! ptrace_attach (tid, &pid_arg->tid_was_stopped)) return false; pid_arg->tid_attached = tid; Dwfl_Process *process = thread->process; @@ -263,12 +266,16 @@ pid_thread_detach (Dwfl_Thread *thread, void *thread_arg) pid_t tid = INTUSE(dwfl_thread_tid) (thread); assert (pid_arg->tid_attached == tid); pid_arg->tid_attached = 0; - /* This handling is needed only on older Linux kernels such as - 2.6.32-358.23.2.el6.ppc64. Later kernels such as 3.11.7-200.fc19.x86_64 - remember the T (stopped) state themselves and no longer need to pass - SIGSTOP during PTRACE_DETACH. */ - ptrace (PTRACE_DETACH, tid, NULL, - (void *) (intptr_t) (pid_arg->tid_was_stopped ? SIGSTOP : 0)); + if (! pid_arg->assume_ptrace_stopped) + { + /* This handling is needed only on older Linux kernels such as + 2.6.32-358.23.2.el6.ppc64. Later kernels such as + 3.11.7-200.fc19.x86_64 remember the T (stopped) state + themselves and no longer need to pass SIGSTOP during + PTRACE_DETACH. */ + ptrace (PTRACE_DETACH, tid, NULL, + (void *) (intptr_t) (pid_arg->tid_was_stopped ? SIGSTOP : 0)); + } } static const Dwfl_Thread_Callbacks pid_thread_callbacks = @@ -281,9 +288,8 @@ static const Dwfl_Thread_Callbacks pid_thread_callbacks = pid_thread_detach, }; -bool -internal_function -__libdwfl_attach_state_for_pid (Dwfl *dwfl, pid_t pid) +int +dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped) { char buffer[36]; FILE *procfile; @@ -293,7 +299,7 @@ __libdwfl_attach_state_for_pid (Dwfl *dwfl, pid_t pid) snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid); procfile = fopen (buffer, "r"); if (procfile == NULL) - return false; + return errno; char *line = NULL; size_t linelen = 0; @@ -307,32 +313,30 @@ __libdwfl_attach_state_for_pid (Dwfl *dwfl, pid_t pid) fclose (procfile); if (pid == 0) - return false; + return ESRCH; char dirname[64]; int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid); assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1); DIR *dir = opendir (dirname); if (dir == NULL) - { - __libdwfl_seterrno (DWFL_E_ERRNO); - return false; - } + return errno; struct pid_arg *pid_arg = malloc (sizeof *pid_arg); if (pid_arg == NULL) { closedir (dir); - __libdwfl_seterrno (DWFL_E_NOMEM); - return false; + return ENOMEM; } pid_arg->dir = dir; pid_arg->tid_attached = 0; + pid_arg->assume_ptrace_stopped = assume_ptrace_stopped; if (! INTUSE(dwfl_attach_state) (dwfl, NULL, pid, &pid_thread_callbacks, pid_arg)) { closedir (dir); free (pid_arg); - return false; + return -1; } - return true; + return 0; } +INTDEF (dwfl_linux_proc_attach) diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c index b1f8b331a..cdb6959db 100644 --- a/libdwfl/linux-proc-maps.c +++ b/libdwfl/linux-proc-maps.c @@ -301,13 +301,6 @@ dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) fclose (f); - if (result == 0) - { - /* Possible error is ignored, DWFL still may be useful for non-unwinding - operations. */ - __libdwfl_attach_state_for_pid (dwfl, pid); - } - return result; } INTDEF (dwfl_linux_proc_report) diff --git a/src/ChangeLog b/src/ChangeLog index cb9c8151b..811004d34 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2013-12-30 Mark Wielaard + + * stack.c (parse_opt): Explicitly call dwfl_linux_proc_attach + or dwfl_core_file_attach and check for errors. + 2013-12-28 Mark Wielaard * stack.c (print_frames): Remove address width code and use... diff --git a/src/stack.c b/src/stack.c index 156455c05..2c1d8ff73 100644 --- a/src/stack.c +++ b/src/stack.c @@ -443,6 +443,22 @@ parse_opt (int key, char *arg __attribute__ ((unused)), if (dwfl_report_end (dwfl, NULL, NULL) != 0) error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); + if (pid != 0) + { + int err = dwfl_linux_proc_attach (dwfl, pid, false); + if (err < 0) + error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %d: %s", pid, + dwfl_errmsg (-1)); + else if (err > 0) + error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %d", pid); + } + + if (core != NULL) + { + if (dwfl_core_file_attach (dwfl, core) < 0) + error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1)); + } + /* Makes sure we are properly attached. */ if (dwfl_pid (dwfl) < 0) error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1)); diff --git a/tests/ChangeLog b/tests/ChangeLog index 23c5051da..5c80e9bf5 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2013-12-30 Mark Wielaard + + * backtrace-dwarf.c (report_pid): Explicitly call + dwfl_linux_proc_attach and check for errors. + * backtrace.c (report_pid): Likewise. + 2013-12-21 Mark Wielaard * backtrace.c (callback_verify): Only assert that case 5 is the last diff --git a/tests/backtrace-dwarf.c b/tests/backtrace-dwarf.c index aa12315a5..3a3e76328 100644 --- a/tests/backtrace-dwarf.c +++ b/tests/backtrace-dwarf.c @@ -41,6 +41,12 @@ report_pid (Dwfl *dwfl, pid_t pid) if (dwfl_report_end (dwfl, NULL, NULL) != 0) error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); + + result = dwfl_linux_proc_attach (dwfl, pid, false); + if (result < 0) + error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1)); + else if (result > 0) + error (2, result, "dwfl_linux_proc_attach"); } static Dwfl * diff --git a/tests/backtrace.c b/tests/backtrace.c index 8a7d6dfcb..64f90c433 100644 --- a/tests/backtrace.c +++ b/tests/backtrace.c @@ -279,6 +279,12 @@ report_pid (Dwfl *dwfl, pid_t pid) if (dwfl_report_end (dwfl, NULL, NULL) != 0) error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); + + result = dwfl_linux_proc_attach (dwfl, pid, false); + if (result < 0) + error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1)); + else if (result > 0) + error (2, result, "dwfl_linux_proc_attach"); } static Dwfl *