Expand description
DWARF 5 generation.
Design: spec/11-asm-objects-debug.md. Layer rank 10, see spec/18-package-layout.md.
§Status
The line table, the types, the functions, the variables a unit defines at file scope, the locals
of those functions wherever they are kept, and the scopes the locals were declared in.
write() takes one unit’s worth of addresses, the places in the source they came from, the
types the unit names, what each of its functions takes and gives back, what each of its
file-scope variables is and where each of its locals is at each address, and gives back the
sections that say so. That is enough for addr2line to answer a program counter with a file and
a line, enough for a debugger to produce a backtrace with argument types in it, enough for one to
print a global, and enough for one to print a local whether it is in the frame or in a register.
A local in the frame is one DW_OP_fbreg for the whole of its function. A local the register
allocator placed is a list instead, since one of those has to be said where it is at the program
counter that is asking, and a .debug_loclists saying so comes out. Which of the two a local
gets is decided by what lowering did with it rather than by the optimization level.
What is still missing is marking a variable unavailable at a program counter where it is dead
rather than leaving the address uncovered, a .debug_frame for a build that writes no unwind
table, and the debugger differential that would say all of this is right against another
compiler on the same program. That is the rest of M8 and of tamnd/rucc#9.
The reason that part came first is tamnd/rucc#1558. A report from the safety monitor carries a
program counter and deliberately carries no source location, because
spec/safe-memory/06-instrumentation.md section 6.5 would rather have one line table than two
that can disagree, and that only works once there is one. Until there was, every report out of a
corpus run had to be read backwards out of a disassembly.
Every crate in the workspace is published, and publishing implies a promise. This one is
tier 3: its Rust API is explicitly unstable and will change without a major version bump.
Depend on the rucc binary’s behaviour, not on this.
§Two things still waiting
Options::prefix_map in rucc-session holds a debug list, which is what
-fdebug-prefix-map= and -ffile-prefix-map= put there. Every path that reaches Unit has
already been through PrefixMap::apply, because that is the whole reason a distribution passes
those flags and because a build is only reproducible if all of the paths in it are rewritten
rather than most. The rewriting is the driver’s rather than this crate’s for one reason: the
driver is where a path is still a path, and by the time one arrives here it is a string in a
table that nothing is allowed to reinterpret.
Options::compress is the other, and it is what -gz put there. Every debug section this
crate hands to the object writer has to be compressed the way that field says, which for
Compress::ZlibGnu also means the section is named .zdebug_info rather than .debug_info
and carries a ZLIB tag and a length instead of an Elf64_Chdr. Compressing the sections is
worth more than anything else a distribution shipping debug symbols passes, so a build that
asked for it and got a file twice the size it expected has a real complaint. Nothing reads it
yet, and on a line table alone the saving is smaller than it will be.
Structs§
- Bits
- Which bits of a record a bit-field member is.
- Constant
- One enumerator of an enumeration.
- Function
- One function: where each of its instructions came from, and what it is.
- Global
- One variable the unit defines at file scope.
- Local
- One local the program declared.
- Member
- One member of a record.
- Param
- One parameter of a function.
- Place
- Where in the source something was declared.
- Reach
- One stretch of a function’s addresses, with nothing said about what is at it.
- Row
- One row of the table: an address, and where the code at it came from.
- Scope
- One inner scope of a function, which is a
{ ... }the program declared something in. - Sig
- What a function takes and gives back.
- Span
- One stretch of a function’s addresses and where a local is over it.
- Unit
- One compilation unit’s worth of debug information.
Enums§
- Encoding
- How the bits of a base type are read, which is DWARF’s
DW_AT_encoding. - Error
- What went wrong while the sections were being built.
- Held
- A place in the machine something can be.
- Qualifier
- A qualifier, which DWARF writes as an entry wrapping the type it qualifies.
- Shape
- One type, in the terms DWARF describes one.
- Spot
- Where a local is over the addresses of the function it is in.
Constants§
- MILESTONE
- The milestone in
spec/17-milestones.mdthat fills this crate in.
Functions§
- write
- The sections a unit’s debug information goes in.