Stacktrace code snippet? Like gdb's "bt"

E

eiselekd

Does anyone know about a code snippet that can be used
to output a backtrace just like gdb's "backtrace" command
does. One that can be called on a segmentation fault.
(without resolving symbol names, just simple list of frames
until the main() stack frame)
 
C

Chris Torek

Does anyone know about a code snippet that can be used
to output a backtrace just like gdb's "backtrace" command
does. One that can be called on a segmentation fault.
(without resolving symbol names, just simple list of frames
until the main() stack frame)

This cannot be done portably. GDB does it with code that includes
special cases -- as in, code written especially for every single
machine architecture for which gdb does it. There is *some*
code-sharing, e.g., via the "bfd" library, but it really, truly
requires that you write new code every time you port gdb to a new
machine. Sometimes that code is simple, but sometimes it is
horribly complex, and requires cooperation with the compiler.
(In particular, on architectures in which there are different
methods for returning from different function classifications,
one might need to look in different registers or stack locations
or similar depending on the return type and/or "leaf-ness" of
any particular function.)

In a few cases (which one might hope are rare), it cannot be done
at all, because by the time you get something like a "segmentation
fault", the system has removed critical information that the program
that encountered the problem would need. (For a debugger to work
at all on these systems, they have to provide a special, outside-the-
"segmentation-fault" communications channel. Systems with no
debugging facilities at all do exist as well, though.)
 
M

Michael B Allen

Does anyone know about a code snippet that can be used to output a
backtrace just like gdb's "backtrace" command does. One that can be
called on a segmentation fault. (without resolving symbol names, just
simple list of frames until the main() stack frame)

I think this is what you want:

http://samba.org/ftp/unpacked/junkcode/segv_handler/

But of course I'm obligated to point out that this is *nix specific,
is not ansi C, and is therefore offtopic here.


I use some macros that can build error text in a static buffer. The
result looks like this:

src/module.c:365:module_load: foo.so: cannot open shared object file
src/module.c:405:module_load_all:
src/main.c:114:run:

It's part of my personal "toolbelt" of stuff:

http://www.ioplex.com/~miallen/libmba/dl/docs/ref/msgno.html

I think it's ANSI but it doesn't get called automatically on segv and it
uses variadic macros so you only get the stack trace like effect if you're
using a c library that supports them (e.g. glibc does, MS' does not).

Mike
 
K

Konrad Eisele

Found it myself:

#include <stdio.h>
#include <stdlib.h>

#define UNW_LOCAL_ONLY
#include <unwind.h>

void *__libc_stack_end;

struct layout
{
struct layout * next;
void * return_address;
};

int
__backtrace (array, size)
void **array;
int size;
{
/* We assume that all the code is generated with frame pointers set. */
register void *ebp __asm__ ("ebp");
register void *esp __asm__ ("esp");
struct layout *current;
int cnt = 0;

/* We skip the call to this function, it makes no sense to record it. */
current = ((struct layout *) ebp);
while (cnt < size)
{
if ((void *) current < esp || (void *) current > __libc_stack_end)
/* This means the address is out of range. Note that for the
toplevel we see a frame pointer with value NULL which clearly is
out of range. */
break;

array[cnt++] = current->return_address;

current = current->next;
}

return cnt;
}

/* _Unwind_Reason_Code Trace_Fn (struct _Unwind_Context *c, void *arg) */
/* { */
/* printf ("Out\n"); */
/* return _URC_NO_REASON; */
/* } */

/* void print_trace (void) { */

/* _Unwind_Reason_Code r = _Unwind_Backtrace(Trace_Fn,0); */

/* /\*{ */

/* unw_getcontext(&uc); */
/* unw_init_local(&cursor, &uc); */
/* while (unw_step(&cursor) > 0) { */
/* unw_get_reg(&cursor, UNW_REG_IP, &ip); */
/* unw_get_reg(&cursor, UNW_REG_SP, &sp); */
/* printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp); */
/* }*\/ */
/* } */


/* A dummy function to make the backtrace more interesting. */
void
dummy_function2 (void)
{
void *a[10]; int i = 0;
int cnt = __backtrace (&a, 10);
for (i = 0;i < cnt;i++) {
printf("%x\n",a);
}

}

/* A dummy function to make the backtrace more interesting. */
void
dummy_function1 (void)
{
dummy_function2 ();
}

int main ()
{
/* We assume that all the code is generated with frame pointers set. */
register void *ebp __asm__ ("ebp");
register void *esp __asm__ ("esp");
__libc_stack_end = ((struct layout *) ebp);
dummy_function1 ();
return 0;
}









If glibc is present:
-------------------------------------
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
void *array[10];
size_t size;
char **strings;
size_t i;

size = backtrace (array, 10);
strings = backtrace_symbols (array, size);

printf ("Obtained %zd stack frames.\n", size);

for (i = 0; i < size; i++)
printf ("%s\n", strings);

free (strings);
}

/* A dummy function to make the backtrace more interesting. */
void
dummy_function (void)
{
print_trace ();
}

int
main (void)
{
dummy_function ();
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top