+2013-12-30 Mark Wielaard <mjw@redhat.com>
+
+ * libdw.map (ELFUTILS_0.158): Add dwfl_core_file_attach and
+ dwfl_linux_proc_attach.
+
2013-12-20 Mark Wielaard <mjw@redhat.com>
* libdw.map (ELFUTILS_0.158): Add dwfl_getthread_frames.
dwfl_module_getsymtab_first_global;
dwfl_module_addrinfo;
dwfl_module_getsym_info;
+
+ dwfl_core_file_attach;
+ dwfl_linux_proc_attach;
} ELFUTILS_0.157;
+2013-12-30 Mark Wielaard <mjw@redhat.com>
+
+ * 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 <mjw@redhat.com>
* linux-proc-maps.c (dwfl_linux_proc_find_elf): Don't return special
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
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)
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. */
{
dwfl->callbacks = callbacks;
dwfl->offline_next_address = OFFLINE_REDZONE;
- dwfl->process_attach_error = DWFL_E_NO_ATTACH_STATE;
}
return dwfl;
{
if (dwfl->process == NULL)
{
- __libdwfl_seterrno (dwfl->process_attach_error);
+ __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
return -1;
}
return dwfl->process->pid;
Dwfl_Process *process = dwfl->process;
if (process == NULL)
{
- __libdwfl_seterrno (dwfl->process_attach_error);
+ __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
return -1;
}
Dwfl_Process *process = dwfl->process;
if (process == NULL)
{
- __libdwfl_seterrno (dwfl->process_attach_error);
+ __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
return -1;
}
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
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)
Dwfl_Module *modulelist; /* List in order used by full traversals. */
Dwfl_Process *process;
- Dwfl_Error process_attach_error;
GElf_Addr offline_next_address;
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;
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)
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)
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;
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;
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)
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
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;
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 =
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;
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;
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)
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)
+2013-12-30 Mark Wielaard <mjw@redhat.com>
+
+ * stack.c (parse_opt): Explicitly call dwfl_linux_proc_attach
+ or dwfl_core_file_attach and check for errors.
+
2013-12-28 Mark Wielaard <mjw@redhat.com>
* stack.c (print_frames): Remove address width code and use...
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));
+2013-12-30 Mark Wielaard <mjw@redhat.com>
+
+ * 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 <mjw@redhat.com>
* backtrace.c (callback_verify): Only assert that case 5 is the last
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 *
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 *