Skip to main content

rucc_debug/
lib.rs

1//! DWARF 5 generation.
2//!
3//! Design: `spec/11-asm-objects-debug.md`. Layer rank 10, see `spec/18-package-layout.md`.
4//!
5//! # Status
6//!
7//! The line table, the types, the functions, the variables a unit defines at file scope and the
8//! locals that have a frame slot. [`write()`] takes one unit's worth of addresses, the places in
9//! the source they came from, the types the unit names, what each of its functions takes and gives
10//! back, what each of its file-scope variables is and where in its frame each of its placed locals
11//! sits, and gives back the sections that say so. That is enough for `addr2line` to answer a
12//! program counter with a file and a line, enough for a debugger to produce a backtrace with
13//! argument types in it, enough for one to print a global, and enough for one to print a local that
14//! is in memory. It is not enough for a local held in an SSA value, because one of those has to be
15//! said where it is at the program counter that is asking, which is a list of places rather than
16//! one. The shape of that list is here and nothing fills it in yet: a local can be said to be in a
17//! register over one stretch of a function's addresses and somewhere else over the next, and a
18//! `.debug_loclists` saying so comes out, but what the driver hands over is still one place for the
19//! whole of a function. Working out the stretches needs the register allocator's output and is the
20//! rest of M8 and of tamnd/rucc#9.
21//!
22//! The reason that part came first is tamnd/rucc#1558. A report from the safety monitor carries a
23//! program counter and deliberately carries no source location, because
24//! `spec/safe-memory/06-instrumentation.md` section 6.5 would rather have one line table than two
25//! that can disagree, and that only works once there is one. Until there was, every report out of a
26//! corpus run had to be read backwards out of a disassembly.
27//!
28//! Every crate in the workspace is published, and publishing implies a promise. This one is
29//! tier 3: its Rust API is explicitly unstable and will change without a major version bump.
30//! Depend on the `rucc` binary's behaviour, not on this.
31//!
32//! # Two things still waiting
33//!
34//! `Options::prefix_map` in `rucc-session` holds a `debug` list, which is what
35//! `-fdebug-prefix-map=` and `-ffile-prefix-map=` put there. Every path that reaches [`Unit`] has
36//! already been through `PrefixMap::apply`, because that is the whole reason a distribution passes
37//! those flags and because a build is only reproducible if all of the paths in it are rewritten
38//! rather than most. The rewriting is the driver's rather than this crate's for one reason: the
39//! driver is where a path is still a path, and by the time one arrives here it is a string in a
40//! table that nothing is allowed to reinterpret.
41//!
42//! `Options::compress` is the other, and it is what `-gz` put there. Every debug section this
43//! crate hands to the object writer has to be compressed the way that field says, which for
44//! `Compress::ZlibGnu` also means the section is named `.zdebug_info` rather than `.debug_info`
45//! and carries a `ZLIB` tag and a length instead of an `Elf64_Chdr`. Compressing the sections is
46//! worth more than anything else a distribution shipping debug symbols passes, so a build that
47//! asked for it and got a file twice the size it expected has a real complaint. Nothing reads it
48//! yet, and on a line table alone the saving is smaller than it will be.
49
50#![doc(html_root_url = "https://docs.rs/rucc-debug/0.10.75")]
51
52mod line;
53mod shape;
54mod tree;
55
56pub use crate::line::{Error, Function, Row, Unit, write};
57pub use crate::shape::{
58    Bits, Constant, Encoding, Global, Held, Local, Member, Param, Place, Qualifier, Shape, Sig,
59    Span, Spot,
60};
61
62/// The milestone in `spec/17-milestones.md` that fills this crate in.
63pub const MILESTONE: &str = "M8";
64
65#[cfg(test)]
66mod tests {
67    #[test]
68    fn milestone_is_recorded() {
69        assert!(super::MILESTONE.starts_with('M'));
70    }
71}