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