diff --git a/src/cmd/dwarf.rs b/src/cmd/dwarf.rs index 23539be..c73936a 100644 --- a/src/cmd/dwarf.rs +++ b/src/cmd/dwarf.rs @@ -15,8 +15,8 @@ use syntect::{ use crate::util::{ dwarf::{ - process_cu_tag, process_root_tag, read_debug_section, should_skip_tag, tag_type_string, - AttributeKind, TagKind, + process_compile_unit, process_cu_tag, process_overlay_branch, read_debug_section, + should_skip_tag, tag_type_string, AttributeKind, TagKind, }, file::{buf_writer, map_file}, }; @@ -163,74 +163,109 @@ where let mut units = Vec::::new(); if let Some((_, mut tag)) = info.tags.first_key_value() { loop { - let unit = process_root_tag(tag)?; - if units.contains(&unit.name) { - // log::warn!("Duplicate unit '{}'", unit.name); - } else { - units.push(unit.name.clone()); - } - writeln!(w, "\n/*\n Compile unit: {}", unit.name)?; - if let Some(producer) = unit.producer { - writeln!(w, " Producer: {}", producer)?; - } - if let Some(language) = unit.language { - writeln!(w, " Language: {}", language)?; - } - if let (Some(start), Some(end)) = (unit.start_address, unit.end_address) { - writeln!(w, " Code range: {:#010X} -> {:#010X}", start, end)?; - } - writeln!(w, "*/")?; - - let children = tag.children(&info.tags); - let mut typedefs = BTreeMap::>::new(); - for child in children { - let tag_type = match process_cu_tag(&info, child) { - Ok(tag_type) => tag_type, - Err(e) => { - log::error!( - "Failed to process tag {} (unit {}): {}", - child.key, - unit.name, - e - ); - writeln!( - w, - "// ERROR: Failed to process tag {} ({:?})", - child.key, child.kind - )?; - continue; - } - }; - if should_skip_tag(&tag_type) { - continue; - } - match tag_type_string(&info, &typedefs, &tag_type) { - Ok(s) => writeln!(w, "{}", s)?, - Err(e) => { - log::error!("Failed to emit tag {} (unit {}): {}", child.key, unit.name, e); - writeln!( - w, - "// ERROR: Failed to emit tag {} ({:?})", - child.key, child.kind - )?; - continue; - } + match tag.kind { + TagKind::Padding => { + // TODO } + TagKind::MwOverlayBranch => { + let branch = process_overlay_branch(tag)?; + writeln!(w, "\n/*\n Overlay: {}", branch.name)?; + writeln!(w, " Overlay ID: {}", branch.id)?; + writeln!( + w, + " Code range: {:#010X} -> {:#010X}", + branch.start_address, branch.end_address + )?; - if let TagKind::Typedef = child.kind { - // TODO fundamental typedefs? - if let Some(ud_type_ref) = child.reference_attribute(AttributeKind::UserDefType) - { - match typedefs.entry(ud_type_ref) { - btree_map::Entry::Vacant(e) => { - e.insert(vec![child.key]); + if let Some(unit_addr) = branch.compile_unit { + let tag = info + .tags + .get(&unit_addr) + .ok_or_else(|| anyhow!("Failed to get CompileUnit"))?; + let unit = process_compile_unit(tag)?; + writeln!(w, " Compile unit: {}", unit.name)?; + } + + writeln!(w, "*/")?; + } + TagKind::CompileUnit => { + let unit = process_compile_unit(tag)?; + if units.contains(&unit.name) { + // log::warn!("Duplicate unit '{}'", unit.name); + } else { + units.push(unit.name.clone()); + } + writeln!(w, "\n/*\n Compile unit: {}", unit.name)?; + if let Some(producer) = unit.producer { + writeln!(w, " Producer: {}", producer)?; + } + if let Some(language) = unit.language { + writeln!(w, " Language: {}", language)?; + } + if let (Some(start), Some(end)) = (unit.start_address, unit.end_address) { + writeln!(w, " Code range: {:#010X} -> {:#010X}", start, end)?; + } + writeln!(w, "*/")?; + + let children = tag.children(&info.tags); + let mut typedefs = BTreeMap::>::new(); + for child in children { + let tag_type = match process_cu_tag(&info, child) { + Ok(tag_type) => tag_type, + Err(e) => { + log::error!( + "Failed to process tag {} (unit {}): {}", + child.key, + unit.name, + e + ); + writeln!( + w, + "// ERROR: Failed to process tag {} ({:?})", + child.key, child.kind + )?; + continue; } - btree_map::Entry::Occupied(e) => { - e.into_mut().push(child.key); + }; + if should_skip_tag(&tag_type) { + continue; + } + match tag_type_string(&info, &typedefs, &tag_type) { + Ok(s) => writeln!(w, "{}", s)?, + Err(e) => { + log::error!( + "Failed to emit tag {} (unit {}): {}", + child.key, + unit.name, + e + ); + writeln!( + w, + "// ERROR: Failed to emit tag {} ({:?})", + child.key, child.kind + )?; + continue; + } + } + + if let TagKind::Typedef = child.kind { + // TODO fundamental typedefs? + if let Some(ud_type_ref) = + child.reference_attribute(AttributeKind::UserDefType) + { + match typedefs.entry(ud_type_ref) { + btree_map::Entry::Vacant(e) => { + e.insert(vec![child.key]); + } + btree_map::Entry::Occupied(e) => { + e.into_mut().push(child.key); + } + } } } } } + kind => bail!("Unhandled root tag type {:?}", kind), } if let Some(next) = tag.next_sibling(&info.tags) { diff --git a/src/util/dwarf.rs b/src/util/dwarf.rs index d870936..c99b18f 100644 --- a/src/util/dwarf.rs +++ b/src/util/dwarf.rs @@ -799,6 +799,15 @@ pub struct CompileUnit { pub end_address: Option, } +#[derive(Debug, Clone)] +pub struct OverlayBranch { + pub name: String, + pub id: u32, + pub start_address: u32, + pub end_address: u32, + pub compile_unit: Option, +} + impl UserDefinedType { pub fn name(&self) -> Option { match self { @@ -2343,7 +2352,7 @@ pub fn process_type(attr: &Attribute, e: Endian) -> Result { } } -pub fn process_root_tag(tag: &Tag) -> Result { +pub fn process_compile_unit(tag: &Tag) -> Result { ensure!(tag.kind == TagKind::CompileUnit, "{:?} is not a CompileUnit tag", tag.kind); let mut name = None; @@ -2374,6 +2383,35 @@ pub fn process_root_tag(tag: &Tag) -> Result { Ok(CompileUnit { name, producer, language, start_address, end_address }) } +pub fn process_overlay_branch(tag: &Tag) -> Result { + ensure!(tag.kind == TagKind::MwOverlayBranch, "{:?} is not an OverlayBranch tag", tag.kind); + + let mut name = None; + let mut id = None; + let mut start_address = None; + let mut end_address = None; + let mut compile_unit = None; + for attr in &tag.attributes { + match (attr.kind, &attr.value) { + (AttributeKind::Sibling, _) => {} + (AttributeKind::Member, AttributeValue::Reference(addr)) => compile_unit = Some(*addr), + (AttributeKind::MwOverlayName, AttributeValue::String(s)) => name = Some(s.clone()), + (AttributeKind::MwOverlayId, AttributeValue::Data4(value)) => id = Some(*value), + (AttributeKind::LowPc, &AttributeValue::Address(addr)) => start_address = Some(addr), + (AttributeKind::HighPc, &AttributeValue::Address(addr)) => end_address = Some(addr), + _ => bail!("Unhandled OverlayBranch attribute {:?}", attr), + } + } + + let name = name.ok_or_else(|| anyhow!("OverlayBranch without Name: {:?}", tag))?; + let id = id.ok_or_else(|| anyhow!("OverlayBranch without Id: {:?}", tag))?; + let start_address = + start_address.ok_or_else(|| anyhow!("OverlayBranch without LowPc: {:?}", tag))?; + let end_address = + end_address.ok_or_else(|| anyhow!("OverlayBranch without HighPc: {:?}", tag))?; + Ok(OverlayBranch { name, id, start_address, end_address, compile_unit }) +} + pub fn process_cu_tag(info: &DwarfInfo, tag: &Tag) -> Result { match tag.kind { TagKind::Typedef => Ok(TagType::Typedef(process_typedef_tag(info, tag)?)),