stack_walking.md
1 # Introduction 2 3 This page aims to provide a detailed description of how Breakpad produces stack 4 traces from the information contained within a minidump file. 5 6 # Details 7 8 ## Starting the Process 9 10 Typically the stack walking process is initiated by instantiating the 11 [MinidumpProcessor](../src/processor/minidump_processor.cc) 12 class and calling the [MinidumpProcessor::Process](../src/processor/minidump_processor.cc#61) 13 method, providing it a minidump file to process. To produce a useful stack 14 trace, the MinidumpProcessor requires two other objects which are passed in its 15 constructor: a [SymbolSupplier](../src/google_breakpad/processor/symbol_supplier.h) 16 and a [SourceLineResolverInterface](../src/google_breakpad/processor/source_line_resolver_interface.h). 17 The SymbolSupplier object is responsible for locating and providing SymbolFiles 18 that match modules from the minidump. The SourceLineResolverInterface is 19 responsible for loading the symbol files and using the information contained 20 within to provide function and source information for stack frames, as well as 21 information on how to unwind from a stack frame to its caller. More detail will 22 be provided on these interactions later. 23 24 A number of data streams are extracted from the minidump to begin stack walking: 25 the list of threads from the process 26 ([MinidumpThreadList](../src/google_breakpad/processor/minidump.h#335)), 27 the list of modules loaded in the process 28 ([MinidumpModuleList](../src/google_breakpad/processor/minidump.h#501)), 29 and information about the exception that caused the process to crash 30 ([MinidumpException](../src/google_breakpad/processor/minidump.h#615)). 31 32 ## Enumerating Threads 33 34 For each thread in the thread list 35 ([MinidumpThread](../src/google_breakpad/processor/minidump.h#299)), 36 the thread memory containing the stack for the thread 37 ([MinidumpMemoryRegion](../src/google_breakpad/processor/minidump.h#236)) 38 and the CPU context representing the CPU state of the thread at the time the 39 dump was written ([MinidumpContext](../src/google_breakpad/processor/minidump.h#171)) 40 are extracted from the minidump. If the thread being processed is the thread 41 that produced the exception then a CPU context is obtained from the 42 MinidumpException object instead, which represents the CPU state of the thread 43 at the point of the exception. A stack walker is then instantiated by calling 44 the [Stackwalker::StackwalkerForCPU](../src/google_breakpad/processor/stackwalker.h#77) 45 method and passing it the CPU context, the thread memory, the module list, as 46 well as the SymbolSupplier and SourceLineResolverInterface. This method selects 47 the specific !Stackwalker subclass based on the CPU architecture of the provided 48 CPU context and returns an instance of that subclass. 49 50 ## Walking a thread's stack 51 52 Once a !Stackwalker instance has been obtained, the processor calls the 53 [Stackwalker::Walk](../src/google_breakpad/processor/source_line_resolver_interface.h) 54 method to obtain a list of frames representing the stack of this thread. The 55 !Stackwalker starts by calling the GetContextFrame method which returns a 56 StackFrame representing the top of the stack, with CPU state provided by the 57 initial CPU context. From there, the stack walker repeats the following steps 58 for each frame in turn: 59 60 ### Finding the Module 61 62 The address of the instruction pointer of the current frame is used to determine 63 which module contains the current frame by calling the module list's 64 [GetModuleForAddress](../src/google_breakpad/processor/code_modules.h#56) method. 65 66 ### Locating Symbols 67 68 If a module is located, the SymbolSupplier is asked to locate symbols 69 corresponding to the module by calling its 70 [GetCStringSymbolData](../src/google_breakpad/processor/symbol_supplier.h#87) 71 method. Typically this is implemented by using the module's debug filename (the 72 PDB filename for Windows dumps) and debug identifier (a GUID plus one extra 73 digit) as a lookup key. The [SimpleSymbolSupplier](../src/processor/simple_symbol_supplier.cc) 74 class simply uses these as parts of a file path to locate a flat file on disk. 75 76 ### Loading Symbols 77 78 If a symbol file is located, the SourceLineResolverInterface is then asked to 79 load the symbol file by calling its 80 [LoadModuleUsingMemoryBuffer](../src/google_breakpad/processor/source_line_resolver_interface.h#71) 81 method. The [BasicSourceLineResolver](../src/processor/basic_source_line_resolver.cc) 82 implementation parses the text-format [symbol file](symbol_files.md) into 83 in-memory data structures to make lookups by address of function names, source 84 line information, and unwind information easy. 85 86 ### Getting source line information 87 88 If a symbol file has been successfully loaded, the SourceLineResolverInterface's 89 [FillSourceLineInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#89) 90 method is called to provide a function name and source line information for the 91 current frame. This is done by subtracting the base address of the module 92 containing the current frame from the instruction pointer of the current frame 93 to obtain a relative virtual address (RVA), which is a code offset relative to 94 the start of the module. This RVA is then used as a lookup into a table of 95 functions ([FUNC lines](SymbolFiles#FUNC_records.md) from the symbol file), each 96 of which has an associated address range (function start address, function 97 size). If a function is found whose address range contains the RVA, then its 98 name is used. The RVA is then used as a lookup into a table of source lines 99 ([line records](SymbolFiles#Line_records.md) from the symbol file), each of 100 which also has an associated address range. If a match is found it will provide 101 the file name and source line associated with the current frame. If no match was 102 found in the function table, another table of publicly exported symbols may be 103 consulted ([PUBLIC lines](SymbolFiles#PUBLIC_records.md) from the symbol file). 104 Public symbols contain only a start address, so the lookup simply looks for the 105 nearest symbol that is less than the provided RVA. 106 107 ### Finding the caller frame 108 109 To find the next frame in the stack, the !Stackwalker calls its 110 [GetCallerFrame](../src/google_breakpad/processor/stackwalker.h#186) 111 method, passing in the current frame. Each !Stackwalker subclass implements 112 GetCallerFrame differently, but there are common patterns. 113 114 Typically the first step is to query the SourceLineResolverInterface for the 115 presence of detailed unwind information. This is done using its 116 [FindWindowsFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#96) 117 and [FindCFIFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#102) 118 methods. These methods look for Windows unwind info extracted from a PDB file 119 ([STACK WIN](SymbolFiles#STACK_WIN_records.md) lines from the symbol file), or 120 DWARF CFI extracted from a binary ([STACK CFI](SymbolFiles#STACK_CFI_records.md) 121 lines from the symbol file) respectively. The information covers address ranges, 122 so the RVA of the current frame is used for lookup as with function and source 123 line information. 124 125 If unwind info is found it provides a set of rules to recover the register state 126 of the caller frame given the current register state as well as the thread's 127 stack memory. The rules are evaluated to produce the caller frame. 128 129 If unwind info is not found then the !Stackwalker may resort to other methods. 130 Typically on architectures which specify a frame pointer unwinding by 131 dereferencing the frame pointer is tried next. If that is successful it is used 132 to produce the caller frame. 133 134 If no caller frame was found by any other method most !Stackwalker 135 implementations resort to stack scanning by looking at each word on the stack 136 down to a fixed depth (implemented in the 137 [Stackwalker::ScanForReturnAddress](../src/google_breakpad/processor/stackwalker.h#131) 138 method) and using a heuristic to attempt to find a reasonable return address 139 (implemented in the 140 [Stackwalker::InstructionAddressSeemsValid](../src/google_breakpad/processor/stackwalker.h#111) method). 141 142 If no caller frame is found or the caller frame seems invalid, stack walking 143 stops. If a caller frame was found then these steps repeat using the new frame 144 as the current frame.