OLD | NEW |
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2009 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_util.h" | 5 #include "base/debug_util.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> |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 // just ignore it. | 85 // just ignore it. |
86 class SymbolContext { | 86 class SymbolContext { |
87 public: | 87 public: |
88 static SymbolContext* Get() { | 88 static SymbolContext* Get() { |
89 // We use a leaky singleton because code may call this during process | 89 // We use a leaky singleton because code may call this during process |
90 // termination. | 90 // termination. |
91 return | 91 return |
92 Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get(); | 92 Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get(); |
93 } | 93 } |
94 | 94 |
95 // Initializes the symbols for the process if it hasn't been done yet. | 95 // Returns the error code of a failed initialization. |
96 // Subsequent calls will not reinitialize the symbol, but instead return | 96 DWORD init_error() const { |
97 // the error code from the first call. | |
98 bool Init() { | |
99 AutoLock lock(lock_); | |
100 if (!initialized_) { | |
101 process_ = GetCurrentProcess(); | |
102 | |
103 // Defer symbol load until they're needed, use undecorated names, and | |
104 // get line numbers. | |
105 SymSetOptions(SYMOPT_DEFERRED_LOADS | | |
106 SYMOPT_UNDNAME | | |
107 SYMOPT_LOAD_LINES); | |
108 if (SymInitialize(process_, NULL, TRUE)) { | |
109 init_error_ = ERROR_SUCCESS; | |
110 } else { | |
111 init_error_ = GetLastError(); | |
112 } | |
113 } | |
114 | |
115 initialized_ = true; | |
116 return init_error_ == ERROR_SUCCESS; | |
117 } | |
118 | |
119 // Returns the error code of a failed initialization. This should only be | |
120 // called if Init() has been called. We do not LOG(FATAL) here because | |
121 // this code is called might be triggered by a LOG(FATAL) itself. Instead, | |
122 // we log an ERROR, and return ERROR_INVALID_DATA. | |
123 DWORD init_error() { | |
124 if (!initialized_) { | |
125 LOG(ERROR) << "Calling GetInitError() before Init() was called. " | |
126 << "Returning ERROR_INVALID_DATA."; | |
127 return ERROR_INVALID_DATA; | |
128 } | |
129 | |
130 return init_error_; | 97 return init_error_; |
131 } | 98 } |
132 | 99 |
133 // Returns the process this was initialized for. This should only be | |
134 // called if Init() has been called. We LOG(ERROR) in this situation. | |
135 // LOG(FATAL) is not used because this code is might be triggered | |
136 // by a LOG(FATAL) itself. | |
137 HANDLE process() { | |
138 if (!initialized_) { | |
139 LOG(ERROR) << "Calling process() before Init() was called. " | |
140 << "Returning NULL."; | |
141 return NULL; | |
142 } | |
143 | |
144 return process_; | |
145 } | |
146 | |
147 // For the given trace, attempts to resolve the symbols, and output a trace | 100 // For the given trace, attempts to resolve the symbols, and output a trace |
148 // to the ostream os. The format for each line of the backtrace is: | 101 // to the ostream os. The format for each line of the backtrace is: |
149 // | 102 // |
150 // <tab>SymbolName[0xAddress+Offset] (FileName:LineNo) | 103 // <tab>SymbolName[0xAddress+Offset] (FileName:LineNo) |
151 // | 104 // |
152 // This function should only be called if Init() has been called. We do not | 105 // This function should only be called if Init() has been called. We do not |
153 // LOG(FATAL) here because this code is called might be triggered by a | 106 // LOG(FATAL) here because this code is called might be triggered by a |
154 // LOG(FATAL) itself. | 107 // LOG(FATAL) itself. |
155 void OutputTraceToStream(const std::vector<void*>& trace, std::ostream* os) { | 108 void OutputTraceToStream(const std::vector<void*>& trace, std::ostream* os) { |
156 AutoLock lock(lock_); | 109 AutoLock lock(lock_); |
157 | 110 |
158 for (size_t i = 0; (i < trace.size()) && os->good(); ++i) { | 111 for (size_t i = 0; (i < trace.size()) && os->good(); ++i) { |
159 const int kMaxNameLength = 256; | 112 const int kMaxNameLength = 256; |
160 DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]); | 113 DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]); |
161 | 114 |
162 // Code adapted from MSDN example: | 115 // Code adapted from MSDN example: |
163 // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx | 116 // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx |
164 ULONG64 buffer[ | 117 ULONG64 buffer[ |
165 (sizeof(SYMBOL_INFO) + | 118 (sizeof(SYMBOL_INFO) + |
166 kMaxNameLength * sizeof(wchar_t) + | 119 kMaxNameLength * sizeof(wchar_t) + |
167 sizeof(ULONG64) - 1) / | 120 sizeof(ULONG64) - 1) / |
168 sizeof(ULONG64)]; | 121 sizeof(ULONG64)]; |
169 | 122 |
170 // Initialize symbol information retrieval structures. | 123 // Initialize symbol information retrieval structures. |
171 DWORD64 sym_displacement = 0; | 124 DWORD64 sym_displacement = 0; |
172 PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]); | 125 PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]); |
173 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); | 126 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
174 symbol->MaxNameLen = kMaxNameLength; | 127 symbol->MaxNameLen = kMaxNameLength; |
175 BOOL has_symbol = SymFromAddr(process(), frame, | 128 BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame, |
176 &sym_displacement, symbol); | 129 &sym_displacement, symbol); |
177 | 130 |
178 // Attempt to retrieve line number information. | 131 // Attempt to retrieve line number information. |
179 DWORD line_displacement = 0; | 132 DWORD line_displacement = 0; |
180 IMAGEHLP_LINE64 line = {}; | 133 IMAGEHLP_LINE64 line = {}; |
181 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); | 134 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
182 BOOL has_line = SymGetLineFromAddr64(process(), frame, | 135 BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame, |
183 &line_displacement, &line); | 136 &line_displacement, &line); |
184 | 137 |
185 // Output the backtrace line. | 138 // Output the backtrace line. |
186 (*os) << "\t"; | 139 (*os) << "\t"; |
187 if (has_symbol) { | 140 if (has_symbol) { |
188 (*os) << symbol->Name << " [0x" << trace[i] << "+" | 141 (*os) << symbol->Name << " [0x" << trace[i] << "+" |
189 << sym_displacement << "]"; | 142 << sym_displacement << "]"; |
190 } else { | 143 } else { |
191 // If there is no symbol informtion, add a spacer. | 144 // If there is no symbol informtion, add a spacer. |
192 (*os) << "(No symbol) [0x" << trace[i] << "]"; | 145 (*os) << "(No symbol) [0x" << trace[i] << "]"; |
193 } | 146 } |
194 if (has_line) { | 147 if (has_line) { |
195 (*os) << " (" << line.FileName << ":" << line.LineNumber << ")"; | 148 (*os) << " (" << line.FileName << ":" << line.LineNumber << ")"; |
196 } | 149 } |
197 (*os) << "\n"; | 150 (*os) << "\n"; |
198 } | 151 } |
199 } | 152 } |
200 | 153 |
201 SymbolContext() | 154 private: |
202 : initialized_(false), | 155 friend struct DefaultSingletonTraits<SymbolContext>; |
203 process_(NULL), | 156 |
204 init_error_(ERROR_SUCCESS) { | 157 SymbolContext() : init_error_(ERROR_SUCCESS) { |
| 158 // Initializes the symbols for the process. |
| 159 // Defer symbol load until they're needed, use undecorated names, and |
| 160 // get line numbers. |
| 161 SymSetOptions(SYMOPT_DEFERRED_LOADS | |
| 162 SYMOPT_UNDNAME | |
| 163 SYMOPT_LOAD_LINES); |
| 164 if (SymInitialize(GetCurrentProcess(), NULL, TRUE)) { |
| 165 init_error_ = ERROR_SUCCESS; |
| 166 } else { |
| 167 __debugbreak(); |
| 168 init_error_ = GetLastError(); |
| 169 } |
205 } | 170 } |
206 | 171 |
207 private: | 172 DWORD init_error_; |
208 Lock lock_; | 173 Lock lock_; |
209 bool initialized_; | |
210 HANDLE process_; | |
211 DWORD init_error_; | |
212 | |
213 DISALLOW_COPY_AND_ASSIGN(SymbolContext); | 174 DISALLOW_COPY_AND_ASSIGN(SymbolContext); |
214 }; | 175 }; |
215 | 176 |
216 } // namespace | 177 } // namespace |
217 | 178 |
218 // Note: Does not use the CRT. | 179 // Note: Does not use the CRT. |
219 bool DebugUtil::SpawnDebuggerOnProcess(unsigned process_id) { | 180 bool DebugUtil::SpawnDebuggerOnProcess(unsigned process_id) { |
220 wchar_t reg_value[1026]; | 181 wchar_t reg_value[1026]; |
221 int len = arraysize(reg_value); | 182 int len = arraysize(reg_value); |
222 if (RegReadString(HKEY_LOCAL_MACHINE, | 183 if (RegReadString(HKEY_LOCAL_MACHINE, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 trace_.resize(0); | 230 trace_.resize(0); |
270 } | 231 } |
271 } | 232 } |
272 | 233 |
273 void StackTrace::PrintBacktrace() { | 234 void StackTrace::PrintBacktrace() { |
274 OutputToStream(&std::cerr); | 235 OutputToStream(&std::cerr); |
275 } | 236 } |
276 | 237 |
277 void StackTrace::OutputToStream(std::ostream* os) { | 238 void StackTrace::OutputToStream(std::ostream* os) { |
278 SymbolContext* context = SymbolContext::Get(); | 239 SymbolContext* context = SymbolContext::Get(); |
279 | 240 DWORD error = context->init_error(); |
280 if (context->Init() != ERROR_SUCCESS) { | 241 if (error != ERROR_SUCCESS) { |
281 DWORD error = context->init_error(); | |
282 (*os) << "Error initializing symbols (" << error | 242 (*os) << "Error initializing symbols (" << error |
283 << "). Dumping unresolved backtrace:\n"; | 243 << "). Dumping unresolved backtrace:\n"; |
284 for (size_t i = 0; (i < trace_.size()) && os->good(); ++i) { | 244 for (size_t i = 0; (i < trace_.size()) && os->good(); ++i) { |
285 (*os) << "\t" << trace_[i] << "\n"; | 245 (*os) << "\t" << trace_[i] << "\n"; |
286 } | 246 } |
287 } else { | 247 } else { |
288 (*os) << "Backtrace:\n"; | 248 (*os) << "Backtrace:\n"; |
289 context->OutputTraceToStream(trace_, os); | 249 context->OutputTraceToStream(trace_, os); |
290 } | 250 } |
291 } | 251 } |
OLD | NEW |