OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/stack_trace.h" | 5 #include "base/debug/stack_trace.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <dbghelp.h> | 8 #include <dbghelp.h> |
9 | 9 |
10 #include <iostream> | 10 #include <iostream> |
11 | 11 |
12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/memory/singleton.h" | 14 #include "base/memory/singleton.h" |
15 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
16 | 16 |
17 namespace base { | 17 namespace base { |
18 namespace debug { | 18 namespace debug { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 // SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family | 22 // SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family |
23 // of functions. The Sym* family of functions may only be invoked by one | 23 // of functions. The Sym* family of functions may only be invoked by one |
24 // thread at a time. SymbolContext code may access a symbol server over the | 24 // thread at a time. SymbolContext code may access a symbol server over the |
25 // network while holding the lock for this singleton. In the case of high | 25 // network while holding the lock for this singleton. In the case of high |
26 // latency, this code will adversly affect performance. | 26 // latency, this code will adversely affect performance. |
27 // | 27 // |
28 // There is also a known issue where this backtrace code can interact | 28 // There is also a known issue where this backtrace code can interact |
29 // badly with breakpad if breakpad is invoked in a separate thread while | 29 // badly with breakpad if breakpad is invoked in a separate thread while |
30 // we are using the Sym* functions. This is because breakpad does now | 30 // we are using the Sym* functions. This is because breakpad does now |
31 // share a lock with this function. See this related bug: | 31 // share a lock with this function. See this related bug: |
32 // | 32 // |
33 // http://code.google.com/p/google-breakpad/issues/detail?id=311 | 33 // http://code.google.com/p/google-breakpad/issues/detail?id=311 |
34 // | 34 // |
35 // This is a very unlikely edge case, and the current solution is to | 35 // This is a very unlikely edge case, and the current solution is to |
36 // just ignore it. | 36 // just ignore it. |
(...skipping 13 matching lines...) Expand all Loading... | |
50 | 50 |
51 // For the given trace, attempts to resolve the symbols, and output a trace | 51 // For the given trace, attempts to resolve the symbols, and output a trace |
52 // to the ostream os. The format for each line of the backtrace is: | 52 // to the ostream os. The format for each line of the backtrace is: |
53 // | 53 // |
54 // <tab>SymbolName[0xAddress+Offset] (FileName:LineNo) | 54 // <tab>SymbolName[0xAddress+Offset] (FileName:LineNo) |
55 // | 55 // |
56 // This function should only be called if Init() has been called. We do not | 56 // This function should only be called if Init() has been called. We do not |
57 // LOG(FATAL) here because this code is called might be triggered by a | 57 // LOG(FATAL) here because this code is called might be triggered by a |
58 // LOG(FATAL) itself. | 58 // LOG(FATAL) itself. |
59 void OutputTraceToStream(const void* const* trace, | 59 void OutputTraceToStream(const void* const* trace, |
60 int count, | 60 size_t count, |
61 std::ostream* os) { | 61 std::ostream* os) { |
62 base::AutoLock lock(lock_); | 62 base::AutoLock lock(lock_); |
63 | 63 |
64 for (size_t i = 0; (i < count) && os->good(); ++i) { | 64 for (size_t i = 0; (i < count) && os->good(); ++i) { |
65 const int kMaxNameLength = 256; | 65 const int kMaxNameLength = 256; |
66 DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]); | 66 DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]); |
67 | 67 |
68 // Code adapted from MSDN example: | 68 // Code adapted from MSDN example: |
69 // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx | 69 // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx |
70 ULONG64 buffer[ | 70 ULONG64 buffer[ |
(...skipping 17 matching lines...) Expand all Loading... | |
88 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); | 88 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
89 BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame, | 89 BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame, |
90 &line_displacement, &line); | 90 &line_displacement, &line); |
91 | 91 |
92 // Output the backtrace line. | 92 // Output the backtrace line. |
93 (*os) << "\t"; | 93 (*os) << "\t"; |
94 if (has_symbol) { | 94 if (has_symbol) { |
95 (*os) << symbol->Name << " [0x" << trace[i] << "+" | 95 (*os) << symbol->Name << " [0x" << trace[i] << "+" |
96 << sym_displacement << "]"; | 96 << sym_displacement << "]"; |
97 } else { | 97 } else { |
98 // If there is no symbol informtion, add a spacer. | 98 // If there is no symbol information, add a spacer. |
99 (*os) << "(No symbol) [0x" << trace[i] << "]"; | 99 (*os) << "(No symbol) [0x" << trace[i] << "]"; |
100 } | 100 } |
101 if (has_line) { | 101 if (has_line) { |
102 (*os) << " (" << line.FileName << ":" << line.LineNumber << ")"; | 102 (*os) << " (" << line.FileName << ":" << line.LineNumber << ")"; |
103 } | 103 } |
104 (*os) << "\n"; | 104 (*os) << "\n"; |
105 } | 105 } |
106 } | 106 } |
107 | 107 |
108 private: | 108 private: |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 GetCurrentThread(), | 178 GetCurrentThread(), |
179 &stack_frame, | 179 &stack_frame, |
180 exception_pointers->ContextRecord, | 180 exception_pointers->ContextRecord, |
181 NULL, | 181 NULL, |
182 &SymFunctionTableAccess64, | 182 &SymFunctionTableAccess64, |
183 &SymGetModuleBase64, | 183 &SymGetModuleBase64, |
184 NULL) && | 184 NULL) && |
185 count_ < arraysize(trace_)) { | 185 count_ < arraysize(trace_)) { |
186 trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset); | 186 trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset); |
187 } | 187 } |
188 | |
189 for (size_t i = count_; i < arraysize(trace_); ++i) | |
brettw
2012/07/25 17:37:26
I'd probably use kMacTrace here instead (since you
James Hawkins
2012/07/25 18:58:09
OK. I actually searched for arraysize to get back
| |
190 trace_[i] = NULL; | |
188 } | 191 } |
189 | 192 |
190 void StackTrace::PrintBacktrace() const { | 193 void StackTrace::PrintBacktrace() const { |
191 OutputToStream(&std::cerr); | 194 OutputToStream(&std::cerr); |
192 } | 195 } |
193 | 196 |
194 void StackTrace::OutputToStream(std::ostream* os) const { | 197 void StackTrace::OutputToStream(std::ostream* os) const { |
195 SymbolContext* context = SymbolContext::GetInstance(); | 198 SymbolContext* context = SymbolContext::GetInstance(); |
196 DWORD error = context->init_error(); | 199 DWORD error = context->init_error(); |
197 if (error != ERROR_SUCCESS) { | 200 if (error != ERROR_SUCCESS) { |
198 (*os) << "Error initializing symbols (" << error | 201 (*os) << "Error initializing symbols (" << error |
199 << "). Dumping unresolved backtrace:\n"; | 202 << "). Dumping unresolved backtrace:\n"; |
200 for (int i = 0; (i < count_) && os->good(); ++i) { | 203 for (int i = 0; (i < count_) && os->good(); ++i) { |
201 (*os) << "\t" << trace_[i] << "\n"; | 204 (*os) << "\t" << trace_[i] << "\n"; |
202 } | 205 } |
203 } else { | 206 } else { |
204 (*os) << "Backtrace:\n"; | 207 (*os) << "Backtrace:\n"; |
205 context->OutputTraceToStream(trace_, count_, os); | 208 context->OutputTraceToStream(trace_, count_, os); |
206 } | 209 } |
207 } | 210 } |
208 | 211 |
209 } // namespace debug | 212 } // namespace debug |
210 } // namespace base | 213 } // namespace base |
OLD | NEW |