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