1 use crate::debug::Reader; 2 use core::fmt; 3 use gimli::{ 4 write, AttributeValue, DebuggingInformationEntry, Dwarf, LittleEndian, Unit, UnitSectionOffset, 5 }; 6 7 macro_rules! dbi_log { 8 ($($tt:tt)*) => { 9 if cfg!(any(feature = "trace-log", debug_assertions)) { 10 ::log::trace!(target: "debug-info-transform", $($tt)*); 11 } 12 }; 13 } 14 pub(crate) use dbi_log; 15 16 pub struct CompileUnitSummary<'a> { 17 unit: &'a Unit<Reader<'a>, usize>, 18 } 19 20 impl<'a> fmt::Debug for CompileUnitSummary<'a> { 21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 let unit = self.unit; 23 let offs = get_offset_value(unit.header.offset()); 24 write!(f, "0x{offs:08x} [")?; 25 let comp_dir = match unit.comp_dir { 26 Some(dir) => &dir.to_string_lossy(), 27 None => "None", 28 }; 29 write!(f, "\"{comp_dir}\"")?; 30 let name = match unit.name { 31 Some(name) => &name.to_string_lossy(), 32 None => "None", 33 }; 34 write!(f, ", \"{name}\"]") 35 } 36 } 37 38 pub fn log_get_cu_summary<'a>(unit: &'a Unit<Reader<'a>, usize>) -> CompileUnitSummary<'a> { 39 CompileUnitSummary { unit } 40 } 41 42 struct DieDetailedSummary<'a> { 43 dwarf: &'a Dwarf<Reader<'a>>, 44 unit: &'a Unit<Reader<'a>, usize>, 45 die: &'a DebuggingInformationEntry<'a, 'a, Reader<'a>>, 46 } 47 48 pub fn log_begin_input_die( 49 dwarf: &Dwarf<Reader<'_>>, 50 unit: &Unit<Reader<'_>, usize>, 51 die: &DebuggingInformationEntry<Reader<'_>>, 52 depth: isize, 53 ) { 54 dbi_log!( 55 "=== Begin DIE at 0x{:08x} (depth = {}):\n{:?}", 56 get_offset_value(die.offset().to_unit_section_offset(unit)), 57 depth, 58 DieDetailedSummary { dwarf, unit, die } 59 ); 60 } 61 62 impl<'a> fmt::Debug for DieDetailedSummary<'a> { 63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 64 let die = self.die; 65 let unit = self.unit; 66 let dwarf = self.dwarf; 67 write!(f, "{}\n", die.tag())?; 68 69 let mut attrs = die.attrs(); 70 while let Some(attr) = attrs.next().unwrap_or(None) { 71 write!(f, " {} (", attr.name())?; 72 let attr_value = attr.value(); 73 match attr_value { 74 AttributeValue::Addr(addr) => { 75 write!(f, "{addr:08x}") 76 } 77 AttributeValue::DebugAddrIndex(index) => { 78 if let Some(addr) = dwarf.address(unit, index).ok() { 79 write!(f, "{addr:08x}") 80 } else { 81 write!(f, "<error reading address at index: {}>", index.0) 82 } 83 } 84 AttributeValue::Block(d) => write!(f, "{d:?}"), 85 AttributeValue::Udata(d) => write!(f, "{d}"), 86 AttributeValue::Data1(d) => write!(f, "{d}"), 87 AttributeValue::Data2(d) => write!(f, "{d}"), 88 AttributeValue::Data4(d) => write!(f, "{d}"), 89 AttributeValue::Data8(d) => write!(f, "{d}"), 90 AttributeValue::Sdata(d) => write!(f, "{d}"), 91 AttributeValue::Flag(d) => write!(f, "{d}"), 92 AttributeValue::DebugLineRef(offset) => write!(f, "0x{:08x}", offset.0), 93 AttributeValue::FileIndex(index) => write!(f, "0x{index:08x}"), 94 AttributeValue::String(_) 95 | AttributeValue::DebugStrRef(_) 96 | AttributeValue::DebugStrOffsetsIndex(_) => { 97 if let Ok(s) = dwarf.attr_string(unit, attr_value) { 98 write!(f, "\"{}\"", &s.to_string_lossy()) 99 } else { 100 write!(f, "<error reading string>") 101 } 102 } 103 AttributeValue::RangeListsRef(_) | AttributeValue::DebugRngListsIndex(_) => { 104 let _ = dwarf.attr_ranges_offset(unit, attr_value); 105 write!(f, "<TODO: rnglist dump>") 106 } 107 AttributeValue::LocationListsRef(_) | AttributeValue::DebugLocListsIndex(_) => { 108 let _ = dwarf.attr_locations_offset(unit, attr_value); 109 write!(f, "<TODO: loclist dump>") 110 } 111 AttributeValue::Exprloc(_) => { 112 write!(f, "<TODO: exprloc dump>") 113 } 114 AttributeValue::Encoding(value) => write!(f, "{value}"), 115 AttributeValue::DecimalSign(value) => write!(f, "{value}"), 116 AttributeValue::Endianity(value) => write!(f, "{value}"), 117 AttributeValue::Accessibility(value) => write!(f, "{value}"), 118 AttributeValue::Visibility(value) => write!(f, "{value}"), 119 AttributeValue::Virtuality(value) => write!(f, "{value}"), 120 AttributeValue::Language(value) => write!(f, "{value}"), 121 AttributeValue::AddressClass(value) => write!(f, "{value}"), 122 AttributeValue::IdentifierCase(value) => write!(f, "{value}"), 123 AttributeValue::CallingConvention(value) => write!(f, "{value}"), 124 AttributeValue::Inline(value) => write!(f, "{value}"), 125 AttributeValue::Ordering(value) => write!(f, "{value}"), 126 AttributeValue::UnitRef(offset) => write!(f, "0x{:08x}", offset.0), 127 AttributeValue::DebugInfoRef(offset) => write!(f, "0x{:08x}", offset.0), 128 unexpected_attr => write!(f, "<unexpected attr: {unexpected_attr:?}>"), 129 }?; 130 write!(f, ")\n")?; 131 } 132 Ok(()) 133 } 134 } 135 136 struct OutDieDetailedSummary<'a> { 137 die_id: write::UnitEntryId, 138 unit: &'a write::Unit, 139 strings: &'a write::StringTable, 140 } 141 142 impl<'a> fmt::Debug for OutDieDetailedSummary<'a> { 143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 144 let die = self.unit.get(self.die_id); 145 write!(f, "{}\n", die.tag())?; 146 for attr in die.attrs() { 147 write!(f, " {} (", attr.name())?; 148 let attr_value = attr.get(); 149 match attr_value { 150 write::AttributeValue::Address(addr) => match addr { 151 write::Address::Constant(addr_value) => write!(f, "{addr_value:08x}"), 152 write::Address::Symbol { symbol, addend } => { 153 write!(f, "symbol #{symbol}+{addend}") 154 } 155 }, 156 write::AttributeValue::Block(d) => { 157 write!(f, "{:?}", Reader::new(d.as_slice(), LittleEndian)) 158 } 159 write::AttributeValue::Udata(d) => write!(f, "{d}"), 160 write::AttributeValue::Data1(d) => write!(f, "{d}"), 161 write::AttributeValue::Data2(d) => write!(f, "{d}"), 162 write::AttributeValue::Data4(d) => write!(f, "{d}"), 163 write::AttributeValue::Data8(d) => write!(f, "{d}"), 164 write::AttributeValue::Sdata(d) => write!(f, "{d}"), 165 write::AttributeValue::Flag(d) => write!(f, "{d}"), 166 write::AttributeValue::LineProgramRef => write!(f, "LineProgramRef"), 167 write::AttributeValue::FileIndex(index) => match index { 168 Some(id) => write!(f, "{id:?}"), 169 None => write!(f, "<file index missing>"), 170 }, 171 write::AttributeValue::String(s) => { 172 write!(f, "\"{}\"", &String::from_utf8_lossy(s)) 173 } 174 write::AttributeValue::StringRef(id) => { 175 write!(f, "\"{}\"", &String::from_utf8_lossy(self.strings.get(*id))) 176 } 177 write::AttributeValue::RangeListRef(_) => { 178 write!(f, "<TODO: out rnglist dump>") 179 } 180 write::AttributeValue::LocationListRef(_) => { 181 write!(f, "<TODO: out loclist dump>") 182 } 183 write::AttributeValue::Exprloc(_) => { 184 write!(f, "<TODO: out exprloc dump>") 185 } 186 write::AttributeValue::Encoding(value) => write!(f, "{value}"), 187 write::AttributeValue::DecimalSign(value) => write!(f, "{value}"), 188 write::AttributeValue::Endianity(value) => write!(f, "{value}"), 189 write::AttributeValue::Accessibility(value) => write!(f, "{value}"), 190 write::AttributeValue::Visibility(value) => write!(f, "{value}"), 191 write::AttributeValue::Virtuality(value) => write!(f, "{value}"), 192 write::AttributeValue::Language(value) => write!(f, "{value}"), 193 write::AttributeValue::AddressClass(value) => write!(f, "{value}"), 194 write::AttributeValue::IdentifierCase(value) => write!(f, "{value}"), 195 write::AttributeValue::CallingConvention(value) => write!(f, "{value}"), 196 write::AttributeValue::Inline(value) => write!(f, "{value}"), 197 write::AttributeValue::Ordering(value) => write!(f, "{value}"), 198 write::AttributeValue::UnitRef(unit_ref) => write!(f, "{unit_ref:?}>"), 199 write::AttributeValue::DebugInfoRef(reference) => match reference { 200 write::Reference::Symbol(index) => write!(f, "symbol #{index}>"), 201 write::Reference::Entry(unit_id, die_id) => { 202 write!(f, "{die_id:?} in {unit_id:?}>") 203 } 204 }, 205 unexpected_attr => write!(f, "<unexpected attr: {unexpected_attr:?}>"), 206 }?; 207 write!(f, ")\n")?; 208 } 209 Ok(()) 210 } 211 } 212 213 pub fn log_end_output_die( 214 input_die: &DebuggingInformationEntry<Reader<'_>>, 215 input_unit: &Unit<Reader<'_>, usize>, 216 die_id: write::UnitEntryId, 217 unit: &write::Unit, 218 strings: &write::StringTable, 219 depth: isize, 220 ) { 221 dbi_log!( 222 "=== End DIE at 0x{:08x} (depth = {}):\n{:?}", 223 get_offset_value(input_die.offset().to_unit_section_offset(input_unit)), 224 depth, 225 OutDieDetailedSummary { 226 die_id, 227 unit, 228 strings 229 } 230 ); 231 } 232 233 pub fn log_end_output_die_skipped( 234 input_die: &DebuggingInformationEntry<Reader<'_>>, 235 input_unit: &Unit<Reader<'_>, usize>, 236 reason: &str, 237 depth: isize, 238 ) { 239 dbi_log!( 240 "=== End DIE at 0x{:08x} (depth = {}):\n Skipped as {}\n", 241 get_offset_value(input_die.offset().to_unit_section_offset(input_unit)), 242 depth, 243 reason 244 ); 245 } 246 247 fn get_offset_value(offset: UnitSectionOffset) -> usize { 248 match offset { 249 UnitSectionOffset::DebugInfoOffset(offs) => offs.0, 250 UnitSectionOffset::DebugTypesOffset(offs) => offs.0, 251 } 252 } 253