[PATCH] libdwfl: Add dwfl_core_file_attach and dwfl_linux_proc_attach.

Mark Wielaard mjw at redhat.com
Tue Dec 31 13:19:06 UTC 2013


> While working on using the pid unwinder in ltrace I noticed it didn't
> really play well with a process that might already be ptrace attached
> to the thread under inspection. This patch solves that by detecting the
> thread already is ptrace attached and making sure we don't detach it
> ourselves in that case.

Although this works it isn't very elegant. And it only works for the
implicit attaching through dwfl_linux_proc_report. While that nicely
makes things "just work" it also isn't very flexible. It relies on the
program to want to use module reporting through dwfl_linux_proc_report.
But some programs (like ltrace) might already track modules/library
loading themselves. In that case it is impossible to attach state to
the Dwfl unless one reimplements all the Dwfl_Thread_Callbacks. So this
patch makes it possible to both explicitly attach thread state to a Dwfl
independent of how the Dwfl_Modules were reported using the existing pid
and core callbacks. And it allows someone using the pid callbacks to
indicate they take care of the ptrace attach/stap/detaching.

This makes using the (pid) unwinder a lot more natural in programs like
ltrace that might already track modules themselves and/or keep track
of ptrace attach/stop of threads.

<-snip->

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 <mjw at redhat.com>
---
 libdw/ChangeLog             |  5 +++++
 libdw/libdw.map             |  3 +++
 libdwfl/ChangeLog           | 32 ++++++++++++++++++++++++++++
 libdwfl/argp-std.c          | 10 +++++++++
 libdwfl/core-file.c         |  7 -------
 libdwfl/dwfl_begin.c        |  1 -
 libdwfl/dwfl_frame.c        |  6 +++---
 libdwfl/libdwfl.h           | 26 +++++++++++++++++------
 libdwfl/libdwflP.h          | 11 ++--------
 libdwfl/linux-core-attach.c | 51 +++++++++++++++++----------------------------
 libdwfl/linux-pid-attach.c  | 44 ++++++++++++++++++++------------------
 libdwfl/linux-proc-maps.c   |  7 -------
 src/ChangeLog               |  5 +++++
 src/stack.c                 | 16 ++++++++++++++
 tests/ChangeLog             |  6 ++++++
 tests/backtrace-dwarf.c     |  6 ++++++
 tests/backtrace.c           |  6 ++++++
 17 files changed, 157 insertions(+), 85 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 2b67759..6e779c8 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-30  Mark Wielaard  <mjw at redhat.com>
+
+	* libdw.map (ELFUTILS_0.158): Add dwfl_core_file_attach and
+	dwfl_linux_proc_attach.
+
 2013-12-20  Mark Wielaard  <mjw at redhat.com>
 
 	* libdw.map (ELFUTILS_0.158): Add dwfl_getthread_frames.
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 08c4ddc..d0e4731 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 6c983b2..2190899 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,35 @@
+2013-12-30  Mark Wielaard  <mjw at 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 at redhat.com>
 
 	* 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 cf178ee..3a2d2a5 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 92745bd..4ce63c4 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 490da90..44c16a9 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 28008e9..e45cf14 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 67785ea..2bb4f45 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 63615a8..710e699 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 cc11467..1002788 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 70bd666..21ff4b9 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 b1f8b33..cdb6959 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 cb9c815..811004d 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-30  Mark Wielaard  <mjw at 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 at redhat.com>
 
 	* stack.c (print_frames): Remove address width code and use...
diff --git a/src/stack.c b/src/stack.c
index 156455c..2c1d8ff 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 23c5051..5c80e9b 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2013-12-30  Mark Wielaard  <mjw at 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 at redhat.com>
 
 	* 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 aa12315..3a3e763 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 8a7d6df..64f90c4 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 *
-- 
1.8.4.2



More information about the elfutils-devel mailing list