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