| # Introduction |
| |
| This page aims to provide a detailed description of how Breakpad produces stack |
| traces from the information contained within a minidump file. |
| |
| # Details |
| |
| ## Starting the Process |
| |
| Typically the stack walking process is initiated by instantiating the |
| [MinidumpProcessor](../src/processor/minidump_processor.cc) |
| class and calling the [MinidumpProcessor::Process](../src/processor/minidump_processor.cc#61) |
| method, providing it a minidump file to process. To produce a useful stack |
| trace, the MinidumpProcessor requires two other objects which are passed in its |
| constructor: a [SymbolSupplier](../src/google_breakpad/processor/symbol_supplier.h) |
| and a [SourceLineResolverInterface](../src/google_breakpad/processor/source_line_resolver_interface.h). |
| The SymbolSupplier object is responsible for locating and providing SymbolFiles |
| that match modules from the minidump. The SourceLineResolverInterface is |
| responsible for loading the symbol files and using the information contained |
| within to provide function and source information for stack frames, as well as |
| information on how to unwind from a stack frame to its caller. More detail will |
| be provided on these interactions later. |
| |
| A number of data streams are extracted from the minidump to begin stack walking: |
| the list of threads from the process |
| ([MinidumpThreadList](../src/google_breakpad/processor/minidump.h#335)), |
| the list of modules loaded in the process |
| ([MinidumpModuleList](../src/google_breakpad/processor/minidump.h#501)), |
| and information about the exception that caused the process to crash |
| ([MinidumpException](../src/google_breakpad/processor/minidump.h#615)). |
| |
| ## Enumerating Threads |
| |
| For each thread in the thread list |
| ([MinidumpThread](../src/google_breakpad/processor/minidump.h#299)), |
| the thread memory containing the stack for the thread |
| ([MinidumpMemoryRegion](../src/google_breakpad/processor/minidump.h#236)) |
| and the CPU context representing the CPU state of the thread at the time the |
| dump was written ([MinidumpContext](../src/google_breakpad/processor/minidump.h#171)) |
| are extracted from the minidump. If the thread being processed is the thread |
| that produced the exception then a CPU context is obtained from the |
| MinidumpException object instead, which represents the CPU state of the thread |
| at the point of the exception. A stack walker is then instantiated by calling |
| the [Stackwalker::StackwalkerForCPU](../src/google_breakpad/processor/stackwalker.h#77) |
| method and passing it the CPU context, the thread memory, the module list, as |
| well as the SymbolSupplier and SourceLineResolverInterface. This method selects |
| the specific !Stackwalker subclass based on the CPU architecture of the provided |
| CPU context and returns an instance of that subclass. |
| |
| ## Walking a thread's stack |
| |
| Once a !Stackwalker instance has been obtained, the processor calls the |
| [Stackwalker::Walk](../src/google_breakpad/processor/source_line_resolver_interface.h) |
| method to obtain a list of frames representing the stack of this thread. The |
| !Stackwalker starts by calling the GetContextFrame method which returns a |
| StackFrame representing the top of the stack, with CPU state provided by the |
| initial CPU context. From there, the stack walker repeats the following steps |
| for each frame in turn: |
| |
| ### Finding the Module |
| |
| The address of the instruction pointer of the current frame is used to determine |
| which module contains the current frame by calling the module list's |
| [GetModuleForAddress](../src/google_breakpad/processor/code_modules.h#56) method. |
| |
| ### Locating Symbols |
| |
| If a module is located, the SymbolSupplier is asked to locate symbols |
| corresponding to the module by calling its |
| [GetCStringSymbolData](../src/google_breakpad/processor/symbol_supplier.h#87) |
| method. Typically this is implemented by using the module's debug filename (the |
| PDB filename for Windows dumps) and debug identifier (a GUID plus one extra |
| digit) as a lookup key. The [SimpleSymbolSupplier](../src/processor/simple_symbol_supplier.cc) |
| class simply uses these as parts of a file path to locate a flat file on disk. |
| |
| ### Loading Symbols |
| |
| If a symbol file is located, the SourceLineResolverInterface is then asked to |
| load the symbol file by calling its |
| [LoadModuleUsingMemoryBuffer](../src/google_breakpad/processor/source_line_resolver_interface.h#71) |
| method. The [BasicSourceLineResolver](../src/processor/basic_source_line_resolver.cc) |
| implementation parses the text-format [symbol file](symbol_files.md) into |
| in-memory data structures to make lookups by address of function names, source |
| line information, and unwind information easy. |
| |
| ### Getting source line information |
| |
| If a symbol file has been successfully loaded, the SourceLineResolverInterface's |
| [FillSourceLineInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#89) |
| method is called to provide a function name and source line information for the |
| current frame. This is done by subtracting the base address of the module |
| containing the current frame from the instruction pointer of the current frame |
| to obtain a relative virtual address (RVA), which is a code offset relative to |
| the start of the module. This RVA is then used as a lookup into a table of |
| functions ([FUNC lines](SymbolFiles#FUNC_records.md) from the symbol file), each |
| of which has an associated address range (function start address, function |
| size). If a function is found whose address range contains the RVA, then its |
| name is used. The RVA is then used as a lookup into a table of source lines |
| ([line records](SymbolFiles#Line_records.md) from the symbol file), each of |
| which also has an associated address range. If a match is found it will provide |
| the file name and source line associated with the current frame. If no match was |
| found in the function table, another table of publicly exported symbols may be |
| consulted ([PUBLIC lines](SymbolFiles#PUBLIC_records.md) from the symbol file). |
| Public symbols contain only a start address, so the lookup simply looks for the |
| nearest symbol that is less than the provided RVA. |
| |
| ### Finding the caller frame |
| |
| To find the next frame in the stack, the !Stackwalker calls its |
| [GetCallerFrame](../src/google_breakpad/processor/stackwalker.h#186) |
| method, passing in the current frame. Each !Stackwalker subclass implements |
| GetCallerFrame differently, but there are common patterns. |
| |
| Typically the first step is to query the SourceLineResolverInterface for the |
| presence of detailed unwind information. This is done using its |
| [FindWindowsFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#96) |
| and [FindCFIFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#102) |
| methods. These methods look for Windows unwind info extracted from a PDB file |
| ([STACK WIN](SymbolFiles#STACK_WIN_records.md) lines from the symbol file), or |
| DWARF CFI extracted from a binary ([STACK CFI](SymbolFiles#STACK_CFI_records.md) |
| lines from the symbol file) respectively. The information covers address ranges, |
| so the RVA of the current frame is used for lookup as with function and source |
| line information. |
| |
| If unwind info is found it provides a set of rules to recover the register state |
| of the caller frame given the current register state as well as the thread's |
| stack memory. The rules are evaluated to produce the caller frame. |
| |
| If unwind info is not found then the !Stackwalker may resort to other methods. |
| Typically on architectures which specify a frame pointer unwinding by |
| dereferencing the frame pointer is tried next. If that is successful it is used |
| to produce the caller frame. |
| |
| If no caller frame was found by any other method most !Stackwalker |
| implementations resort to stack scanning by looking at each word on the stack |
| down to a fixed depth (implemented in the |
| [Stackwalker::ScanForReturnAddress](../src/google_breakpad/processor/stackwalker.h#131) |
| method) and using a heuristic to attempt to find a reasonable return address |
| (implemented in the |
| [Stackwalker::InstructionAddressSeemsValid](../src/google_breakpad/processor/stackwalker.h#111) method). |
| |
| If no caller frame is found or the caller frame seems invalid, stack walking |
| stops. If a caller frame was found then these steps repeat using the new frame |
| as the current frame. |