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