Skip to main content

rucc_debug/
shape.rs

1//! What the program means: the types a unit describes and the functions it defines.
2//!
3//! Design: `spec/11-asm-objects-debug.md` section 11.4.
4//!
5//! The line table answers where an address came from. This answers what the thing at that address
6//! is: which function a program counter is inside, what that function takes and gives back, and
7//! what the types in its signature are made of. A backtrace needs the first, and printing anything
8//! at all needs the rest.
9//!
10//! # A table of shapes rather than the compiler's own types
11//!
12//! Nothing here is a C type. A [`Shape`] is a DWARF entry with its attributes already decided, so
13//! the questions C answers and DWARF does not, which is most of them, are settled before anything
14//! reaches this crate. Whoever builds the table decides what `long` is on this target, which of two
15//! spellings of one width to write, whether a record is complete and where a bit-field's bits sit.
16//! What is left here is writing entries down, which is the part that has to be right about DWARF
17//! and has no opinion about C.
18//!
19//! It costs one thing, which is that a table can say something C cannot mean, and the answer to
20//! that is the same as for the machine IR: the writer is not a checker and the thing that would
21//! catch it is a reader. `readelf --debug-dump=info` is that reader and is what the differential
22//! runs.
23//!
24//! Every reference between entries is an index into the unit's [`types`] table, because a table of
25//! indices can be built in one pass over a recursive type without the borrow checker having
26//! anything to say about it, and because a cycle is ordinary rather than special: `struct node {
27//! struct node *next; }` is a pointer whose target is the record that holds it, and an index says
28//! that with nothing added.
29//!
30//! # What is described and what is skipped
31//!
32//! An [`Option<usize>`] target is DWARF's own convention, where the absence of a `DW_AT_type` means
33//! `void`. A type this compiler cannot yet describe is not that: a function that mentions one gets
34//! no [`Sig`], and a function with no `Sig` gets no `DW_TAG_subprogram` at all, so a debugger falls
35//! back to the symbol table for it the way it does for every function today. The alternative is an
36//! entry that says `void` or `void *` where the program said something else, and a debugger showing
37//! a wrong type is worse than one showing none.
38//!
39//! [`types`]: crate::Unit::types
40
41/// How the bits of a base type are read, which is DWARF's `DW_AT_encoding`.
42///
43/// The set C needs and no more. An enumeration rather than the `DW_ATE_` constants themselves so
44/// that whoever builds a table does not have to depend on `gimli` to name one.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum Encoding {
47    /// `bool`, whose one byte holds zero or one.
48    Boolean,
49    /// A signed integer in two's complement.
50    Signed,
51    /// An unsigned integer.
52    Unsigned,
53    /// `char` where it is signed, which DWARF keeps apart from a signed integer because a debugger
54    /// prints one as a character and the other as a number.
55    SignedChar,
56    /// `char` where it is unsigned, and `unsigned char`.
57    UnsignedChar,
58    /// One of the real floating types.
59    Float,
60    /// `_Complex T`, whose bytes are the real half and then the imaginary one.
61    Complex,
62}
63
64/// A qualifier, which DWARF writes as an entry wrapping the type it qualifies.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum Qualifier {
67    /// `const`.
68    Const,
69    /// `volatile`.
70    Volatile,
71    /// `restrict`.
72    Restrict,
73    /// `_Atomic`, which C calls a type rather than a qualifier and DWARF writes like one.
74    Atomic,
75}
76
77/// Which bits of a record a bit-field member is.
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub struct Bits {
80    /// How far into the record the first bit is, in bits from the start of it.
81    ///
82    /// Bits from the start of the whole record and not from the start of some storage unit, which
83    /// is what `DW_AT_data_bit_offset` means and is the one of DWARF's two spellings that does not
84    /// depend on the reader working out which unit was meant or which way round the target is.
85    pub at: u64,
86    /// How many bits it is, which is the width the program wrote.
87    pub width: u64,
88}
89
90/// One member of a record.
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct Member {
93    /// Its name, absent for an anonymous `struct` or `union` member and for an unnamed bit-field.
94    pub name: Option<String>,
95    /// Which of the unit's [`types`](crate::Unit::types) it is.
96    pub ty: usize,
97    /// How far into the record it starts, in bytes. Meaningless for a bit-field, which says where
98    /// it is in [`Member::bits`] instead.
99    pub at: u64,
100    /// Which bits it is, for a bit-field, and [`None`] for an ordinary member.
101    pub bits: Option<Bits>,
102}
103
104/// One type, in the terms DWARF describes one.
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub enum Shape {
107    /// A type whose bytes are read directly, which is every arithmetic type C has.
108    Base {
109        /// What it is called, which is the spelling the program would have written.
110        name: String,
111        /// How its bits are read.
112        encoding: Encoding,
113        /// How many bytes it is.
114        size: u64,
115    },
116    /// A pointer, whose target is [`None`] for `void *`.
117    Pointer {
118        /// Which of the unit's [`types`](crate::Unit::types) it points at.
119        to: Option<usize>,
120        /// How many bytes the pointer itself is.
121        size: u64,
122    },
123    /// An array, whose length is [`None`] when it has none a number can say.
124    ///
125    /// That covers three C spellings at once: the flexible array member, the array of unknown
126    /// length, and the array whose length is an expression. DWARF can describe the last of those
127    /// with an expression of its own, which is worth doing and is not done here, and leaving the
128    /// bound out is the answer a debugger already has to handle for the other two.
129    Array {
130        /// Which of the unit's [`types`](crate::Unit::types) the elements are.
131        of: usize,
132        /// How many of them there are.
133        count: Option<u64>,
134    },
135    /// A `struct` or a `union`, whose members are [`None`] when it is incomplete.
136    Record {
137        /// Whether it is a `union` rather than a `struct`.
138        union: bool,
139        /// Its tag, absent for one the program left anonymous.
140        name: Option<String>,
141        /// How many bytes it is, and nothing for an incomplete one.
142        size: Option<u64>,
143        /// The members in the order they were written, and [`None`] for an incomplete record,
144        /// which is a different thing from a complete record with no members.
145        members: Option<Vec<Member>>,
146    },
147    /// An `enum`.
148    Enumeration {
149        /// Its tag, absent for one the program left anonymous.
150        name: Option<String>,
151        /// Which of the unit's [`types`](crate::Unit::types) the enumerators are held in.
152        of: usize,
153        /// How many bytes it is.
154        size: u64,
155        /// The enumerators in the order the program wrote them.
156        ///
157        /// Empty for an enumeration that has not been completed, which is a thing a C program can
158        /// mention but cannot have an object of.
159        values: Vec<Constant>,
160    },
161    /// A `typedef` name for another type.
162    Alias {
163        /// The name.
164        name: String,
165        /// Which of the unit's [`types`](crate::Unit::types) it stands for, and [`None`] for a
166        /// name for `void`.
167        of: Option<usize>,
168    },
169    /// A qualified version of another type.
170    Qualified {
171        /// Which qualifier.
172        which: Qualifier,
173        /// Which of the unit's [`types`](crate::Unit::types) it qualifies, and [`None`] for
174        /// qualified `void`.
175        of: Option<usize>,
176    },
177    /// A function type, which is what a pointer to a function points at.
178    Subroutine(Sig),
179}
180
181/// One enumerator of an enumeration.
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct Constant {
184    /// The name the program wrote, which is what a debugger prints in place of the number.
185    pub name: String,
186    /// Its value.
187    ///
188    /// Wider than any enumeration a target has, so that the writer decides which DWARF form the
189    /// number goes in rather than the caller having to know. A value wider than 64 bits has no
190    /// form that holds it and is left out, the same way a record drops a member it cannot
191    /// describe and keeps the rest.
192    pub value: i128,
193}
194
195/// What a function takes and gives back.
196#[derive(Debug, Clone, Default, PartialEq, Eq)]
197pub struct Sig {
198    /// Which of the unit's [`types`](crate::Unit::types) it returns, and [`None`] for `void`.
199    pub returns: Option<usize>,
200    /// The parameters in order.
201    pub params: Vec<Param>,
202    /// Whether it ends in `...`.
203    pub variadic: bool,
204    /// Whether the program wrote a parameter list rather than leaving it empty.
205    ///
206    /// `DW_AT_prototyped`, and it is not the same question as whether the list is empty: `int f()`
207    /// says nothing about what `f` takes and `int f(void)` says it takes nothing, and a debugger
208    /// that could not tell them apart would offer to call the first with no arguments.
209    pub prototyped: bool,
210}
211
212/// One parameter of a function.
213#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct Param {
215    /// Its name, absent in a prototype that gave none and in a function type.
216    pub name: Option<String>,
217    /// Which of the unit's [`types`](crate::Unit::types) it is.
218    pub ty: usize,
219    /// Where the parameter is, and [`None`] where this compiler cannot yet say and for every
220    /// function type.
221    ///
222    /// A parameter is a local that happened to arrive in a register, so where it ends up is decided
223    /// the same way every other local's place is. See [`Local::spot`]. A function type never has
224    /// one, since a type is not a piece of code and has no frame or registers to be in.
225    pub spot: Option<Spot>,
226}
227
228/// One variable the unit defines at file scope.
229///
230/// Not the same problem as a local, and that is the whole reason this is here and a local is not.
231/// A file-scope variable is at one address for the whole of the program, so its location is the
232/// address of its own symbol and the linker fills it in, the same way it fills in a function's. A
233/// local's location is wherever the code happens to be keeping it at the program counter the
234/// debugger stopped at, which is a list rather than an expression, and that is the rest of
235/// tamnd/rucc#9.
236#[derive(Debug, Clone, Default, PartialEq, Eq)]
237pub struct Global {
238    /// Its name, as the C program spelled it, which is what the relocation asks the linker for.
239    pub name: String,
240    /// Which of the unit's [`types`](crate::Unit::types) it is, and [`None`] when this compiler
241    /// cannot yet say.
242    ///
243    /// A variable with nothing here still gets an entry, which is the one place the rule for a
244    /// function is turned around. A `DW_TAG_variable` with no `DW_AT_type` does not say `void`,
245    /// because nothing in C is a variable of type `void`, so a reader takes it as a variable whose
246    /// type was not recorded. The name and the address are worth having on their own: they are
247    /// what lets a debugger resolve the name at all, and a program that knows what it is looking
248    /// at can cast.
249    pub ty: Option<usize>,
250    /// Where it was declared, and nothing when that is not known.
251    pub decl: Option<Place>,
252    /// Whether anything outside this unit can see it, which is the opposite of `static`.
253    pub external: bool,
254}
255
256/// One local the program declared.
257///
258/// A parameter is not here even when it has a place. It is already a child of the subprogram, from
259/// the signature, and a second entry for it would be a second variable of the same name. What it
260/// gets instead is [`Param::spot`].
261#[derive(Debug, Clone, PartialEq, Eq)]
262pub struct Local {
263    /// Its name, as the C program spelled it.
264    pub name: String,
265    /// Which of the unit's [`types`](crate::Unit::types) it is, and [`None`] when this compiler
266    /// cannot yet say, which is the case [`Global::ty`] explains.
267    pub ty: Option<usize>,
268    /// Where it was declared, and nothing when that is not known.
269    pub decl: Option<Place>,
270    /// Where in the machine it is, over the addresses of the function it is in.
271    pub spot: Spot,
272}
273
274/// Where a local is over the addresses of the function it is in.
275///
276/// Which of the two a local gets is decided by what lowering did with it rather than by the
277/// optimization level. A local with a frame slot is in that slot from the first instruction of the
278/// function to the last, because the frame layout hands the slot out once and nothing moves it
279/// afterwards, and one expression says so. A scalar whose address is never taken is put in an SSA
280/// value instead, at every optimization level including `-O0`, and where the register allocator put
281/// that value changes from one program counter to the next.
282#[derive(Debug, Clone, PartialEq, Eq)]
283pub enum Spot {
284    /// In one place at every address in the function.
285    Always(Held),
286    /// In a place that depends on where the program counter is, said stretch by stretch.
287    ///
288    /// The stretches do not have to cover the function, and an address none of them covers is an
289    /// address the local is nowhere. That is the honest answer rather than a gap: a value that has
290    /// not been computed yet, or whose last reader is already behind, is somewhere for part of a
291    /// function and nowhere for the rest, and a debugger stopped in the rest should say the
292    /// variable is not available rather than print whatever is in the register now.
293    Over(Vec<Span>),
294}
295
296/// One stretch of a function's addresses and where a local is over it.
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub struct Span {
299    /// How far into the function the stretch starts, in bytes.
300    pub from: u64,
301    /// How long it is, in bytes. A stretch of no length covers nothing and is refused.
302    pub len: u64,
303    /// Where the local is over it.
304    pub held: Held,
305}
306
307/// A place in the machine something can be.
308#[derive(Debug, Clone, Copy, PartialEq, Eq)]
309pub enum Held {
310    /// This far from the function's frame base, which is a negative number for anything in the
311    /// frame, since the frame base is the stack pointer the caller had and a frame is below that.
312    Frame(i64),
313    /// In this register, by the number this target's DWARF register numbering gives it.
314    ///
315    /// Not the register number the back end uses. The two agree on some targets and not on others,
316    /// and the translation is the caller's, because the caller is what knows which target this is.
317    Reg(u16),
318}
319
320/// Where in the source something was declared.
321#[derive(Debug, Clone, Copy, PartialEq, Eq)]
322pub struct Place {
323    /// Which of the unit's [`files`](crate::Unit::files) it is in.
324    pub file: usize,
325    /// Which line of that file, counting from one.
326    pub line: u32,
327}