| # Debug Info Module | |
| This module serves the purpose of generating debug symbols. We use LLVM's | |
| [source level debugging](https://llvm.org/docs/SourceLevelDebugging.html) | |
| features for generating the debug information. The general principle is | |
| this: | |
| Given the right metadata in the LLVM IR, the LLVM code generator is able to | |
| create DWARF debug symbols for the given code. The | |
| [metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured | |
| much like DWARF *debugging information entries* (DIE), representing type | |
| information such as datatype layout, function signatures, block layout, | |
| variable location and scope information, etc. It is the purpose of this | |
| module to generate correct metadata and insert it into the LLVM IR. | |
| As the exact format of metadata trees may change between different LLVM | |
| versions, we now use LLVM | |
| [DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) | |
| to create metadata where possible. This will hopefully ease the adaptation of | |
| this module to future LLVM versions. | |
| The public API of the module is a set of functions that will insert the | |
| correct metadata into the LLVM IR when called with the right parameters. | |
| The module is thus driven from an outside client with functions like | |
| `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`. | |
| Internally the module will try to reuse already created metadata by | |
| utilizing a cache. The way to get a shared metadata node when needed is | |
| thus to just call the corresponding function in this module: | |
| ```ignore (illustrative) | |
| let file_metadata = file_metadata(cx, file); | |
| ``` | |
| The function will take care of probing the cache for an existing node for | |
| that exact file path. | |
| All private state used by the module is stored within either the | |
| CodegenUnitDebugContext struct (owned by the CodegenCx) or the | |
| FunctionDebugContext (owned by the FunctionCx). | |
| This file consists of three conceptual sections: | |
| 1. The public interface of the module | |
| 2. Module-internal metadata creation functions | |
| 3. Minor utility functions | |
| ## Recursive Types | |
| Some kinds of types, such as structs and enums can be recursive. That means | |
| that the type definition of some type X refers to some other type which in | |
| turn (transitively) refers to X. This introduces cycles into the type | |
| referral graph. A naive algorithm doing an on-demand, depth-first traversal | |
| of this graph when describing types, can get trapped in an endless loop | |
| when it reaches such a cycle. | |
| For example, the following simple type for a singly-linked list... | |
| ``` | |
| struct List { | |
| value: i32, | |
| tail: Option<Box<List>>, | |
| } | |
| ``` | |
| will generate the following callstack with a naive DFS algorithm: | |
| ```ignore (illustrative) | |
| describe(t = List) | |
| describe(t = i32) | |
| describe(t = Option<Box<List>>) | |
| describe(t = Box<List>) | |
| describe(t = List) // at the beginning again... | |
| ... | |
| ``` | |
| To break cycles like these, we use "stubs". That is, when | |
| the algorithm encounters a possibly recursive type (any struct or enum), it | |
| immediately creates a type description node and inserts it into the cache | |
| *before* describing the members of the type. This type description is just | |
| a stub (as type members are not described and added to it yet) but it | |
| allows the algorithm to already refer to the type. After the stub is | |
| inserted into the cache, the algorithm continues as before. If it now | |
| encounters a recursive reference, it will hit the cache and does not try to | |
| describe the type anew. This behavior is encapsulated in the | |
| `type_map::build_type_with_children()` function. | |
| ## Source Locations and Line Information | |
| In addition to data type descriptions the debugging information must also | |
| allow mapping machine code locations back to source code locations in order | |
| to be useful. This functionality is also handled in this module. The | |
| following functions allow controlling source mappings: | |
| + `set_source_location()` | |
| + `clear_source_location()` | |
| + `start_emitting_source_locations()` | |
| `set_source_location()` allows setting the current source location. All IR | |
| instructions created after a call to this function will be linked to the | |
| given source location, until another location is specified with | |
| `set_source_location()` or the source location is cleared with | |
| `clear_source_location()`. In the latter case, subsequent IR instructions | |
| will not be linked to any source location. As you can see, this is a | |
| stateful API (mimicking the one in LLVM), so be careful with source | |
| locations set by previous calls. It's probably best to not rely on any | |
| specific state being present at a given point in code. | |
| One topic that deserves some extra attention is *function prologues*. At | |
| the beginning of a function's machine code there are typically a few | |
| instructions for loading argument values into allocas and checking if | |
| there's enough stack space for the function to execute. This *prologue* is | |
| not visible in the source code and LLVM puts a special PROLOGUE END marker | |
| into the line table at the first non-prologue instruction of the function. | |
| In order to find out where the prologue ends, LLVM looks for the first | |
| instruction in the function body that is linked to a source location. So, | |
| when generating prologue instructions we have to make sure that we don't | |
| emit source location information until the 'real' function body begins. For | |
| this reason, source location emission is disabled by default for any new | |
| function being codegened and is only activated after a call to the third | |
| function from the list above, `start_emitting_source_locations()`. This | |
| function should be called right before regularly starting to codegen the | |
| top-level block of the given function. | |
| There is one exception to the above rule: `llvm.dbg.declare` instruction | |
| must be linked to the source location of the variable being declared. For | |
| function parameters these `llvm.dbg.declare` instructions typically occur | |
| in the middle of the prologue, however, they are ignored by LLVM's prologue | |
| detection. The `create_argument_metadata()` and related functions take care | |
| of linking the `llvm.dbg.declare` instructions to the correct source | |
| locations even while source location emission is still disabled, so there | |
| is no need to do anything special with source location handling here. |