This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] stack: Add new '-n MAXFRAMES' option. Resolve addresses after unwind.


Limit the number of frames printed per thread (defaults to 64) and resolve
addresses to names, modules and source after unwinding so the thread is
only stopped for the minimum time needed to do the actual unwinding. The
thread doesn't need to wait for the lookups and printing of information.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 src/ChangeLog |   16 +++++
 src/stack.c   |  174 ++++++++++++++++++++++++++++++++++++---------------------
 2 files changed, 127 insertions(+), 63 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 0e6d2dc..d3d6807 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,19 @@
+2013-12-22  Mark Wielaard  <mjw@redhat.com>
+
+	* stack.c (maxframes): New static unsigned. Initialize to 64.
+	(struct frame): New struct.
+	(struct frames): Likewise.
+	(dwfl): New static Dwfl pointer.
+	(frame_callback): Use arg as struct frames and fill it next frame.
+	Return DWARF_CB_ABORT when maxframes has been reached. Move
+	printing of frame to...
+	(print_frames): ...here. New function.
+	(thread_callback): Use arg as struct frames and set frames to zero.
+	Call print_frames.
+	(parse_opt): Handle '-n'.
+	(main): Add -n to options. Allocate frames using maxframes. Pass
+	frames to frame_callback and thread_callback.
+
 2013-12-20  Mark Wielaard  <mjw@redhat.com>
 
 	* stack.c (show_one_tid): New static boolean.
diff --git a/src/stack.c b/src/stack.c
index 512c85b..188aa00 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -41,91 +41,122 @@ static bool show_module = false;
 static bool show_source = false;
 static bool show_one_tid = false;
 
-static int
-frame_callback (Dwfl_Frame *state, void *arg)
+static unsigned maxframes = 64;
+
+struct frame
 {
-  unsigned *framenop = arg;
   Dwarf_Addr pc;
   bool isactivation;
-  if (! dwfl_frame_pc (state, &pc, &isactivation))
+};
+
+struct frames
+{
+  unsigned frames;
+  struct frame frame[];
+};
+
+static Dwfl *dwfl = NULL;
+
+static int
+frame_callback (Dwfl_Frame *state, void *arg)
+{
+  struct frames *frames = (struct frames *) arg;
+  unsigned nr = frames->frames;
+  if (! dwfl_frame_pc (state, &frames->frame[nr].pc,
+		       &frames->frame[nr].isactivation))
     {
       error (0, 0, "%s", dwfl_errmsg (-1));
       return DWARF_CB_ABORT;
     }
-  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
-
-  /* Get PC->SYMNAME.  */
-  Dwfl *dwfl = dwfl_thread_dwfl (dwfl_frame_thread (state));
-  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
-  const char *symname = NULL;
-  if (mod)
-    symname = dwfl_module_addrname (mod, pc_adjusted);
-
-  // Try to find the address wide if possible.
-  static int width = 0;
-  if (width == 0 && mod)
+
+  frames->frames++;
+  if (frames->frames == maxframes)
+    return DWARF_CB_ABORT;
+
+  return DWARF_CB_OK;
+}
+
+static void
+print_frames (struct frames *frames)
+{
+  for (unsigned nr = 0; nr < frames->frames; nr++)
     {
-      Dwarf_Addr bias;
-      Elf *elf = dwfl_module_getelf (mod, &bias);
-      if (elf)
+      Dwarf_Addr pc = frames->frame[nr].pc;
+      bool isactivation = frames->frame[nr].isactivation;
+      Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
+
+      /* Get PC->SYMNAME.  */
+      Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
+      const char *symname = NULL;
+      if (mod)
+	symname = dwfl_module_addrname (mod, pc_adjusted);
+
+      // Try to find the address wide if possible.
+      static int width = 0;
+      if (width == 0 && mod)
 	{
-	  GElf_Ehdr ehdr_mem;
-	  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
-	  if (ehdr)
-	    width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
+	  Dwarf_Addr bias;
+	  Elf *elf = dwfl_module_getelf (mod, &bias);
+	  if (elf)
+	    {
+	      GElf_Ehdr ehdr_mem;
+	      GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
+	      if (ehdr)
+		width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
+	    }
 	}
-    }
-  if (width == 0)
-    width = 16;
+      if (width == 0)
+	width = 16;
 
-  printf ("#%-2u 0x%0*" PRIx64, (*framenop)++, width, (uint64_t) pc);
+      printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
 
-  if (show_activation)
-    printf ("%4s", ! isactivation ? "- 1" : "");
+      if (show_activation)
+	printf ("%4s", ! isactivation ? "- 1" : "");
 
-  if (symname != NULL)
-    printf (" %s", symname);
+      if (symname != NULL)
+	printf (" %s", symname);
 
-  if (show_module)
-    {
-      const char* fname;
-
-      fname = dwfl_module_info(mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-      if (fname != NULL)
-	printf (" - %s", fname);
-    }
+      if (show_module)
+	{
+	  const char* fname;
+	  fname = dwfl_module_info(mod,
+				   NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+	  if (fname != NULL)
+	    printf (" - %s", fname);
+	}
 
-  if (show_source)
-    {
-      Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
-      if (lineobj)
+      if (show_source)
 	{
-	  int line, col;
-	  const char* sname;
-	  line = col = -1;
-	  sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
-	  if (sname != NULL)
+	  Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
+	  if (lineobj)
 	    {
-	      printf ("\n    %s", sname);
-	      if (line > 0)
+	      int line, col;
+	      const char* sname;
+	      line = col = -1;
+	      sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
+	      if (sname != NULL)
 		{
-		  printf (":%d", line);
-		  if (col > 0)
-		    printf (":%d", col);
+		  printf ("\n    %s", sname);
+		  if (line > 0)
+		    {
+		      printf (":%d", line);
+		      if (col > 0)
+			printf (":%d", col);
+		    }
 		}
 	    }
 	}
+      printf ("\n");
     }
-  printf ("\n");
-  return DWARF_CB_OK;
 }
 
 static int
-thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__ ((unused)))
+thread_callback (Dwfl_Thread *thread, void *thread_arg)
 {
   printf ("TID %ld:\n", (long) dwfl_thread_tid (thread));
-  unsigned frameno = 0;
-  switch (dwfl_thread_getframes (thread, frame_callback, &frameno))
+  struct frames *frames = (struct frames *) thread_arg;
+  frames->frames = 0;
+  switch (dwfl_thread_getframes (thread, frame_callback, thread_arg))
     {
     case DWARF_CB_OK:
     case DWARF_CB_ABORT:
@@ -136,6 +167,7 @@ thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__ ((unused)))
     default:
       abort ();
     }
+  print_frames (frames);
   return DWARF_CB_OK;
 }
 
@@ -175,6 +207,15 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
       show_one_tid = true;
       break;
 
+    case 'n':
+      maxframes = atoi (arg);
+      if (maxframes == 0)
+	{
+	  argp_error (state, N_("-n MAXFRAMES should be 1 or higher."));
+	  return EINVAL;
+	}
+      break;
+
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -204,6 +245,8 @@ main (int argc, char **argv)
 	N_("Show all additional information (activation, module and source)"), 0 },
       { NULL, '1', NULL, 0,
 	N_("Show the backtrace of only one thread"), 0 },
+      { NULL, 'n', "MAXFRAMES", 0,
+	N_("Show at most MAXFRAMES per thread (defaults to 64)"), 0 },
       { NULL, 0, NULL, 0, NULL, 0 }
     };
 
@@ -224,11 +267,11 @@ Only real user processes are supported, no kernel or process maps."),
     };
 
   int remaining;
-  Dwfl *dwfl = NULL;
   argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
   assert (dwfl != NULL);
   if (remaining != argc)
-    error (2, 0, "eu-stack [-a] [-m] [-s] [-v] [-1] [--debuginfo-path=<path>]"
+    error (2, 0, "eu-stack [-a] [-m] [-s] [-v] [-1] [-n MAXFRAMES]"
+	   " [--debuginfo-path=<path>]"
 	   " {-p <process id>|--core=<file> [--executable=<file>]|--help}");
 
   /* dwfl_linux_proc_report has been already called from dwfl_standard_argp's
@@ -236,11 +279,14 @@ Only real user processes are supported, no kernel or process maps."),
   if (dwfl_report_end (dwfl, NULL, NULL) != 0)
     error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
 
+  struct frames *frames = malloc (sizeof (struct frames)
+				  + sizeof (struct frame) * maxframes);
+  frames->frames = 0;
+
   if (show_one_tid)
     {
       pid_t tid = dwfl_pid (dwfl);
-      unsigned frameno = 0;
-      switch (dwfl_getthread_frames (dwfl, tid, frame_callback, &frameno))
+      switch (dwfl_getthread_frames (dwfl, tid, frame_callback, frames))
 	{
 	case DWARF_CB_OK:
 	  break;
@@ -251,10 +297,11 @@ Only real user processes are supported, no kernel or process maps."),
 	default:
 	  abort ();
 	}
+      print_frames (frames);
     }
   else
     {
-      switch (dwfl_getthreads (dwfl, thread_callback, NULL))
+      switch (dwfl_getthreads (dwfl, thread_callback, frames))
 	{
 	case DWARF_CB_OK:
 	  break;
@@ -265,6 +312,7 @@ Only real user processes are supported, no kernel or process maps."),
 	  abort ();
 	}
     }
+  free (frames);
   dwfl_end (dwfl);
 
   return 0;
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]