1 use crate::debug::Reader;
2 use core::fmt;
3 use gimli::{
4     write, AttributeValue, DebuggingInformationEntry, Dwarf, LittleEndian, Unit, UnitSectionOffset,
5 };
6 
7 macro_rules! dbi_log {
8     ($($tt:tt)*) => {
9         if cfg!(any(feature = "trace-log", debug_assertions)) {
10             ::log::trace!(target: "debug-info-transform", $($tt)*);
11         }
12     };
13 }
14 pub(crate) use dbi_log;
15 
16 pub struct CompileUnitSummary<'a> {
17     unit: &'a Unit<Reader<'a>, usize>,
18 }
19 
20 impl<'a> fmt::Debug for CompileUnitSummary<'a> {
21     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22         let unit = self.unit;
23         let offs = get_offset_value(unit.header.offset());
24         write!(f, "0x{offs:08x} [")?;
25         let comp_dir = match unit.comp_dir {
26             Some(dir) => &dir.to_string_lossy(),
27             None => "None",
28         };
29         write!(f, "\"{comp_dir}\"")?;
30         let name = match unit.name {
31             Some(name) => &name.to_string_lossy(),
32             None => "None",
33         };
34         write!(f, ", \"{name}\"]")
35     }
36 }
37 
38 pub fn log_get_cu_summary<'a>(unit: &'a Unit<Reader<'a>, usize>) -> CompileUnitSummary<'a> {
39     CompileUnitSummary { unit }
40 }
41 
42 struct DieDetailedSummary<'a> {
43     dwarf: &'a Dwarf<Reader<'a>>,
44     unit: &'a Unit<Reader<'a>, usize>,
45     die: &'a DebuggingInformationEntry<'a, 'a, Reader<'a>>,
46 }
47 
48 pub fn log_begin_input_die(
49     dwarf: &Dwarf<Reader<'_>>,
50     unit: &Unit<Reader<'_>, usize>,
51     die: &DebuggingInformationEntry<Reader<'_>>,
52     depth: isize,
53 ) {
54     dbi_log!(
55         "=== Begin DIE at 0x{:08x} (depth = {}):\n{:?}",
56         get_offset_value(die.offset().to_unit_section_offset(unit)),
57         depth,
58         DieDetailedSummary { dwarf, unit, die }
59     );
60 }
61 
62 impl<'a> fmt::Debug for DieDetailedSummary<'a> {
63     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64         let die = self.die;
65         let unit = self.unit;
66         let dwarf = self.dwarf;
67         write!(f, "{}\n", die.tag())?;
68 
69         let mut attrs = die.attrs();
70         while let Some(attr) = attrs.next().unwrap_or(None) {
71             write!(f, "  {} (", attr.name())?;
72             let attr_value = attr.value();
73             match attr_value {
74                 AttributeValue::Addr(addr) => {
75                     write!(f, "{addr:08x}")
76                 }
77                 AttributeValue::DebugAddrIndex(index) => {
78                     if let Some(addr) = dwarf.address(unit, index).ok() {
79                         write!(f, "{addr:08x}")
80                     } else {
81                         write!(f, "<error reading address at index: {}>", index.0)
82                     }
83                 }
84                 AttributeValue::Block(d) => write!(f, "{d:?}"),
85                 AttributeValue::Udata(d) => write!(f, "{d}"),
86                 AttributeValue::Data1(d) => write!(f, "{d}"),
87                 AttributeValue::Data2(d) => write!(f, "{d}"),
88                 AttributeValue::Data4(d) => write!(f, "{d}"),
89                 AttributeValue::Data8(d) => write!(f, "{d}"),
90                 AttributeValue::Sdata(d) => write!(f, "{d}"),
91                 AttributeValue::Flag(d) => write!(f, "{d}"),
92                 AttributeValue::DebugLineRef(offset) => write!(f, "0x{:08x}", offset.0),
93                 AttributeValue::FileIndex(index) => write!(f, "0x{index:08x}"),
94                 AttributeValue::String(_)
95                 | AttributeValue::DebugStrRef(_)
96                 | AttributeValue::DebugStrOffsetsIndex(_) => {
97                     if let Ok(s) = dwarf.attr_string(unit, attr_value) {
98                         write!(f, "\"{}\"", &s.to_string_lossy())
99                     } else {
100                         write!(f, "<error reading string>")
101                     }
102                 }
103                 AttributeValue::RangeListsRef(_) | AttributeValue::DebugRngListsIndex(_) => {
104                     let _ = dwarf.attr_ranges_offset(unit, attr_value);
105                     write!(f, "<TODO: rnglist dump>")
106                 }
107                 AttributeValue::LocationListsRef(_) | AttributeValue::DebugLocListsIndex(_) => {
108                     let _ = dwarf.attr_locations_offset(unit, attr_value);
109                     write!(f, "<TODO: loclist dump>")
110                 }
111                 AttributeValue::Exprloc(_) => {
112                     write!(f, "<TODO: exprloc dump>")
113                 }
114                 AttributeValue::Encoding(value) => write!(f, "{value}"),
115                 AttributeValue::DecimalSign(value) => write!(f, "{value}"),
116                 AttributeValue::Endianity(value) => write!(f, "{value}"),
117                 AttributeValue::Accessibility(value) => write!(f, "{value}"),
118                 AttributeValue::Visibility(value) => write!(f, "{value}"),
119                 AttributeValue::Virtuality(value) => write!(f, "{value}"),
120                 AttributeValue::Language(value) => write!(f, "{value}"),
121                 AttributeValue::AddressClass(value) => write!(f, "{value}"),
122                 AttributeValue::IdentifierCase(value) => write!(f, "{value}"),
123                 AttributeValue::CallingConvention(value) => write!(f, "{value}"),
124                 AttributeValue::Inline(value) => write!(f, "{value}"),
125                 AttributeValue::Ordering(value) => write!(f, "{value}"),
126                 AttributeValue::UnitRef(offset) => write!(f, "0x{:08x}", offset.0),
127                 AttributeValue::DebugInfoRef(offset) => write!(f, "0x{:08x}", offset.0),
128                 unexpected_attr => write!(f, "<unexpected attr: {unexpected_attr:?}>"),
129             }?;
130             write!(f, ")\n")?;
131         }
132         Ok(())
133     }
134 }
135 
136 struct OutDieDetailedSummary<'a> {
137     die_id: write::UnitEntryId,
138     unit: &'a write::Unit,
139     strings: &'a write::StringTable,
140 }
141 
142 impl<'a> fmt::Debug for OutDieDetailedSummary<'a> {
143     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144         let die = self.unit.get(self.die_id);
145         write!(f, "{}\n", die.tag())?;
146         for attr in die.attrs() {
147             write!(f, "  {} (", attr.name())?;
148             let attr_value = attr.get();
149             match attr_value {
150                 write::AttributeValue::Address(addr) => match addr {
151                     write::Address::Constant(addr_value) => write!(f, "{addr_value:08x}"),
152                     write::Address::Symbol { symbol, addend } => {
153                         write!(f, "symbol #{symbol}+{addend}")
154                     }
155                 },
156                 write::AttributeValue::Block(d) => {
157                     write!(f, "{:?}", Reader::new(d.as_slice(), LittleEndian))
158                 }
159                 write::AttributeValue::Udata(d) => write!(f, "{d}"),
160                 write::AttributeValue::Data1(d) => write!(f, "{d}"),
161                 write::AttributeValue::Data2(d) => write!(f, "{d}"),
162                 write::AttributeValue::Data4(d) => write!(f, "{d}"),
163                 write::AttributeValue::Data8(d) => write!(f, "{d}"),
164                 write::AttributeValue::Sdata(d) => write!(f, "{d}"),
165                 write::AttributeValue::Flag(d) => write!(f, "{d}"),
166                 write::AttributeValue::LineProgramRef => write!(f, "LineProgramRef"),
167                 write::AttributeValue::FileIndex(index) => match index {
168                     Some(id) => write!(f, "{id:?}"),
169                     None => write!(f, "<file index missing>"),
170                 },
171                 write::AttributeValue::String(s) => {
172                     write!(f, "\"{}\"", &String::from_utf8_lossy(s))
173                 }
174                 write::AttributeValue::StringRef(id) => {
175                     write!(f, "\"{}\"", &String::from_utf8_lossy(self.strings.get(*id)))
176                 }
177                 write::AttributeValue::RangeListRef(_) => {
178                     write!(f, "<TODO: out rnglist dump>")
179                 }
180                 write::AttributeValue::LocationListRef(_) => {
181                     write!(f, "<TODO: out loclist dump>")
182                 }
183                 write::AttributeValue::Exprloc(_) => {
184                     write!(f, "<TODO: out exprloc dump>")
185                 }
186                 write::AttributeValue::Encoding(value) => write!(f, "{value}"),
187                 write::AttributeValue::DecimalSign(value) => write!(f, "{value}"),
188                 write::AttributeValue::Endianity(value) => write!(f, "{value}"),
189                 write::AttributeValue::Accessibility(value) => write!(f, "{value}"),
190                 write::AttributeValue::Visibility(value) => write!(f, "{value}"),
191                 write::AttributeValue::Virtuality(value) => write!(f, "{value}"),
192                 write::AttributeValue::Language(value) => write!(f, "{value}"),
193                 write::AttributeValue::AddressClass(value) => write!(f, "{value}"),
194                 write::AttributeValue::IdentifierCase(value) => write!(f, "{value}"),
195                 write::AttributeValue::CallingConvention(value) => write!(f, "{value}"),
196                 write::AttributeValue::Inline(value) => write!(f, "{value}"),
197                 write::AttributeValue::Ordering(value) => write!(f, "{value}"),
198                 write::AttributeValue::UnitRef(unit_ref) => write!(f, "{unit_ref:?}>"),
199                 write::AttributeValue::DebugInfoRef(reference) => match reference {
200                     write::Reference::Symbol(index) => write!(f, "symbol #{index}>"),
201                     write::Reference::Entry(unit_id, die_id) => {
202                         write!(f, "{die_id:?} in {unit_id:?}>")
203                     }
204                 },
205                 unexpected_attr => write!(f, "<unexpected attr: {unexpected_attr:?}>"),
206             }?;
207             write!(f, ")\n")?;
208         }
209         Ok(())
210     }
211 }
212 
213 pub fn log_end_output_die(
214     input_die: &DebuggingInformationEntry<Reader<'_>>,
215     input_unit: &Unit<Reader<'_>, usize>,
216     die_id: write::UnitEntryId,
217     unit: &write::Unit,
218     strings: &write::StringTable,
219     depth: isize,
220 ) {
221     dbi_log!(
222         "=== End DIE at 0x{:08x} (depth = {}):\n{:?}",
223         get_offset_value(input_die.offset().to_unit_section_offset(input_unit)),
224         depth,
225         OutDieDetailedSummary {
226             die_id,
227             unit,
228             strings
229         }
230     );
231 }
232 
233 pub fn log_end_output_die_skipped(
234     input_die: &DebuggingInformationEntry<Reader<'_>>,
235     input_unit: &Unit<Reader<'_>, usize>,
236     reason: &str,
237     depth: isize,
238 ) {
239     dbi_log!(
240         "=== End DIE at 0x{:08x} (depth = {}):\n  Skipped as {}\n",
241         get_offset_value(input_die.offset().to_unit_section_offset(input_unit)),
242         depth,
243         reason
244     );
245 }
246 
247 fn get_offset_value(offset: UnitSectionOffset) -> usize {
248     match offset {
249         UnitSectionOffset::DebugInfoOffset(offs) => offs.0,
250         UnitSectionOffset::DebugTypesOffset(offs) => offs.0,
251     }
252 }
253