diff options
Diffstat (limited to 'absl/debugging/stacktrace.h')
-rw-r--r-- | absl/debugging/stacktrace.h | 178 |
1 files changed, 118 insertions, 60 deletions
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h index 82da3f15fa7d..8b831e268155 100644 --- a/absl/debugging/stacktrace.h +++ b/absl/debugging/stacktrace.h @@ -1,5 +1,4 @@ -// -// Copyright 2017 The Abseil Authors. +// Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,26 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. // - -// Routines to extract the current stack trace. These functions are -// thread-safe and async-signal-safe. +// ----------------------------------------------------------------------------- +// File: stacktrace.h +// ----------------------------------------------------------------------------- +// +// This file contains routines to extract the current stack trace and associated +// stack frames. These functions are thread-safe and async-signal-safe. +// // Note that stack trace functionality is platform dependent and requires -// additional support from the compiler/build system in many cases. (That is, -// this generally only works on platforms/builds that have been specifically -// configured to support it.) +// additional support from the compiler/build system in most cases. (That is, +// this functionality generally only works on platforms/builds that have been +// specifically configured to support it.) +// +// Note: stack traces in Abseil that do not utilize a symbolizer will result in +// frames consisting of function addresses rather than human-readable function +// names. (See symbolize.h for information on symbolizing these values.) #ifndef ABSL_DEBUGGING_STACKTRACE_H_ #define ABSL_DEBUGGING_STACKTRACE_H_ namespace absl { -// Skips the most recent "skip_count" stack frames (also skips the -// frame generated for the "absl::GetStackFrames" routine itself), and then -// records the pc values for up to the next "max_depth" frames in -// "result", and the corresponding stack frame sizes in "sizes". -// Returns the number of values recorded in "result"/"sizes". +// GetStackFrames() +// +// Records program counter values for up to `max_depth` frames, skipping the +// most recent `skip_count` stack frames, and stores their corresponding values +// and sizes in `results` and `sizes` buffers. (Note that the frame generated +// for the `absl::GetStackFrames()` routine itself is also skipped.) +// routine itself. // // Example: +// // main() { foo(); } // foo() { bar(); } // bar() { @@ -41,41 +51,66 @@ namespace absl { // int depth = absl::GetStackFrames(result, sizes, 10, 1); // } // -// The absl::GetStackFrames call will skip the frame for "bar". It will -// return 2 and will produce pc values that map to the following -// procedures: -// result[0] foo -// result[1] main -// (Actually, there may be a few more entries after "main" to account for -// startup procedures.) -// And corresponding stack frame sizes will also be recorded: +// The current stack frame would consist of three function calls: `bar()`, +// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets +// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently +// invoked function call. It will therefore return two program counters and will +// produce values that map to the following function calls: +// +// result[0] foo() +// result[1] main() +// +// (Note: in practice, a few more entries after `main()` may be added to account +// for startup processes.) +// +// Corresponding stack frame sizes will also be recorded: +// // sizes[0] 16 // sizes[1] 16 -// (Stack frame sizes of 16 above are just for illustration purposes.) +// +// (Stack frame sizes of `16` above are just for illustration purposes.) +// // Stack frame sizes of 0 or less indicate that those frame sizes couldn't // be identified. // // This routine may return fewer stack frame entries than are -// available. Also note that "result" and "sizes" must both be non-null. +// available. Also note that `result` and `sizes` must both be non-null. extern int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count); -// Same as above, but to be used from a signal handler. The "uc" parameter -// should be the pointer to ucontext_t which was passed as the 3rd parameter -// to sa_sigaction signal handler. It may help the unwinder to get a -// better stack trace under certain conditions. The "uc" may safely be null. -// -// If min_dropped_frames is not null, stores in *min_dropped_frames a -// lower bound on the number of dropped stack frames. The stored value is -// guaranteed to be >= 0. The number of real stack frames is guaranteed to -// be >= skip_count + max_depth + *min_dropped_frames. +// GetStackFramesWithContext() +// +// Records program counter values obtained from a signal handler. Records +// program counter values for up to `max_depth` frames, skipping the most recent +// `skip_count` stack frames, and stores their corresponding values and sizes in +// `results` and `sizes` buffers. (Note that the frame generated for the +// `absl::GetStackFramesWithContext()` routine itself is also skipped.) +// +// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value +// passed to a signal handler registered via the `sa_sigaction` field of a +// `sigaction` struct. (See +// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may +// help a stack unwinder to provide a better stack trace under certain +// conditions. `uc` may safely be null. +// +// The `min_dropped_frames` output parameter, if non-null, points to the +// location to note any dropped stack frames, if any, due to buffer limitations +// or other reasons. (This value will be set to `0` if no frames were dropped.) +// The number of total stack frames is guaranteed to be >= skip_count + +// max_depth + *min_dropped_frames. extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth, int skip_count, const void* uc, int* min_dropped_frames); -// This is similar to the absl::GetStackFrames routine, except that it returns -// the stack trace only, and not the stack frame sizes as well. +// GetStackTrace() +// +// Records program counter values for up to `max_depth` frames, skipping the +// most recent `skip_count` stack frames, and stores their corresponding values +// in `results`. Note that this function is similar to `absl::GetStackFrames()` +// except that it returns the stack trace only, and not stack frame sizes. +// // Example: +// // main() { foo(); } // foo() { bar(); } // bar() { @@ -84,42 +119,57 @@ extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth, // } // // This produces: +// // result[0] foo // result[1] main // .... ... // -// "result" must not be null. +// `result` must not be null. extern int GetStackTrace(void** result, int max_depth, int skip_count); -// Same as above, but to be used from a signal handler. The "uc" parameter -// should be the pointer to ucontext_t which was passed as the 3rd parameter -// to sa_sigaction signal handler. It may help the unwinder to get a -// better stack trace under certain conditions. The "uc" may safely be null. -// -// If min_dropped_frames is not null, stores in *min_dropped_frames a -// lower bound on the number of dropped stack frames. The stored value is -// guaranteed to be >= 0. The number of real stack frames is guaranteed to -// be >= skip_count + max_depth + *min_dropped_frames. +// GetStackTraceWithContext() +// +// Records program counter values obtained from a signal handler. Records +// program counter values for up to `max_depth` frames, skipping the most recent +// `skip_count` stack frames, and stores their corresponding values in +// `results`. (Note that the frame generated for the +// `absl::GetStackFramesWithContext()` routine itself is also skipped.) +// +// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value +// passed to a signal handler registered via the `sa_sigaction` field of a +// `sigaction` struct. (See +// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may +// help a stack unwinder to provide a better stack trace under certain +// conditions. `uc` may safely be null. +// +// The `min_dropped_frames` output parameter, if non-null, points to the +// location to note any dropped stack frames, if any, due to buffer limitations +// or other reasons. (This value will be set to `0` if no frames were dropped.) +// The number of total stack frames is guaranteed to be >= skip_count + +// max_depth + *min_dropped_frames. extern int GetStackTraceWithContext(void** result, int max_depth, int skip_count, const void* uc, int* min_dropped_frames); -// Call this to provide a custom function for unwinding stack frames -// that will be used every time someone invokes one of the static +// SetStackUnwinder() +// +// Provides a custom function for unwinding stack frames that will be used in +// place of the default stack unwinder when invoking the static // GetStack{Frames,Trace}{,WithContext}() functions above. // // The arguments passed to the unwinder function will match the -// arguments passed to absl::GetStackFramesWithContext() except that sizes +// arguments passed to `absl::GetStackFramesWithContext()` except that sizes // will be non-null iff the caller is interested in frame sizes. // -// If unwinder is null, we revert to the default stack-tracing behavior. +// If unwinder is set to null, we revert to the default stack-tracing behavior. // -// **************************************************************** -// WARNINGS +// ***************************************************************************** +// WARNING +// ***************************************************************************** // // absl::SetStackUnwinder is not suitable for general purpose use. It is // provided for custom runtimes. -// Some things to watch out for when calling absl::SetStackUnwinder: +// Some things to watch out for when calling `absl::SetStackUnwinder()`: // // (a) The unwinder may be called from within signal handlers and // therefore must be async-signal-safe. @@ -128,23 +178,31 @@ extern int GetStackTraceWithContext(void** result, int max_depth, // threads may still be in the process of using that unwinder. // Therefore do not clean up any state that may be needed by an old // unwinder. -// **************************************************************** +// ***************************************************************************** extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes, int max_depth, int skip_count, const void* uc, int* min_dropped_frames)); -// Function that exposes built-in stack-unwinding behavior, ignoring -// any calls to absl::SetStackUnwinder(). +// DefaultStackUnwinder() +// +// Records program counter values of up to `max_depth` frames, skipping the most +// recent `skip_count` stack frames, and stores their corresponding values in +// `pcs`. (Note that the frame generated for this call itself is also skipped.) +// This function acts as a generic stack-unwinder; prefer usage of the more +// specific `GetStack{Trace,Frames}{,WithContext}()` functions above. // -// pcs must NOT be null. +// If you have set your own stack unwinder (with the `SetStackUnwinder()` +// function above, you can still get the default stack unwinder by calling +// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder +// and use the default one instead. // -// sizes may be null. -// uc may be null. -// min_dropped_frames may be null. +// Because this function is generic, only `pcs` is guaranteed to be non-null +// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all +// be null when called. // -// The semantics are the same as the corresponding GetStack*() function in the -// case where absl::SetStackUnwinder() was never called. Equivalents are: +// The semantics are the same as the corresponding `GetStack*()` function in the +// case where `absl::SetStackUnwinder()` was never called. Equivalents are: // // null sizes | non-nullptr sizes // |==========================================================| |