8 #include "src/base/debug/stack_trace.h" 25 #include "src/base/logging.h" 26 #include "src/base/macros.h" 36 LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter =
nullptr;
38 bool g_dump_stack_in_signal_handler =
true;
39 bool g_initialized_symbols =
false;
40 DWORD g_init_error = ERROR_SUCCESS;
44 long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
45 if (g_dump_stack_in_signal_handler) {
46 debug::StackTrace(info).Print();
48 if (g_previous_filter)
return g_previous_filter(info);
49 return EXCEPTION_CONTINUE_SEARCH;
52 void GetExePath(
wchar_t* path_out) {
53 GetModuleFileName(
nullptr, path_out, MAX_PATH);
54 path_out[MAX_PATH - 1] = L
'\0';
55 PathRemoveFileSpec(path_out);
58 bool InitializeSymbols() {
59 if (g_initialized_symbols)
return g_init_error == ERROR_SUCCESS;
60 g_initialized_symbols =
true;
63 SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
64 if (!SymInitialize(GetCurrentProcess(),
nullptr, TRUE)) {
65 g_init_error = GetLastError();
78 const size_t kSymbolsArraySize = 1024;
79 std::unique_ptr<wchar_t[]> symbols_path(
new wchar_t[kSymbolsArraySize]);
83 if (!SymGetSearchPathW(GetCurrentProcess(), symbols_path.get(),
85 g_init_error = GetLastError();
89 wchar_t exe_path[MAX_PATH];
91 std::wstring new_path(std::wstring(symbols_path.get()) + L
";" +
92 std::wstring(exe_path));
93 if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) {
94 g_init_error = GetLastError();
98 g_init_error = ERROR_SUCCESS;
111 void OutputTraceToStream(
const void*
const* trace,
size_t count,
113 for (
size_t i = 0; (
i < count) && os->good(); ++
i) {
114 const int kMaxNameLength = 256;
115 DWORD_PTR frame =
reinterpret_cast<DWORD_PTR
>(trace[
i]);
119 ULONG64 buffer[(
sizeof(SYMBOL_INFO) + kMaxNameLength *
sizeof(
wchar_t) +
120 sizeof(ULONG64) - 1) /
122 memset(buffer, 0,
sizeof(buffer));
125 DWORD64 sym_displacement = 0;
126 PSYMBOL_INFO symbol =
reinterpret_cast<PSYMBOL_INFO
>(&buffer[0]);
127 symbol->SizeOfStruct =
sizeof(SYMBOL_INFO);
128 symbol->MaxNameLen = kMaxNameLength - 1;
130 SymFromAddr(GetCurrentProcess(), frame, &sym_displacement, symbol);
133 DWORD line_displacement = 0;
134 IMAGEHLP_LINE64 line = {};
135 line.SizeOfStruct =
sizeof(IMAGEHLP_LINE64);
136 BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
137 &line_displacement, &line);
142 (*os) << symbol->Name <<
" [0x" << trace[
i] <<
"+" << sym_displacement
146 (*os) <<
"(No symbol) [0x" << trace[
i] <<
"]";
149 (*os) <<
" (" << line.FileName <<
":" << line.LineNumber <<
")";
157 bool EnableInProcessStackDumping() {
160 g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
161 g_dump_stack_in_signal_handler =
true;
166 return InitializeSymbols();
169 void DisableSignalStackDump() {
170 g_dump_stack_in_signal_handler =
false;
173 StackTrace::StackTrace() {
175 count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_,
nullptr);
178 StackTrace::StackTrace(EXCEPTION_POINTERS* exception_pointers) {
179 InitTrace(exception_pointers->ContextRecord);
182 StackTrace::StackTrace(
const CONTEXT* context) { InitTrace(context); }
184 void StackTrace::InitTrace(
const CONTEXT* context_record) {
189 CONTEXT context_copy;
190 memcpy(&context_copy, context_record,
sizeof(context_copy));
191 context_copy.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
196 STACKFRAME64 stack_frame;
197 memset(&stack_frame, 0,
sizeof(stack_frame));
200 int machine_type = IMAGE_FILE_MACHINE_AMD64;
201 stack_frame.AddrPC.Offset = context_record->Rip;
202 stack_frame.AddrFrame.Offset = context_record->Rbp;
203 stack_frame.AddrStack.Offset = context_record->Rsp;
204 #elif defined(_M_ARM64) 205 int machine_type = IMAGE_FILE_MACHINE_ARM64;
206 stack_frame.AddrPC.Offset = context_record->Pc;
207 stack_frame.AddrFrame.Offset = context_record->Fp;
208 stack_frame.AddrStack.Offset = context_record->Sp;
210 #error Unsupported Arch 213 int machine_type = IMAGE_FILE_MACHINE_I386;
214 stack_frame.AddrPC.Offset = context_record->Eip;
215 stack_frame.AddrFrame.Offset = context_record->Ebp;
216 stack_frame.AddrStack.Offset = context_record->Esp;
218 stack_frame.AddrPC.Mode = AddrModeFlat;
219 stack_frame.AddrFrame.Mode = AddrModeFlat;
220 stack_frame.AddrStack.Mode = AddrModeFlat;
221 while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
222 &stack_frame, &context_copy,
nullptr,
223 &SymFunctionTableAccess64, &SymGetModuleBase64,
nullptr) &&
224 count_ < arraysize(trace_)) {
225 trace_[count_++] =
reinterpret_cast<void*
>(stack_frame.AddrPC.Offset);
228 for (
size_t i = count_;
i < arraysize(trace_); ++
i) trace_[
i] =
nullptr;
231 void StackTrace::Print()
const { OutputToStream(&std::cerr); }
233 void StackTrace::OutputToStream(std::ostream* os)
const {
235 if (g_init_error != ERROR_SUCCESS) {
236 (*os) <<
"Error initializing symbols (" << g_init_error
237 <<
"). Dumping unresolved backtrace:\n";
238 for (
size_t i = 0; (
i < count_) && os->good(); ++
i) {
239 (*os) <<
"\t" << trace_[
i] <<
"\n";
243 (*os) <<
"==== C stack trace ===============================\n";
245 OutputTraceToStream(trace_, count_, os);