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