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