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