summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog16
-rw-r--r--src/stack.c174
2 files changed, 127 insertions, 63 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 0e6d2dc5..d3d68078 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,19 @@
+2013-12-22 Mark Wielaard <[email protected]>
+
+ * 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 <[email protected]>
* stack.c (show_one_tid): New static boolean.
diff --git a/src/stack.c b/src/stack.c
index 512c85b4..188aa005 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;