| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2005, Google Inc. | |
| 2 // All rights reserved. | |
| 3 // | |
| 4 // Redistribution and use in source and binary forms, with or without | |
| 5 // modification, are permitted provided that the following conditions are | |
| 6 // met: | |
| 7 // | |
| 8 // * Redistributions of source code must retain the above copyright | |
| 9 // notice, this list of conditions and the following disclaimer. | |
| 10 // * Redistributions in binary form must reproduce the above | |
| 11 // copyright notice, this list of conditions and the following disclaimer | |
| 12 // in the documentation and/or other materials provided with the | |
| 13 // distribution. | |
| 14 // * Neither the name of Google Inc. nor the names of its | |
| 15 // contributors may be used to endorse or promote products derived from | |
| 16 // this software without specific prior written permission. | |
| 17 // | |
| 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 | |
| 30 // --- | |
| 31 // Author: Arun Sharma | |
| 32 // | |
| 33 // Produce stack trace using libgcc | |
| 34 | |
| 35 extern "C" { | |
| 36 #include <stdlib.h> // for NULL | |
| 37 #include <unwind.h> // ABI defined unwinder | |
| 38 #include <string.h> // for memset | |
| 39 } | |
| 40 #include "google/stacktrace.h" | |
| 41 | |
| 42 typedef struct { | |
| 43 void **result; | |
| 44 int max_depth; | |
| 45 int skip_count; | |
| 46 int count; | |
| 47 } trace_arg_t; | |
| 48 | |
| 49 | |
| 50 // Workaround for the malloc() in _Unwind_Backtrace() issue. | |
| 51 static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context *uc, void *opq)
{ | |
| 52 return _URC_NO_REASON; | |
| 53 } | |
| 54 | |
| 55 | |
| 56 // This code is not considered ready to run until | |
| 57 // static initializers run so that we are guaranteed | |
| 58 // that any malloc-related initialization is done. | |
| 59 static bool ready_to_run = false; | |
| 60 class StackTraceInit { | |
| 61 public: | |
| 62 StackTraceInit() { | |
| 63 // Extra call to force initialization | |
| 64 _Unwind_Backtrace(nop_backtrace, NULL); | |
| 65 ready_to_run = true; | |
| 66 } | |
| 67 }; | |
| 68 | |
| 69 static StackTraceInit module_initializer; // Force initialization | |
| 70 | |
| 71 static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) { | |
| 72 trace_arg_t *targ = (trace_arg_t *) opq; | |
| 73 | |
| 74 if (targ->skip_count > 0) { | |
| 75 targ->skip_count--; | |
| 76 } else { | |
| 77 targ->result[targ->count++] = (void *) _Unwind_GetIP(uc); | |
| 78 } | |
| 79 | |
| 80 if (targ->count == targ->max_depth) | |
| 81 return _URC_END_OF_STACK; | |
| 82 | |
| 83 return _URC_NO_REASON; | |
| 84 } | |
| 85 | |
| 86 // If you change this function, also change GetStackFrames below. | |
| 87 int GetStackTrace(void** result, int max_depth, int skip_count) { | |
| 88 if (!ready_to_run) | |
| 89 return 0; | |
| 90 | |
| 91 trace_arg_t targ; | |
| 92 | |
| 93 skip_count += 1; // Do not include the "GetStackTrace" frame | |
| 94 | |
| 95 targ.result = result; | |
| 96 targ.max_depth = max_depth; | |
| 97 targ.skip_count = skip_count; | |
| 98 targ.count = 0; | |
| 99 | |
| 100 _Unwind_Backtrace(GetOneFrame, &targ); | |
| 101 | |
| 102 return targ.count; | |
| 103 } | |
| 104 | |
| 105 // If you change this function, also change GetStackTrace above: | |
| 106 // | |
| 107 // This GetStackFrames routine shares a lot of code with GetStackTrace | |
| 108 // above. This code could have been refactored into a common routine, | |
| 109 // and then both GetStackTrace/GetStackFrames could call that routine. | |
| 110 // There are two problems with that: | |
| 111 // | |
| 112 // (1) The performance of the refactored-code suffers substantially - the | |
| 113 // refactored needs to be able to record the stack trace when called | |
| 114 // from GetStackTrace, and both the stack trace and stack frame sizes, | |
| 115 // when called from GetStackFrames - this introduces enough new | |
| 116 // conditionals that GetStackTrace performance can degrade by as much | |
| 117 // as 50%. | |
| 118 // | |
| 119 // (2) Whether the refactored routine gets inlined into GetStackTrace and | |
| 120 // GetStackFrames depends on the compiler, and we can't guarantee the | |
| 121 // behavior either-way, even with "__attribute__ ((always_inline))" | |
| 122 // or "__attribute__ ((noinline))". But we need this guarantee or the | |
| 123 // frame counts may be off by one. | |
| 124 // | |
| 125 // Both (1) and (2) can be addressed without this code duplication, by | |
| 126 // clever use of template functions, and by defining GetStackTrace and | |
| 127 // GetStackFrames as macros that expand to these template functions. | |
| 128 // However, this approach comes with its own set of problems - namely, | |
| 129 // macros and preprocessor trouble - for example, if GetStackTrace | |
| 130 // and/or GetStackFrames is ever defined as a member functions in some | |
| 131 // class, we are in trouble. | |
| 132 int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) { | |
| 133 if (!ready_to_run) | |
| 134 return 0; | |
| 135 | |
| 136 trace_arg_t targ; | |
| 137 | |
| 138 skip_count += 1; // Do not include the "GetStackFrames" frame | |
| 139 | |
| 140 targ.result = pcs; | |
| 141 targ.max_depth = max_depth; | |
| 142 targ.skip_count = skip_count; | |
| 143 targ.count = 0; | |
| 144 | |
| 145 _Unwind_Backtrace(GetOneFrame, &targ); | |
| 146 | |
| 147 // No implementation for finding out the stack frame sizes yet. | |
| 148 memset(sizes, 0, sizeof(*sizes) * targ.count); | |
| 149 | |
| 150 return targ.count; | |
| 151 } | |
| OLD | NEW |