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 |