1 use crate::{debug::Reader, translate::get_vmctx_value_label};
2 use core::fmt;
3 use cranelift_codegen::{LabelValueLoc, ValueLabelsRanges, ir::ValueLabel, isa::TargetIsa};
4 use gimli::{
5     AttributeValue, DebuggingInformationEntry, Dwarf, LittleEndian, Unit, UnitOffset,
6     UnitSectionOffset, write,
7 };
8 
9 macro_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 }
15 macro_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 }
22 pub(crate) use dbi_log;
23 pub(crate) use dbi_log_enabled;
24 
25 pub struct CompileUnitSummary<'a> {
26     unit: &'a Unit<Reader<'a>, usize>,
27 }
28 
29 impl<'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 
47 pub fn log_get_cu_summary<'a>(unit: &'a Unit<Reader<'a>, usize>) -> CompileUnitSummary<'a> {
48     CompileUnitSummary { unit }
49 }
50 
51 pub struct DieRefSummary<'a> {
52     unit: &'a Unit<Reader<'a>, usize>,
53     unit_ref: UnitOffset,
54 }
55 
56 impl<'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 
64 pub 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 
71 struct 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 
77 pub 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 
91 impl<'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 
168 struct OutDieDetailedSummary<'a> {
169     die_id: write::UnitEntryId,
170     unit: &'a write::Unit,
171     strings: &'a write::StringTable,
172 }
173 
174 impl<'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 
245 pub 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 
265 pub 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 
279 fn get_offset_value(offset: UnitSectionOffset) -> usize {
280     match offset {
281         UnitSectionOffset::DebugInfoOffset(offs) => offs.0,
282         UnitSectionOffset::DebugTypesOffset(offs) => offs.0,
283     }
284 }
285 
286 pub fn log_get_value_name(value: ValueLabel) -> ValueNameSummary {
287     ValueNameSummary { value }
288 }
289 
290 pub struct ValueNameSummary {
291     value: ValueLabel,
292 }
293 
294 impl 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 
304 pub fn log_get_value_loc(loc: LabelValueLoc, isa: &dyn TargetIsa) -> ValueLocSummary<'_> {
305     ValueLocSummary { loc, isa }
306 }
307 
308 pub struct ValueLocSummary<'a> {
309     loc: LabelValueLoc,
310     isa: &'a dyn TargetIsa,
311 }
312 
313 impl<'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 
324 pub 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 
331 pub struct ValueRangesSummary<'a> {
332     ranges: Option<&'a ValueLabelsRanges>,
333     isa: &'a dyn TargetIsa,
334 }
335 
336 impl<'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 }
361