Flutter Engine
The Flutter Engine
|
The Dart VM AOT compiler can encode code source mapping information as DWARF debugging information instead of using in-snapshot CodeSourceMap
objects. Unlike CodeSourceMap
objects, this DWARF information can then be stripped from snapshots provided to users, which lowers the binary size.
To output code source mapping information as DWARF debugging information, use the --dwarf-stack-traces
flag. By default, generated assembly or ELF snapshots include the DWARF information directly.
Note: DWARF debugging information is not obfuscated when using the
--obfuscate
flag. To avoid unobfuscated information leaking to users when using--dwarf-stack-traces
, use the--strip
option when creating ELF snapshots.
To output DWARF debugging information to a separate file that can be saved as an artifact for later debugging, use the --save-debugging-info=<...>
flag. The generated file is not guaranteed to be any specific format and may change in the future. See Translating DWARF stack traces for how to use this file.
When using DWARF code source mapping information, stack traces only include PC address information for frames. This means that a developer will need the generated DWARF information to get function, file, and line number information for each frame.
Take the following example program, saved as throws.dart
in the root of a Dart SDK checkout:
Below is the result of running the file both without and with --dwarf-stack-traces
in a 64-bit Linux development environment:
For a DWARF-based stack trace, we are guaranteed to have an absolute PC address for each frame (the hexadecimal number following abs
) as well as the absolute addresses for the start of the isolate instructions and the VM instructions (the line starting with isolate_instructions
). This information is used by our tool and libraries for converting DWARF stack traces, described later.
If we are running from a snapshot which is a native format for dynamic libraries (e.g., ELF on Linux or Mach-O on Mac OS X), then we will also have a virtual PC address for each frame (the hexadecimal number following virt
). If we have appropriate DWARF information for the snapshot (e.g., part of the unstripped ELF snapshot on Linux, or a separately generated .DSYM package when compiling the generated assembly on Mac OS X), we can use the virtual address along with the DWARF information to get back function, file, and line number information using native tools:
However, as seen here, the information may not be exactly as expected from the non-DWARF stack trace. In addition, the DWARF stack trace may include frames that are internal to the Dart VM and would not normally be provided in non-DWARF stack traces. Note that there are seven frames in the DWARF stack trace above, but only 5 in the non-DWARF stack trace. Frame #02
happens to correspond to one of these elided frames:
To ease translation of DWARF stack traces, we provide a platform-independent tool and libraries. They can translate DWARF stack traces using the DWARF debugging information contained in unstripped ELF snapshots or saved separately using --save-debugging-info=<...>
. For most uses, the tool should suffice, but the libraries it uses are also available for integration into Dart-based workflows.
A simple way to translate DWARF stack traces is to use the tool decode
from the package native_stack_traces. The tool has one required argument -e
, which takes the name of the file containing DWARF debugging information as an input. This can either be an unstripped ELF snapshot or a file generated by --save-debugging-info=<...>
.
Using the earlier example, we can run the snapshot and convert any generated stack traces as follows:
Note: As seen here, only lines that contain stack trace frames are converted. In particular, we do not strip the extra stack trace header lines that are only part of DWARF-based stack traces.
This section describes two different libraries used to retrieve and convert information associated with DWARF-based stack traces:
package:vm/dwarf/dwarf.dart
, for 'Dwarf' and 'CallInfo' objectspackage:vm/dwarf/convert.dart
, for PCOffset
objects and various operations on stack tracesA Dwarf
object represents the DWARF debugging information from either unstripped ELF snapshots or a file generated by --save-debugging-info=<...>
.
The Dwarf.fromFile
factory takes a filename and returns a 'Dwarf' object, if the given file exists and is a recognized format that contains DWARF information.
A CallInfo
object represents a call site in the code corresponding to a particular virtual address and contains the function name, file name, and line number for the call site and whether the code for the call site has been inlined at this use.
To look up the call information associated with a particular virtual address, use Dwarf::callInfo
. If the virtual address is outside the range of those generated by the DWARF line number program(s), then it returns null
, otherwise it returns an iterable of CallInfo
objects. If the optional includeInternalFrames
argument is false (the default), then the iterable can be empty if the virtual address points to code that does not correspond to user or library code, like generated function prologues.
To convert a stream of lines that may include DWARF stack traces, use the stack transformer DwarfStackTraceDecoder
. Its constructor takes a Dwarf
object, and the transformer, like decode.dart
from the package native_stack_traces, only changes lines that correspond to stack trace frames.
Note: The stack transformer assumes that lines are not combined or broken across
String
s in the input stream. If this is not already guaranteed, transform the stream withLineSplitter
fromdart:convert
prior to transforming it with aDwarfStackTraceDecoder
.
A PCOffset
object represents the PC address information extracted from a DWARF-based stack trace frame. It contains whether the PC address comes from the VM or isolate instructions section, and the offset of the PC address in that section.
The PCOffset::virtualAddress
method takes a Dwarf
object and returns a compatible virtual address for use with methods on that Dwarf
object.
The function collectPCOffsets
extracts PCOffset
s for the frames of a stack trace.
Note: Since the absolute addresses of the VM and isolate instruction sections are part of the stack frame header,
collectPCOffsets
can only extract information from complete stack traces.