diff options
Diffstat (limited to 'sysdeps/generic/backtrace.c')
-rw-r--r-- | sysdeps/generic/backtrace.c | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/sysdeps/generic/backtrace.c b/sysdeps/generic/backtrace.c index 26bf9d41cf..7ac1d5f2c4 100644 --- a/sysdeps/generic/backtrace.c +++ b/sysdeps/generic/backtrace.c @@ -1,4 +1,4 @@ -/* Return backtrace of current program state. +/* Return backtrace of current program state. Generic version. Copyright (C) 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. @@ -21,14 +21,63 @@ #include <execinfo.h> +/* This is a global variable set at program start time. It marks the + highest used stack address. */ +extern void *__libc_stack_end; + + +/* This implementation assumes a stack layout that matches the defaults + used by gcc's `__builtin_frame_address' and `__builtin_return_address' + (FP is the frame pointer register): + + +-----------------+ +-----------------+ + FP -> | previous FP --------> | previous FP ------>... + | | | | + | return address | | return address | + +-----------------+ +-----------------+ + + */ + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#ifndef CURRENT_STACK_FRAME +# define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) +#endif + +struct layout +{ + struct layout *next; + void *return_address; +}; + int __backtrace (array, size) void **array; int size; { - /* We don't generally have the possibility to determine the stack - trace. Even gcc's `__builtin_return_address' feature cannot help - since it requires a constant argument. */ - return 0; + struct layout *current; + void *top_frame; + void *top_stack; + int cnt = 0; + + top_frame = __builtin_frame_address (0); + top_stack = CURRENT_STACK_FRAME; + + /* We skip the call to this function, it makes no sense to record it. */ + current = (struct layout *) top_frame; + while (cnt < size) + { + if ((void *) current < top_stack || (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; } weak_alias (__backtrace, backtrace) |