/ docs / stack_walking.md
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.