diff options
| -rw-r--r-- | libdw/ChangeLog | 5 | ||||
| -rw-r--r-- | libdw/libdw.map | 3 | ||||
| -rw-r--r-- | libdwfl/ChangeLog | 32 | ||||
| -rw-r--r-- | libdwfl/argp-std.c | 10 | ||||
| -rw-r--r-- | libdwfl/core-file.c | 7 | ||||
| -rw-r--r-- | libdwfl/dwfl_begin.c | 1 | ||||
| -rw-r--r-- | libdwfl/dwfl_frame.c | 6 | ||||
| -rw-r--r-- | libdwfl/libdwfl.h | 26 | ||||
| -rw-r--r-- | libdwfl/libdwflP.h | 11 | ||||
| -rw-r--r-- | libdwfl/linux-core-attach.c | 51 | ||||
| -rw-r--r-- | libdwfl/linux-pid-attach.c | 44 | ||||
| -rw-r--r-- | libdwfl/linux-proc-maps.c | 7 | ||||
| -rw-r--r-- | src/ChangeLog | 5 | ||||
| -rw-r--r-- | src/stack.c | 16 | ||||
| -rw-r--r-- | tests/ChangeLog | 6 | ||||
| -rw-r--r-- | tests/backtrace-dwarf.c | 6 | ||||
| -rw-r--r-- | tests/backtrace.c | 6 |
17 files changed, 157 insertions, 85 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 2b677595..6e779c8e 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,8 @@ +2013-12-30 Mark Wielaard <[email protected]> + + * libdw.map (ELFUTILS_0.158): Add dwfl_core_file_attach and + dwfl_linux_proc_attach. + 2013-12-20 Mark Wielaard <[email protected]> * libdw.map (ELFUTILS_0.158): Add dwfl_getthread_frames. diff --git a/libdw/libdw.map b/libdw/libdw.map index 08c4ddcc..d0e47317 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 6c983b2b..2190899e 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,35 @@ +2013-12-30 Mark Wielaard <[email protected]> + + * 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 <[email protected]> * 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 cf178eee..3a2d2a59 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 92745bd6..4ce63c4e 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 490da905..44c16a92 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 28008e90..e45cf14c 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 67785ea3..2bb4f455 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 63615a8a..710e6992 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 cc11467b..1002788e 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 70bd666a..21ff4b99 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 b1f8b331..cdb6959d 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 cb9c8151..811004d3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2013-12-30 Mark Wielaard <[email protected]> + + * stack.c (parse_opt): Explicitly call dwfl_linux_proc_attach + or dwfl_core_file_attach and check for errors. + 2013-12-28 Mark Wielaard <[email protected]> * stack.c (print_frames): Remove address width code and use... diff --git a/src/stack.c b/src/stack.c index 156455c0..2c1d8ff7 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 23c5051d..5c80e9bf 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2013-12-30 Mark Wielaard <[email protected]> + + * 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 <[email protected]> * 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 aa12315a..3a3e7632 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 8a7d6dfc..64f90c43 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 * |
