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