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> { 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 entry: &'a write::ConvertUnitEntry<'a, Reader<'r>>, 49 } 50 51 impl<'a, 'r> fmt::Debug for DieRefSummary<'a, 'r> { 52 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 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 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> { 81 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> { 160 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 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 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 256 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 { 265 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 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> { 284 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 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> { 307 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