wasmtime_cranelift/debug/transform/
debug_transform_logging.rs

1use crate::{debug::Reader, translate::get_vmctx_value_label};
2use core::fmt;
3use cranelift_codegen::{ir::ValueLabel, isa::TargetIsa, LabelValueLoc, ValueLabelsRanges};
4use gimli::{
5    write, AttributeValue, DebuggingInformationEntry, Dwarf, LittleEndian, Unit, UnitOffset,
6    UnitSectionOffset,
7};
8
9macro_rules! dbi_log_enabled {
10    () => {
11        cfg!(any(feature = "trace-log", debug_assertions))
12            && ::log::log_enabled!(target: "debug-info-transform", ::log::Level::Trace)
13    };
14}
15macro_rules! dbi_log {
16    ($($tt:tt)*) => {
17        if cfg!(any(feature = "trace-log", debug_assertions)) {
18            ::log::trace!(target: "debug-info-transform", $($tt)*);
19        }
20    };
21}
22pub(crate) use dbi_log;
23pub(crate) use dbi_log_enabled;
24
25pub struct CompileUnitSummary<'a> {
26    unit: &'a Unit<Reader<'a>, usize>,
27}
28
29impl<'a> fmt::Debug for CompileUnitSummary<'a> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        let unit = self.unit;
32        let offs = get_offset_value(unit.header.offset());
33        write!(f, "0x{offs:08x} [")?;
34        let comp_dir = match unit.comp_dir {
35            Some(dir) => &dir.to_string_lossy(),
36            None => "None",
37        };
38        write!(f, "\"{comp_dir}\"")?;
39        let name = match unit.name {
40            Some(name) => &name.to_string_lossy(),
41            None => "None",
42        };
43        write!(f, ", \"{name}\"]")
44    }
45}
46
47pub fn log_get_cu_summary<'a>(unit: &'a Unit<Reader<'a>, usize>) -> CompileUnitSummary<'a> {
48    CompileUnitSummary { unit }
49}
50
51pub struct DieRefSummary<'a> {
52    unit: &'a Unit<Reader<'a>, usize>,
53    unit_ref: UnitOffset,
54}
55
56impl<'a> fmt::Debug for DieRefSummary<'a> {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        let section_offs = self.unit_ref.to_unit_section_offset(self.unit);
59        let offs = get_offset_value(section_offs);
60        write!(f, "0x{offs:08x}")
61    }
62}
63
64pub fn log_get_die_ref<'a>(
65    unit: &'a Unit<Reader<'a>, usize>,
66    unit_ref: UnitOffset,
67) -> DieRefSummary<'a> {
68    DieRefSummary { unit, unit_ref }
69}
70
71struct DieDetailedSummary<'a> {
72    dwarf: &'a Dwarf<Reader<'a>>,
73    unit: &'a Unit<Reader<'a>, usize>,
74    die: &'a DebuggingInformationEntry<'a, 'a, Reader<'a>>,
75}
76
77pub fn log_begin_input_die(
78    dwarf: &Dwarf<Reader<'_>>,
79    unit: &Unit<Reader<'_>, usize>,
80    die: &DebuggingInformationEntry<Reader<'_>>,
81    depth: isize,
82) {
83    dbi_log!(
84        "=== Begin DIE at {:?} (depth = {}):\n{:?}",
85        log_get_die_ref(unit, die.offset()),
86        depth,
87        DieDetailedSummary { dwarf, unit, die }
88    );
89}
90
91impl<'a> fmt::Debug for DieDetailedSummary<'a> {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        let die = self.die;
94        let unit = self.unit;
95        let dwarf = self.dwarf;
96        write!(f, "{}\n", die.tag())?;
97
98        let mut attrs = die.attrs();
99        while let Some(attr) = attrs.next().unwrap_or(None) {
100            write!(f, "  {} (", attr.name())?;
101            let attr_value = attr.value();
102            match attr_value {
103                AttributeValue::Addr(addr) => {
104                    write!(f, "{addr:08x}")
105                }
106                AttributeValue::DebugAddrIndex(index) => {
107                    if let Some(addr) = dwarf.address(unit, index).ok() {
108                        write!(f, "{addr:08x}")
109                    } else {
110                        write!(f, "<error reading address at index: {}>", index.0)
111                    }
112                }
113                AttributeValue::Block(d) => write!(f, "{d:?}"),
114                AttributeValue::Udata(d) => write!(f, "{d}"),
115                AttributeValue::Data1(d) => write!(f, "{d}"),
116                AttributeValue::Data2(d) => write!(f, "{d}"),
117                AttributeValue::Data4(d) => write!(f, "{d}"),
118                AttributeValue::Data8(d) => write!(f, "{d}"),
119                AttributeValue::Sdata(d) => write!(f, "{d}"),
120                AttributeValue::Flag(d) => write!(f, "{d}"),
121                AttributeValue::DebugLineRef(offset) => write!(f, "0x{:08x}", offset.0),
122                AttributeValue::FileIndex(index) => write!(f, "0x{index:08x}"),
123                AttributeValue::String(_)
124                | AttributeValue::DebugStrRef(_)
125                | AttributeValue::DebugStrOffsetsIndex(_) => {
126                    if let Ok(s) = dwarf.attr_string(unit, attr_value) {
127                        write!(f, "\"{}\"", &s.to_string_lossy())
128                    } else {
129                        write!(f, "<error reading string>")
130                    }
131                }
132                AttributeValue::RangeListsRef(_) | AttributeValue::DebugRngListsIndex(_) => {
133                    let _ = dwarf.attr_ranges_offset(unit, attr_value);
134                    write!(f, "<TODO: rnglist dump>")
135                }
136                AttributeValue::LocationListsRef(_) | AttributeValue::DebugLocListsIndex(_) => {
137                    let _ = dwarf.attr_locations_offset(unit, attr_value);
138                    write!(f, "<TODO: loclist dump>")
139                }
140                AttributeValue::Exprloc(_) => {
141                    write!(f, "<TODO: exprloc dump>")
142                }
143                AttributeValue::Encoding(value) => write!(f, "{value}"),
144                AttributeValue::DecimalSign(value) => write!(f, "{value}"),
145                AttributeValue::Endianity(value) => write!(f, "{value}"),
146                AttributeValue::Accessibility(value) => write!(f, "{value}"),
147                AttributeValue::Visibility(value) => write!(f, "{value}"),
148                AttributeValue::Virtuality(value) => write!(f, "{value}"),
149                AttributeValue::Language(value) => write!(f, "{value}"),
150                AttributeValue::AddressClass(value) => write!(f, "{value}"),
151                AttributeValue::IdentifierCase(value) => write!(f, "{value}"),
152                AttributeValue::CallingConvention(value) => write!(f, "{value}"),
153                AttributeValue::Inline(value) => write!(f, "{value}"),
154                AttributeValue::Ordering(value) => write!(f, "{value}"),
155                AttributeValue::UnitRef(offset) => {
156                    let section_offset = offset.to_unit_section_offset(unit);
157                    write!(f, "0x{:08x}", get_offset_value(section_offset))
158                }
159                AttributeValue::DebugInfoRef(offset) => write!(f, "0x{:08x}", offset.0),
160                unexpected_attr => write!(f, "<unexpected attr: {unexpected_attr:?}>"),
161            }?;
162            write!(f, ")\n")?;
163        }
164        Ok(())
165    }
166}
167
168struct OutDieDetailedSummary<'a> {
169    die_id: write::UnitEntryId,
170    unit: &'a write::Unit,
171    strings: &'a write::StringTable,
172}
173
174impl<'a> fmt::Debug for OutDieDetailedSummary<'a> {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        let die = self.unit.get(self.die_id);
177        write!(f, "{}\n", die.tag())?;
178        for attr in die.attrs() {
179            write!(f, "  {} (", attr.name())?;
180            let attr_value = attr.get();
181            match attr_value {
182                write::AttributeValue::Address(addr) => match addr {
183                    write::Address::Constant(addr_value) => write!(f, "{addr_value:08x}"),
184                    write::Address::Symbol { symbol, addend } => {
185                        write!(f, "symbol #{symbol}+{addend}")
186                    }
187                },
188                write::AttributeValue::Block(d) => {
189                    write!(f, "{:?}", Reader::new(d.as_slice(), LittleEndian))
190                }
191                write::AttributeValue::Udata(d) => write!(f, "{d}"),
192                write::AttributeValue::Data1(d) => write!(f, "{d}"),
193                write::AttributeValue::Data2(d) => write!(f, "{d}"),
194                write::AttributeValue::Data4(d) => write!(f, "{d}"),
195                write::AttributeValue::Data8(d) => write!(f, "{d}"),
196                write::AttributeValue::Sdata(d) => write!(f, "{d}"),
197                write::AttributeValue::Flag(d) => write!(f, "{d}"),
198                write::AttributeValue::LineProgramRef => write!(f, "LineProgramRef"),
199                write::AttributeValue::FileIndex(index) => match index {
200                    Some(id) => write!(f, "{id:?}"),
201                    None => write!(f, "<file index missing>"),
202                },
203                write::AttributeValue::String(s) => {
204                    write!(f, "\"{}\"", &String::from_utf8_lossy(s))
205                }
206                write::AttributeValue::StringRef(id) => {
207                    write!(f, "\"{}\"", &String::from_utf8_lossy(self.strings.get(*id)))
208                }
209                write::AttributeValue::RangeListRef(_) => {
210                    write!(f, "<TODO: out rnglist dump>")
211                }
212                write::AttributeValue::LocationListRef(_) => {
213                    write!(f, "<TODO: out loclist dump>")
214                }
215                write::AttributeValue::Exprloc(_) => {
216                    write!(f, "<TODO: out exprloc dump>")
217                }
218                write::AttributeValue::Encoding(value) => write!(f, "{value}"),
219                write::AttributeValue::DecimalSign(value) => write!(f, "{value}"),
220                write::AttributeValue::Endianity(value) => write!(f, "{value}"),
221                write::AttributeValue::Accessibility(value) => write!(f, "{value}"),
222                write::AttributeValue::Visibility(value) => write!(f, "{value}"),
223                write::AttributeValue::Virtuality(value) => write!(f, "{value}"),
224                write::AttributeValue::Language(value) => write!(f, "{value}"),
225                write::AttributeValue::AddressClass(value) => write!(f, "{value}"),
226                write::AttributeValue::IdentifierCase(value) => write!(f, "{value}"),
227                write::AttributeValue::CallingConvention(value) => write!(f, "{value}"),
228                write::AttributeValue::Inline(value) => write!(f, "{value}"),
229                write::AttributeValue::Ordering(value) => write!(f, "{value}"),
230                write::AttributeValue::UnitRef(unit_ref) => write!(f, "{unit_ref:?}>"),
231                write::AttributeValue::DebugInfoRef(reference) => match reference {
232                    write::Reference::Symbol(index) => write!(f, "symbol #{index}>"),
233                    write::Reference::Entry(unit_id, die_id) => {
234                        write!(f, "{die_id:?} in {unit_id:?}>")
235                    }
236                },
237                unexpected_attr => write!(f, "<unexpected attr: {unexpected_attr:?}>"),
238            }?;
239            write!(f, ")\n")?;
240        }
241        Ok(())
242    }
243}
244
245pub fn log_end_output_die(
246    input_die: &DebuggingInformationEntry<Reader<'_>>,
247    input_unit: &Unit<Reader<'_>, usize>,
248    die_id: write::UnitEntryId,
249    unit: &write::Unit,
250    strings: &write::StringTable,
251    depth: isize,
252) {
253    dbi_log!(
254        "=== End DIE at {:?} (depth = {}):\n{:?}",
255        log_get_die_ref(input_unit, input_die.offset()),
256        depth,
257        OutDieDetailedSummary {
258            die_id,
259            unit,
260            strings
261        }
262    );
263}
264
265pub fn log_end_output_die_skipped(
266    input_die: &DebuggingInformationEntry<Reader<'_>>,
267    input_unit: &Unit<Reader<'_>, usize>,
268    reason: &str,
269    depth: isize,
270) {
271    dbi_log!(
272        "=== End DIE at {:?} (depth = {}):\n  Skipped as {}\n",
273        log_get_die_ref(input_unit, input_die.offset()),
274        depth,
275        reason
276    );
277}
278
279fn get_offset_value(offset: UnitSectionOffset) -> usize {
280    match offset {
281        UnitSectionOffset::DebugInfoOffset(offs) => offs.0,
282        UnitSectionOffset::DebugTypesOffset(offs) => offs.0,
283    }
284}
285
286pub fn log_get_value_name(value: ValueLabel) -> ValueNameSummary {
287    ValueNameSummary { value }
288}
289
290pub struct ValueNameSummary {
291    value: ValueLabel,
292}
293
294impl fmt::Debug for ValueNameSummary {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        if self.value == get_vmctx_value_label() {
297            f.pad("VMCTX")
298        } else {
299            f.pad(&format!("L#{}", self.value.as_u32()))
300        }
301    }
302}
303
304pub fn log_get_value_loc(loc: LabelValueLoc, isa: &dyn TargetIsa) -> ValueLocSummary {
305    ValueLocSummary { loc, isa }
306}
307
308pub struct ValueLocSummary<'a> {
309    loc: LabelValueLoc,
310    isa: &'a dyn TargetIsa,
311}
312
313impl<'a> fmt::Debug for ValueLocSummary<'a> {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        if let LabelValueLoc::Reg(reg) = self.loc {
316            let reg_name = self.isa.pretty_print_reg(reg, self.isa.pointer_bytes());
317            return write!(f, "{reg_name}");
318        }
319
320        write!(f, "{:?}", self.loc)
321    }
322}
323
324pub fn log_get_value_ranges<'a>(
325    ranges: Option<&'a ValueLabelsRanges>,
326    isa: &'a dyn TargetIsa,
327) -> ValueRangesSummary<'a> {
328    ValueRangesSummary { ranges, isa }
329}
330
331pub struct ValueRangesSummary<'a> {
332    ranges: Option<&'a ValueLabelsRanges>,
333    isa: &'a dyn TargetIsa,
334}
335
336impl<'a> fmt::Debug for ValueRangesSummary<'a> {
337    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338        if let Some(ranges) = self.ranges {
339            // Sort the output first for nicer display.
340            let mut locals = Vec::new();
341            for value in ranges {
342                locals.push(*value.0);
343            }
344            locals.sort_by_key(|n| n.as_u32());
345
346            for i in 0..locals.len() {
347                let name = locals[i];
348                write!(f, "{:<6?}:", log_get_value_name(name))?;
349                for range in ranges.get(&name).unwrap() {
350                    write!(f, " {:?}", log_get_value_loc(range.loc, self.isa))?;
351                    write!(f, "@[{}..{})", range.start, range.end)?;
352                }
353                if i != locals.len() - 1 {
354                    writeln!(f)?;
355                }
356            }
357        }
358        Ok(())
359    }
360}