xref: /aosp_15_r20/external/cronet/base/debug/stack_trace_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <windows.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <dbghelp.h>
10*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include <algorithm>
13*6777b538SAndroid Build Coastguard Worker #include <iostream>
14*6777b538SAndroid Build Coastguard Worker #include <iterator>
15*6777b538SAndroid Build Coastguard Worker #include <memory>
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/memory/singleton.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat_win.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
24*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker namespace base {
27*6777b538SAndroid Build Coastguard Worker namespace debug {
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker namespace {
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker // Previous unhandled filter. Will be called if not NULL when we intercept an
32*6777b538SAndroid Build Coastguard Worker // exception. Only used in unit tests.
33*6777b538SAndroid Build Coastguard Worker LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker bool g_initialized_symbols = false;
36*6777b538SAndroid Build Coastguard Worker DWORD g_init_error = ERROR_SUCCESS;
37*6777b538SAndroid Build Coastguard Worker // STATUS_INFO_LENGTH_MISMATCH is declared in <ntstatus.h>, but including that
38*6777b538SAndroid Build Coastguard Worker // header creates a conflict with base/win/windows_types.h, so re-declaring it
39*6777b538SAndroid Build Coastguard Worker // here.
40*6777b538SAndroid Build Coastguard Worker DWORD g_status_info_length_mismatch = 0xC0000004;
41*6777b538SAndroid Build Coastguard Worker 
42*6777b538SAndroid Build Coastguard Worker // Prints the exception call stack.
43*6777b538SAndroid Build Coastguard Worker // This is the unit tests exception filter.
StackDumpExceptionFilter(EXCEPTION_POINTERS * info)44*6777b538SAndroid Build Coastguard Worker long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
45*6777b538SAndroid Build Coastguard Worker   DWORD exc_code = info->ExceptionRecord->ExceptionCode;
46*6777b538SAndroid Build Coastguard Worker   std::cerr << "Received fatal exception ";
47*6777b538SAndroid Build Coastguard Worker   switch (exc_code) {
48*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_ACCESS_VIOLATION:
49*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_ACCESS_VIOLATION";
50*6777b538SAndroid Build Coastguard Worker       break;
51*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
52*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
53*6777b538SAndroid Build Coastguard Worker       break;
54*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_BREAKPOINT:
55*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_BREAKPOINT";
56*6777b538SAndroid Build Coastguard Worker       break;
57*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_DATATYPE_MISALIGNMENT:
58*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_DATATYPE_MISALIGNMENT";
59*6777b538SAndroid Build Coastguard Worker       break;
60*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_DENORMAL_OPERAND:
61*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_DENORMAL_OPERAND";
62*6777b538SAndroid Build Coastguard Worker       break;
63*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
64*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_DIVIDE_BY_ZERO";
65*6777b538SAndroid Build Coastguard Worker       break;
66*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_INEXACT_RESULT:
67*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_INEXACT_RESULT";
68*6777b538SAndroid Build Coastguard Worker       break;
69*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_INVALID_OPERATION:
70*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_INVALID_OPERATION";
71*6777b538SAndroid Build Coastguard Worker       break;
72*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_OVERFLOW:
73*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_OVERFLOW";
74*6777b538SAndroid Build Coastguard Worker       break;
75*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_STACK_CHECK:
76*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_STACK_CHECK";
77*6777b538SAndroid Build Coastguard Worker       break;
78*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_FLT_UNDERFLOW:
79*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_FLT_UNDERFLOW";
80*6777b538SAndroid Build Coastguard Worker       break;
81*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_ILLEGAL_INSTRUCTION:
82*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_ILLEGAL_INSTRUCTION";
83*6777b538SAndroid Build Coastguard Worker       break;
84*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_IN_PAGE_ERROR:
85*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_IN_PAGE_ERROR";
86*6777b538SAndroid Build Coastguard Worker       break;
87*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_INT_DIVIDE_BY_ZERO:
88*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_INT_DIVIDE_BY_ZERO";
89*6777b538SAndroid Build Coastguard Worker       break;
90*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_INT_OVERFLOW:
91*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_INT_OVERFLOW";
92*6777b538SAndroid Build Coastguard Worker       break;
93*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_INVALID_DISPOSITION:
94*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_INVALID_DISPOSITION";
95*6777b538SAndroid Build Coastguard Worker       break;
96*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
97*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_NONCONTINUABLE_EXCEPTION";
98*6777b538SAndroid Build Coastguard Worker       break;
99*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_PRIV_INSTRUCTION:
100*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_PRIV_INSTRUCTION";
101*6777b538SAndroid Build Coastguard Worker       break;
102*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_SINGLE_STEP:
103*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_SINGLE_STEP";
104*6777b538SAndroid Build Coastguard Worker       break;
105*6777b538SAndroid Build Coastguard Worker     case EXCEPTION_STACK_OVERFLOW:
106*6777b538SAndroid Build Coastguard Worker       std::cerr << "EXCEPTION_STACK_OVERFLOW";
107*6777b538SAndroid Build Coastguard Worker       break;
108*6777b538SAndroid Build Coastguard Worker     default:
109*6777b538SAndroid Build Coastguard Worker       std::cerr << "0x" << std::hex << exc_code;
110*6777b538SAndroid Build Coastguard Worker       break;
111*6777b538SAndroid Build Coastguard Worker   }
112*6777b538SAndroid Build Coastguard Worker   std::cerr << "\n";
113*6777b538SAndroid Build Coastguard Worker 
114*6777b538SAndroid Build Coastguard Worker   debug::StackTrace(info).Print();
115*6777b538SAndroid Build Coastguard Worker   if (g_previous_filter)
116*6777b538SAndroid Build Coastguard Worker     return g_previous_filter(info);
117*6777b538SAndroid Build Coastguard Worker   return EXCEPTION_CONTINUE_SEARCH;
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker 
GetExePath()120*6777b538SAndroid Build Coastguard Worker FilePath GetExePath() {
121*6777b538SAndroid Build Coastguard Worker   wchar_t system_buffer[MAX_PATH];
122*6777b538SAndroid Build Coastguard Worker   GetModuleFileName(NULL, system_buffer, MAX_PATH);
123*6777b538SAndroid Build Coastguard Worker   system_buffer[MAX_PATH - 1] = L'\0';
124*6777b538SAndroid Build Coastguard Worker   return FilePath(system_buffer);
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker constexpr size_t kSymInitializeRetryCount = 3;
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker // A wrapper for SymInitialize. SymInitialize seems to occasionally fail
130*6777b538SAndroid Build Coastguard Worker // because of an internal race condition. So  wrap it and retry a finite
131*6777b538SAndroid Build Coastguard Worker // number of times.
132*6777b538SAndroid Build Coastguard Worker // See crbug.com/1339753
SymInitializeWrapper(HANDLE handle,BOOL invade_process)133*6777b538SAndroid Build Coastguard Worker bool SymInitializeWrapper(HANDLE handle, BOOL invade_process) {
134*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < kSymInitializeRetryCount; ++i) {
135*6777b538SAndroid Build Coastguard Worker     if (SymInitialize(handle, nullptr, invade_process))
136*6777b538SAndroid Build Coastguard Worker       return true;
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker     g_init_error = GetLastError();
139*6777b538SAndroid Build Coastguard Worker     if (g_init_error != g_status_info_length_mismatch)
140*6777b538SAndroid Build Coastguard Worker       return false;
141*6777b538SAndroid Build Coastguard Worker   }
142*6777b538SAndroid Build Coastguard Worker   DLOG(ERROR) << "SymInitialize failed repeatedly.";
143*6777b538SAndroid Build Coastguard Worker   return false;
144*6777b538SAndroid Build Coastguard Worker }
145*6777b538SAndroid Build Coastguard Worker 
SymInitializeCurrentProc()146*6777b538SAndroid Build Coastguard Worker bool SymInitializeCurrentProc() {
147*6777b538SAndroid Build Coastguard Worker   const HANDLE current_process = GetCurrentProcess();
148*6777b538SAndroid Build Coastguard Worker   if (SymInitializeWrapper(current_process, TRUE))
149*6777b538SAndroid Build Coastguard Worker     return true;
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker   // g_init_error is updated by SymInitializeWrapper.
152*6777b538SAndroid Build Coastguard Worker   // No need to do "g_init_error = GetLastError()" here.
153*6777b538SAndroid Build Coastguard Worker   if (g_init_error != ERROR_INVALID_PARAMETER)
154*6777b538SAndroid Build Coastguard Worker     return false;
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker   // SymInitialize() can fail with ERROR_INVALID_PARAMETER when something has
157*6777b538SAndroid Build Coastguard Worker   // already called SymInitialize() in this process. For example, when absl
158*6777b538SAndroid Build Coastguard Worker   // support for gtest is enabled, it results in absl calling SymInitialize()
159*6777b538SAndroid Build Coastguard Worker   // almost immediately after startup. In such a case, try to reinit to see if
160*6777b538SAndroid Build Coastguard Worker   // that succeeds.
161*6777b538SAndroid Build Coastguard Worker   SymCleanup(current_process);
162*6777b538SAndroid Build Coastguard Worker   if (SymInitializeWrapper(current_process, TRUE))
163*6777b538SAndroid Build Coastguard Worker     return true;
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker   return false;
166*6777b538SAndroid Build Coastguard Worker }
167*6777b538SAndroid Build Coastguard Worker 
InitializeSymbols()168*6777b538SAndroid Build Coastguard Worker bool InitializeSymbols() {
169*6777b538SAndroid Build Coastguard Worker   if (g_initialized_symbols) {
170*6777b538SAndroid Build Coastguard Worker     // Force a reinitialization. Will ensure any modules loaded after process
171*6777b538SAndroid Build Coastguard Worker     // startup also get symbolized.
172*6777b538SAndroid Build Coastguard Worker     SymCleanup(GetCurrentProcess());
173*6777b538SAndroid Build Coastguard Worker     g_initialized_symbols = false;
174*6777b538SAndroid Build Coastguard Worker   }
175*6777b538SAndroid Build Coastguard Worker   g_initialized_symbols = true;
176*6777b538SAndroid Build Coastguard Worker   // Defer symbol load until they're needed, use undecorated names, and get line
177*6777b538SAndroid Build Coastguard Worker   // numbers.
178*6777b538SAndroid Build Coastguard Worker   SymSetOptions(SYMOPT_DEFERRED_LOADS |
179*6777b538SAndroid Build Coastguard Worker                 SYMOPT_UNDNAME |
180*6777b538SAndroid Build Coastguard Worker                 SYMOPT_LOAD_LINES);
181*6777b538SAndroid Build Coastguard Worker   if (!SymInitializeCurrentProc()) {
182*6777b538SAndroid Build Coastguard Worker     // When it fails, we should not call debugbreak since it kills the current
183*6777b538SAndroid Build Coastguard Worker     // process (prevents future tests from running or kills the browser
184*6777b538SAndroid Build Coastguard Worker     // process).
185*6777b538SAndroid Build Coastguard Worker     DLOG(ERROR) << "SymInitialize failed: " << g_init_error;
186*6777b538SAndroid Build Coastguard Worker     return false;
187*6777b538SAndroid Build Coastguard Worker   }
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker   // When transferring the binaries e.g. between bots, path put
190*6777b538SAndroid Build Coastguard Worker   // into the executable will get off. To still retrieve symbols correctly,
191*6777b538SAndroid Build Coastguard Worker   // add the directory of the executable to symbol search path.
192*6777b538SAndroid Build Coastguard Worker   // All following errors are non-fatal.
193*6777b538SAndroid Build Coastguard Worker   static constexpr size_t kSymbolsArraySize = 1024;
194*6777b538SAndroid Build Coastguard Worker   wchar_t symbols_path[kSymbolsArraySize];
195*6777b538SAndroid Build Coastguard Worker 
196*6777b538SAndroid Build Coastguard Worker   // Note: The below function takes buffer size as number of characters,
197*6777b538SAndroid Build Coastguard Worker   // not number of bytes!
198*6777b538SAndroid Build Coastguard Worker   if (!SymGetSearchPathW(GetCurrentProcess(), symbols_path,
199*6777b538SAndroid Build Coastguard Worker                          kSymbolsArraySize)) {
200*6777b538SAndroid Build Coastguard Worker     g_init_error = GetLastError();
201*6777b538SAndroid Build Coastguard Worker     DLOG(WARNING) << "SymGetSearchPath failed: " << g_init_error;
202*6777b538SAndroid Build Coastguard Worker     return false;
203*6777b538SAndroid Build Coastguard Worker   }
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   std::wstring new_path =
206*6777b538SAndroid Build Coastguard Worker       StrCat({symbols_path, L";", GetExePath().DirName().value()});
207*6777b538SAndroid Build Coastguard Worker   if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) {
208*6777b538SAndroid Build Coastguard Worker     g_init_error = GetLastError();
209*6777b538SAndroid Build Coastguard Worker     DLOG(WARNING) << "SymSetSearchPath failed." << g_init_error;
210*6777b538SAndroid Build Coastguard Worker     return false;
211*6777b538SAndroid Build Coastguard Worker   }
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker   g_init_error = ERROR_SUCCESS;
214*6777b538SAndroid Build Coastguard Worker   return true;
215*6777b538SAndroid Build Coastguard Worker }
216*6777b538SAndroid Build Coastguard Worker 
217*6777b538SAndroid Build Coastguard Worker // SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family
218*6777b538SAndroid Build Coastguard Worker // of functions.  The Sym* family of functions may only be invoked by one
219*6777b538SAndroid Build Coastguard Worker // thread at a time.  SymbolContext code may access a symbol server over the
220*6777b538SAndroid Build Coastguard Worker // network while holding the lock for this singleton.  In the case of high
221*6777b538SAndroid Build Coastguard Worker // latency, this code will adversely affect performance.
222*6777b538SAndroid Build Coastguard Worker //
223*6777b538SAndroid Build Coastguard Worker // There is also a known issue where this backtrace code can interact
224*6777b538SAndroid Build Coastguard Worker // badly with breakpad if breakpad is invoked in a separate thread while
225*6777b538SAndroid Build Coastguard Worker // we are using the Sym* functions.  This is because breakpad does now
226*6777b538SAndroid Build Coastguard Worker // share a lock with this function.  See this related bug:
227*6777b538SAndroid Build Coastguard Worker //
228*6777b538SAndroid Build Coastguard Worker //   https://crbug.com/google-breakpad/311
229*6777b538SAndroid Build Coastguard Worker //
230*6777b538SAndroid Build Coastguard Worker // This is a very unlikely edge case, and the current solution is to
231*6777b538SAndroid Build Coastguard Worker // just ignore it.
232*6777b538SAndroid Build Coastguard Worker class SymbolContext {
233*6777b538SAndroid Build Coastguard Worker  public:
GetInstance()234*6777b538SAndroid Build Coastguard Worker   static SymbolContext* GetInstance() {
235*6777b538SAndroid Build Coastguard Worker     // We use a leaky singleton because code may call this during process
236*6777b538SAndroid Build Coastguard Worker     // termination.
237*6777b538SAndroid Build Coastguard Worker     return
238*6777b538SAndroid Build Coastguard Worker       Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get();
239*6777b538SAndroid Build Coastguard Worker   }
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker   SymbolContext(const SymbolContext&) = delete;
242*6777b538SAndroid Build Coastguard Worker   SymbolContext& operator=(const SymbolContext&) = delete;
243*6777b538SAndroid Build Coastguard Worker 
244*6777b538SAndroid Build Coastguard Worker   // For the given trace, attempts to resolve the symbols, and output a trace
245*6777b538SAndroid Build Coastguard Worker   // to the ostream os.  The format for each line of the backtrace is:
246*6777b538SAndroid Build Coastguard Worker   //
247*6777b538SAndroid Build Coastguard Worker   //    <tab>SymbolName[0xAddress+Offset] (FileName:LineNo)
248*6777b538SAndroid Build Coastguard Worker   //
249*6777b538SAndroid Build Coastguard Worker   // This function should only be called if Init() has been called.  We do not
250*6777b538SAndroid Build Coastguard Worker   // LOG(FATAL) here because this code is called might be triggered by a
251*6777b538SAndroid Build Coastguard Worker   // LOG(FATAL) itself. Also, it should not be calling complex code that is
252*6777b538SAndroid Build Coastguard Worker   // extensible like PathService since that can in turn fire CHECKs.
OutputTraceToStream(const void * const * trace,size_t count,std::ostream * os,cstring_view prefix_string)253*6777b538SAndroid Build Coastguard Worker   void OutputTraceToStream(const void* const* trace,
254*6777b538SAndroid Build Coastguard Worker                            size_t count,
255*6777b538SAndroid Build Coastguard Worker                            std::ostream* os,
256*6777b538SAndroid Build Coastguard Worker                            cstring_view prefix_string) {
257*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
258*6777b538SAndroid Build Coastguard Worker 
259*6777b538SAndroid Build Coastguard Worker     for (size_t i = 0; (i < count) && os->good(); ++i) {
260*6777b538SAndroid Build Coastguard Worker       const int kMaxNameLength = 256;
261*6777b538SAndroid Build Coastguard Worker       DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]);
262*6777b538SAndroid Build Coastguard Worker 
263*6777b538SAndroid Build Coastguard Worker       // Code adapted from MSDN example:
264*6777b538SAndroid Build Coastguard Worker       // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
265*6777b538SAndroid Build Coastguard Worker       ULONG64 buffer[
266*6777b538SAndroid Build Coastguard Worker         (sizeof(SYMBOL_INFO) +
267*6777b538SAndroid Build Coastguard Worker           kMaxNameLength * sizeof(wchar_t) +
268*6777b538SAndroid Build Coastguard Worker           sizeof(ULONG64) - 1) /
269*6777b538SAndroid Build Coastguard Worker         sizeof(ULONG64)];
270*6777b538SAndroid Build Coastguard Worker       memset(buffer, 0, sizeof(buffer));
271*6777b538SAndroid Build Coastguard Worker 
272*6777b538SAndroid Build Coastguard Worker       // Initialize symbol information retrieval structures.
273*6777b538SAndroid Build Coastguard Worker       DWORD64 sym_displacement = 0;
274*6777b538SAndroid Build Coastguard Worker       PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
275*6777b538SAndroid Build Coastguard Worker       symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
276*6777b538SAndroid Build Coastguard Worker       symbol->MaxNameLen = kMaxNameLength - 1;
277*6777b538SAndroid Build Coastguard Worker       BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame,
278*6777b538SAndroid Build Coastguard Worker                                     &sym_displacement, symbol);
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker       // Attempt to retrieve line number information.
281*6777b538SAndroid Build Coastguard Worker       DWORD line_displacement = 0;
282*6777b538SAndroid Build Coastguard Worker       IMAGEHLP_LINE64 line = {};
283*6777b538SAndroid Build Coastguard Worker       line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
284*6777b538SAndroid Build Coastguard Worker       BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
285*6777b538SAndroid Build Coastguard Worker                                            &line_displacement, &line);
286*6777b538SAndroid Build Coastguard Worker 
287*6777b538SAndroid Build Coastguard Worker       // Output the backtrace line.
288*6777b538SAndroid Build Coastguard Worker       (*os) << prefix_string << "\t";
289*6777b538SAndroid Build Coastguard Worker       if (has_symbol) {
290*6777b538SAndroid Build Coastguard Worker         (*os) << symbol->Name << " [0x" << trace[i] << "+"
291*6777b538SAndroid Build Coastguard Worker               << sym_displacement << "]";
292*6777b538SAndroid Build Coastguard Worker       } else {
293*6777b538SAndroid Build Coastguard Worker         // If there is no symbol information, add a spacer.
294*6777b538SAndroid Build Coastguard Worker         (*os) << "(No symbol) [0x" << trace[i] << "]";
295*6777b538SAndroid Build Coastguard Worker       }
296*6777b538SAndroid Build Coastguard Worker       if (has_line) {
297*6777b538SAndroid Build Coastguard Worker         (*os) << " (" << line.FileName << ":" << line.LineNumber << ")";
298*6777b538SAndroid Build Coastguard Worker       }
299*6777b538SAndroid Build Coastguard Worker       (*os) << "\n";
300*6777b538SAndroid Build Coastguard Worker     }
301*6777b538SAndroid Build Coastguard Worker   }
302*6777b538SAndroid Build Coastguard Worker 
303*6777b538SAndroid Build Coastguard Worker  private:
304*6777b538SAndroid Build Coastguard Worker   friend struct DefaultSingletonTraits<SymbolContext>;
305*6777b538SAndroid Build Coastguard Worker 
SymbolContext()306*6777b538SAndroid Build Coastguard Worker   SymbolContext() {
307*6777b538SAndroid Build Coastguard Worker     InitializeSymbols();
308*6777b538SAndroid Build Coastguard Worker   }
309*6777b538SAndroid Build Coastguard Worker 
310*6777b538SAndroid Build Coastguard Worker   Lock lock_;
311*6777b538SAndroid Build Coastguard Worker };
312*6777b538SAndroid Build Coastguard Worker 
313*6777b538SAndroid Build Coastguard Worker }  // namespace
314*6777b538SAndroid Build Coastguard Worker 
EnableInProcessStackDumping()315*6777b538SAndroid Build Coastguard Worker bool EnableInProcessStackDumping() {
316*6777b538SAndroid Build Coastguard Worker   // Add stack dumping support on exception on windows. Similar to OS_POSIX
317*6777b538SAndroid Build Coastguard Worker   // signal() handling in process_util_posix.cc.
318*6777b538SAndroid Build Coastguard Worker   g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
319*6777b538SAndroid Build Coastguard Worker 
320*6777b538SAndroid Build Coastguard Worker   // Need to initialize symbols early in the process or else this fails on
321*6777b538SAndroid Build Coastguard Worker   // swarming (since symbols are in different directory than in the exes) and
322*6777b538SAndroid Build Coastguard Worker   // also release x64.
323*6777b538SAndroid Build Coastguard Worker   return InitializeSymbols();
324*6777b538SAndroid Build Coastguard Worker }
325*6777b538SAndroid Build Coastguard Worker 
CollectStackTrace(const void ** trace,size_t count)326*6777b538SAndroid Build Coastguard Worker NOINLINE size_t CollectStackTrace(const void** trace, size_t count) {
327*6777b538SAndroid Build Coastguard Worker   // When walking our own stack, use CaptureStackBackTrace().
328*6777b538SAndroid Build Coastguard Worker   return CaptureStackBackTrace(0, count, const_cast<void**>(trace), NULL);
329*6777b538SAndroid Build Coastguard Worker }
330*6777b538SAndroid Build Coastguard Worker 
StackTrace(EXCEPTION_POINTERS * exception_pointers)331*6777b538SAndroid Build Coastguard Worker StackTrace::StackTrace(EXCEPTION_POINTERS* exception_pointers) {
332*6777b538SAndroid Build Coastguard Worker   InitTrace(exception_pointers->ContextRecord);
333*6777b538SAndroid Build Coastguard Worker }
334*6777b538SAndroid Build Coastguard Worker 
StackTrace(const CONTEXT * context)335*6777b538SAndroid Build Coastguard Worker StackTrace::StackTrace(const CONTEXT* context) {
336*6777b538SAndroid Build Coastguard Worker   InitTrace(context);
337*6777b538SAndroid Build Coastguard Worker }
338*6777b538SAndroid Build Coastguard Worker 
InitTrace(const CONTEXT * context_record)339*6777b538SAndroid Build Coastguard Worker void StackTrace::InitTrace(const CONTEXT* context_record) {
340*6777b538SAndroid Build Coastguard Worker   if (ShouldSuppressOutput()) {
341*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(count_, 0U);
342*6777b538SAndroid Build Coastguard Worker     base::ranges::fill(trace_, nullptr);
343*6777b538SAndroid Build Coastguard Worker     return;
344*6777b538SAndroid Build Coastguard Worker   }
345*6777b538SAndroid Build Coastguard Worker 
346*6777b538SAndroid Build Coastguard Worker   // StackWalk64 modifies the register context in place, so we have to copy it
347*6777b538SAndroid Build Coastguard Worker   // so that downstream exception handlers get the right context.  The incoming
348*6777b538SAndroid Build Coastguard Worker   // context may have had more register state (YMM, etc) than we need to unwind
349*6777b538SAndroid Build Coastguard Worker   // the stack. Typically StackWalk64 only needs integer and control registers.
350*6777b538SAndroid Build Coastguard Worker   CONTEXT context_copy;
351*6777b538SAndroid Build Coastguard Worker   memcpy(&context_copy, context_record, sizeof(context_copy));
352*6777b538SAndroid Build Coastguard Worker   context_copy.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
353*6777b538SAndroid Build Coastguard Worker 
354*6777b538SAndroid Build Coastguard Worker   // When walking an exception stack, we need to use StackWalk64().
355*6777b538SAndroid Build Coastguard Worker   count_ = 0;
356*6777b538SAndroid Build Coastguard Worker   // Initialize stack walking.
357*6777b538SAndroid Build Coastguard Worker   STACKFRAME64 stack_frame;
358*6777b538SAndroid Build Coastguard Worker   memset(&stack_frame, 0, sizeof(stack_frame));
359*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_X86_64)
360*6777b538SAndroid Build Coastguard Worker   DWORD machine_type = IMAGE_FILE_MACHINE_AMD64;
361*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrPC.Offset = context_record->Rip;
362*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrFrame.Offset = context_record->Rbp;
363*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrStack.Offset = context_record->Rsp;
364*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_ARM64)
365*6777b538SAndroid Build Coastguard Worker   DWORD machine_type = IMAGE_FILE_MACHINE_ARM64;
366*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrPC.Offset = context_record->Pc;
367*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrFrame.Offset = context_record->Fp;
368*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrStack.Offset = context_record->Sp;
369*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_X86)
370*6777b538SAndroid Build Coastguard Worker   DWORD machine_type = IMAGE_FILE_MACHINE_I386;
371*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrPC.Offset = context_record->Eip;
372*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrFrame.Offset = context_record->Ebp;
373*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrStack.Offset = context_record->Esp;
374*6777b538SAndroid Build Coastguard Worker #else
375*6777b538SAndroid Build Coastguard Worker #error Unsupported Windows Arch
376*6777b538SAndroid Build Coastguard Worker #endif
377*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrPC.Mode = AddrModeFlat;
378*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrFrame.Mode = AddrModeFlat;
379*6777b538SAndroid Build Coastguard Worker   stack_frame.AddrStack.Mode = AddrModeFlat;
380*6777b538SAndroid Build Coastguard Worker   while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
381*6777b538SAndroid Build Coastguard Worker                      &stack_frame, &context_copy, NULL,
382*6777b538SAndroid Build Coastguard Worker                      &SymFunctionTableAccess64, &SymGetModuleBase64, NULL) &&
383*6777b538SAndroid Build Coastguard Worker          count_ < std::size(trace_)) {
384*6777b538SAndroid Build Coastguard Worker     trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
385*6777b538SAndroid Build Coastguard Worker   }
386*6777b538SAndroid Build Coastguard Worker 
387*6777b538SAndroid Build Coastguard Worker   for (size_t i = count_; i < std::size(trace_); ++i)
388*6777b538SAndroid Build Coastguard Worker     trace_[i] = NULL;
389*6777b538SAndroid Build Coastguard Worker }
390*6777b538SAndroid Build Coastguard Worker 
391*6777b538SAndroid Build Coastguard Worker // static
PrintMessageWithPrefix(cstring_view prefix_string,cstring_view message)392*6777b538SAndroid Build Coastguard Worker void StackTrace::PrintMessageWithPrefix(cstring_view prefix_string,
393*6777b538SAndroid Build Coastguard Worker                                         cstring_view message) {
394*6777b538SAndroid Build Coastguard Worker   std::cerr << prefix_string << message;
395*6777b538SAndroid Build Coastguard Worker }
396*6777b538SAndroid Build Coastguard Worker 
PrintWithPrefixImpl(cstring_view prefix_string) const397*6777b538SAndroid Build Coastguard Worker void StackTrace::PrintWithPrefixImpl(cstring_view prefix_string) const {
398*6777b538SAndroid Build Coastguard Worker   OutputToStreamWithPrefixImpl(&std::cerr, prefix_string);
399*6777b538SAndroid Build Coastguard Worker }
400*6777b538SAndroid Build Coastguard Worker 
OutputToStreamWithPrefixImpl(std::ostream * os,cstring_view prefix_string) const401*6777b538SAndroid Build Coastguard Worker void StackTrace::OutputToStreamWithPrefixImpl(
402*6777b538SAndroid Build Coastguard Worker     std::ostream* os,
403*6777b538SAndroid Build Coastguard Worker     cstring_view prefix_string) const {
404*6777b538SAndroid Build Coastguard Worker   SymbolContext* context = SymbolContext::GetInstance();
405*6777b538SAndroid Build Coastguard Worker   if (g_init_error != ERROR_SUCCESS) {
406*6777b538SAndroid Build Coastguard Worker     (*os) << "Error initializing symbols (" << g_init_error
407*6777b538SAndroid Build Coastguard Worker           << ").  Dumping unresolved backtrace:\n";
408*6777b538SAndroid Build Coastguard Worker     for (size_t i = 0; (i < count_) && os->good(); ++i) {
409*6777b538SAndroid Build Coastguard Worker       (*os) << prefix_string << "\t" << trace_[i] << "\n";
410*6777b538SAndroid Build Coastguard Worker     }
411*6777b538SAndroid Build Coastguard Worker   } else {
412*6777b538SAndroid Build Coastguard Worker     context->OutputTraceToStream(trace_, count_, os, prefix_string);
413*6777b538SAndroid Build Coastguard Worker   }
414*6777b538SAndroid Build Coastguard Worker }
415*6777b538SAndroid Build Coastguard Worker 
416*6777b538SAndroid Build Coastguard Worker }  // namespace debug
417*6777b538SAndroid Build Coastguard Worker }  // namespace base
418