diff options
Diffstat (limited to 'src/os/os_stack.c')
-rw-r--r-- | src/os/os_stack.c | 135 |
1 files changed, 123 insertions, 12 deletions
diff --git a/src/os/os_stack.c b/src/os/os_stack.c index 037080f3..9844930f 100644 --- a/src/os/os_stack.c +++ b/src/os/os_stack.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -14,32 +14,143 @@ #include <execinfo.h> #endif +#undef __DB_STACK_MAXFRAMES +#define __DB_STACK_MAXFRAMES 25 + /* * __os_stack -- - * Output a stack trace to the message file handle. + * Output a stack trace in a single write to the error file handle. * - * PUBLIC: void __os_stack __P((ENV *)); + * PUBLIC: void __os_stack __P((const ENV *)); */ void __os_stack(env) - ENV *env; + const ENV *env; +{ + /* Adjust by 2 to exclude __os_stack() and __os_stack_top(). */ + __os_stack_top(env, __DB_STACK_MAXFRAMES - 2, 2); +} + +/* + * __os_stack_top -- + * Output just a certain range of stack frames to the error file handle. + * + * PUBLIC: void __os_stack_top __P((const ENV *, unsigned, unsigned)); + */ +void +__os_stack_top(env, nframes, skipframes) + const ENV *env; + unsigned nframes; + unsigned skipframes; { #if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) - void *array[200]; - size_t i, size; - char **strings; + char buf[__DB_STACK_MAXFRAMES * 80]; /* Allow for 80 chars/line. */ + __os_stack_text(env, buf, sizeof(buf), nframes, skipframes + 1); + __db_errx(env, "Top of stack:\n%s", buf); +#else + COMPQUIET(env, NULL); + COMPQUIET(nframes, 0); + COMPQUIET(skipframes, 0); +#endif +} + +/* + * __os_stack_text -- + * 'Print' the current stack into a char text buffer. + * + * PUBLIC: void __os_stack_text + * PUBLIC: __P((const ENV *, char *, size_t, unsigned, unsigned)); + */ +void +__os_stack_text(env, result, bufsize, nframes, skip) + const ENV *env; + char *result; + size_t bufsize; + unsigned nframes; + unsigned skip; +{ + DB_MSGBUF mb; + + DB_MSGBUF_INIT(&mb); + mb.buf = mb.cur = result; + mb.len = bufsize; + F_SET(&mb, DB_MSGBUF_PREALLOCATED); + __os_stack_msgadd(env, &mb, nframes, skip, NULL); +} + +/* + * __os_stack_save -- + * Save a certain range of stack frames into the frames argument. + * + * PUBLIC: int __os_stack_save __P((const ENV *, unsigned, void **)); + */ +int +__os_stack_save(env, nframes, frames) + const ENV *env; + unsigned nframes; + void **frames; +{ + COMPQUIET(env, NULL); +#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) /* * Solaris and the GNU C library support this interface. Solaris * has additional interfaces (printstack and walkcontext), I don't * know if they offer any additional value or not. */ - size = backtrace(array, sizeof(array) / sizeof(array[0])); - strings = backtrace_symbols(array, size); + return ((int) backtrace(frames, nframes)); +#else + COMPQUIET(nframes, 0); + COMPQUIET(frames, NULL); + return (0); +#endif +} + +/* + * __os_stack_msgadd -- + * Decode a stack and add it to a DB_MSGBUF. The stack was either + * previously obtained stack, e.g., from __os_stack_save(), or if it is + * null, the current stack is fetched here. + * + * PUBLIC: void __os_stack_msgadd + * PUBLIC: __P((const ENV *, DB_MSGBUF *, unsigned, unsigned, void **)); + */ +void +__os_stack_msgadd(env, mb, totalframes, skipframes, stack) + const ENV *env; + DB_MSGBUF *mb; + unsigned totalframes; + unsigned skipframes; + void **stack; +{ +#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) + char **strings; + void *local_frames[__DB_STACK_MAXFRAMES]; + unsigned i; + + if (stack == NULL) { + stack = local_frames; + if (totalframes > __DB_STACK_MAXFRAMES) + totalframes = __DB_STACK_MAXFRAMES; + totalframes = backtrace(local_frames, totalframes); + skipframes++; + } + + /* + * Solaris and the GNU C library support this interface. Solaris + * has additional interfaces (printstack and walkcontext) which have + * know if they offer any additional value or not. + */ + strings = backtrace_symbols(stack, totalframes); - for (i = 0; i < size; ++i) - __db_errx(env, "%s", strings[i]); + for (i = skipframes; i < totalframes; ++i) + __db_msgadd((ENV *)env, mb, "\t%s\n", strings[i]); free(strings); -#endif +#else COMPQUIET(env, NULL); + COMPQUIET(mb, NULL); + COMPQUIET(totalframes, 0); + COMPQUIET(skipframes, 0); + COMPQUIET(stack, NULL); +#endif } |