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