1 // Copyright 2005 - 2007 Google Inc.
2 // All rights reserved.
6 // Produce stack trace using libgcc
9 #include <stdlib.h> // for NULL
10 #include <unwind.h> // ABI defined unwinder
12 #include "stacktrace.h"
14 _START_GOOGLE_NAMESPACE_
24 // Workaround for the malloc() in _Unwind_Backtrace() issue.
25 static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context *uc, void *opq) {
26 return _URC_NO_REASON;
30 // This code is not considered ready to run until
31 // static initializers run so that we are guaranteed
32 // that any malloc-related initialization is done.
33 static bool ready_to_run = false;
34 class StackTraceInit {
37 // Extra call to force initialization
38 _Unwind_Backtrace(nop_backtrace, NULL);
43 static StackTraceInit module_initializer; // Force initialization
45 static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
46 trace_arg_t *targ = (trace_arg_t *) opq;
48 if (targ->skip_count > 0) {
51 targ->result[targ->count++] = (void *) _Unwind_GetIP(uc);
54 if (targ->count == targ->max_depth)
55 return _URC_END_OF_STACK;
57 return _URC_NO_REASON;
60 // If you change this function, also change GetStackFrames below.
61 int GetStackTrace(void** result, int max_depth, int skip_count) {
67 skip_count += 1; // Do not include the "GetStackTrace" frame
70 targ.max_depth = max_depth;
71 targ.skip_count = skip_count;
74 _Unwind_Backtrace(GetOneFrame, &targ);
79 // If you change this function, also change GetStackTrace above:
81 // This GetStackFrames routine shares a lot of code with GetStackTrace
82 // above. This code could have been refactored into a common routine,
83 // and then both GetStackTrace/GetStackFrames could call that routine.
84 // There are two problems with that:
86 // (1) The performance of the refactored-code suffers substantially - the
87 // refactored needs to be able to record the stack trace when called
88 // from GetStackTrace, and both the stack trace and stack frame sizes,
89 // when called from GetStackFrames - this introduces enough new
90 // conditionals that GetStackTrace performance can degrade by as much
93 // (2) Whether the refactored routine gets inlined into GetStackTrace and
94 // GetStackFrames depends on the compiler, and we can't guarantee the
95 // behavior either-way, even with "__attribute__ ((always_inline))"
96 // or "__attribute__ ((noinline))". But we need this guarantee or the
97 // frame counts may be off by one.
99 // Both (1) and (2) can be addressed without this code duplication, by
100 // clever use of template functions, and by defining GetStackTrace and
101 // GetStackFrames as macros that expand to these template functions.
102 // However, this approach comes with its own set of problems - namely,
103 // macros and preprocessor trouble - for example, if GetStackTrace
104 // and/or GetStackFrames is ever defined as a member functions in some
105 // class, we are in trouble.
106 int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
112 skip_count += 1; // Do not include the "GetStackFrames" frame
115 targ.max_depth = max_depth;
116 targ.skip_count = skip_count;
119 _Unwind_Backtrace(GetOneFrame, &targ);
121 // No implementation for finding out the stack frame sizes yet.
122 memset(sizes, 0, sizeof(*sizes) * targ.count);
127 _END_GOOGLE_NAMESPACE_