From d43b95a0e4a2734f1da91567ec2a22e1d93c0581 Mon Sep 17 00:00:00 2001 From: Sewer Date: Mon, 11 Dec 2023 18:07:29 +0000 Subject: [PATCH] Added: Support for Little Endian DWARF, Inline Arrays & Additional MetroWerks Extensions (#14) * Added: Minimal Required Changes to Dump Sonic Heroes (PS2) * Added: Switch for Little Endian DWARF Dump * Added: Support for Array Ordering * Added: Big/Little Endian Variants of u32_from_bytes * Changed: Detect bitness from .elf header. * Changed: Use Proper MetroWerks Names * Changed: Use Endianness from File API * Refactor DWARF endian handling & some fixes * Undo accidental formatting changes --------- Co-authored-by: Luke Street --- src/cmd/dwarf.rs | 14 +- src/util/dwarf.rs | 503 +++++++++++++++++++++++++++------------------ src/util/reader.rs | 28 ++- 3 files changed, 336 insertions(+), 209 deletions(-) diff --git a/src/cmd/dwarf.rs b/src/cmd/dwarf.rs index 46552c8..545cc83 100644 --- a/src/cmd/dwarf.rs +++ b/src/cmd/dwarf.rs @@ -154,14 +154,14 @@ where } let mut reader = Cursor::new(&*data); - let tags = read_debug_section(&mut reader)?; + let info = read_debug_section(&mut reader, obj_file.endianness().into())?; - for (&addr, tag) in &tags { + for (&addr, tag) in &info.tags { log::debug!("{}: {:?}", addr, tag); } let mut units = Vec::::new(); - if let Some((_, mut tag)) = tags.first_key_value() { + if let Some((_, mut tag)) = info.tags.first_key_value() { loop { match tag.kind { TagKind::CompileUnit => { @@ -175,10 +175,10 @@ where } writeln!(w, "\n// Compile unit: {}", unit)?; - let children = tag.children(&tags); + let children = tag.children(&info.tags); let mut typedefs = BTreeMap::>::new(); for child in children { - let tag_type = match process_root_tag(&tags, child) { + let tag_type = match process_root_tag(&info, child) { Ok(tag_type) => tag_type, Err(e) => { log::error!( @@ -198,7 +198,7 @@ where if should_skip_tag(&tag_type) { continue; } - match tag_type_string(&tags, &typedefs, &tag_type) { + match tag_type_string(&info, &typedefs, &tag_type) { Ok(s) => writeln!(w, "{}", s)?, Err(e) => { log::error!( @@ -238,7 +238,7 @@ where break; } } - if let Some(next) = tag.next_sibling(&tags) { + if let Some(next) = tag.next_sibling(&info.tags) { tag = next; } else { break; diff --git a/src/util/dwarf.rs b/src/util/dwarf.rs index f0a697e..a63356d 100644 --- a/src/util/dwarf.rs +++ b/src/util/dwarf.rs @@ -13,7 +13,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use crate::{ array_ref, - util::reader::{Endian, FromReader}, + util::reader::{Endian, FromBytes, FromReader}, }; #[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)] @@ -53,6 +53,7 @@ pub enum TagKind { SubrangeType = 0x0021, WithStmt = 0x0022, // User types + MwOverlayBranch = 0x4080, } #[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)] @@ -268,8 +269,45 @@ pub enum AttributeKind { HiUser = 0x3ff0, // User types MwMangled = 0x2000 | (FormKind::String as u16), + MwRestoreSp = 0x2010 | (FormKind::Block2 as u16), MwGlobalRef = 0x2020 | (FormKind::Ref as u16), MwGlobalRefByName = 0x2030 | (FormKind::String as u16), + MwRestoreS0 = 0x2040 | (FormKind::Block2 as u16), + MwRestoreS1 = 0x2050 | (FormKind::Block2 as u16), + MwRestoreS2 = 0x2060 | (FormKind::Block2 as u16), + MwRestoreS3 = 0x2070 | (FormKind::Block2 as u16), + MwRestoreS4 = 0x2080 | (FormKind::Block2 as u16), + MwRestoreS5 = 0x2090 | (FormKind::Block2 as u16), + MwRestoreS6 = 0x20A0 | (FormKind::Block2 as u16), + MwRestoreS7 = 0x20B0 | (FormKind::Block2 as u16), + MwRestoreS8 = 0x20C0 | (FormKind::Block2 as u16), + MwRestoreF20 = 0x20D0 | (FormKind::Block2 as u16), + MwRestoreF21 = 0x20E0 | (FormKind::Block2 as u16), + MwRestoreF22 = 0x20F0 | (FormKind::Block2 as u16), + MwRestoreF23 = 0x2100 | (FormKind::Block2 as u16), + MwRestoreF24 = 0x2110 | (FormKind::Block2 as u16), + MwRestoreF25 = 0x2120 | (FormKind::Block2 as u16), + MwRestoreF26 = 0x2130 | (FormKind::Block2 as u16), + MwRestoreF27 = 0x2140 | (FormKind::Block2 as u16), + MwRestoreF28 = 0x2150 | (FormKind::Block2 as u16), + MwRestoreF29 = 0x2160 | (FormKind::Block2 as u16), + MwRestoreF30 = 0x2170 | (FormKind::Block2 as u16), + MwRestoreD20 = 0x2180 | (FormKind::Block2 as u16), + MwRestoreD21 = 0x2190 | (FormKind::Block2 as u16), + MwRestoreD22 = 0x21A0 | (FormKind::Block2 as u16), + MwRestoreD23 = 0x21B0 | (FormKind::Block2 as u16), + MwRestoreD24 = 0x21C0 | (FormKind::Block2 as u16), + MwRestoreD25 = 0x21D0 | (FormKind::Block2 as u16), + MwRestoreD26 = 0x2240 | (FormKind::Block2 as u16), + MwRestoreD27 = 0x2250 | (FormKind::Block2 as u16), + MwRestoreD28 = 0x2260 | (FormKind::Block2 as u16), + MwRestoreD29 = 0x2270 | (FormKind::Block2 as u16), + MwRestoreD30 = 0x2280 | (FormKind::Block2 as u16), + MwOverlayId = 0x2290 | (FormKind::Data4 as u16), + MwOverlayName = 0x22A0 | (FormKind::String as u16), + MwGlobalRefsBlock = 0x2300 | (FormKind::Block2 as u16), + MwLocalSpoffset = 0x2310 | (FormKind::Block4 as u16), + MwMips16 = 0x2330 | (FormKind::String as u16), MwDwarf2Location = 0x2340 | (FormKind::Block2 as u16), Unknown800 = 0x8000 | (FormKind::Data4 as u16), Unknown801 = 0x8010 | (FormKind::Data4 as u16), @@ -304,6 +342,12 @@ pub struct Tag { pub type TagMap = BTreeMap; pub type TypedefMap = BTreeMap>; +#[derive(Debug, Clone)] +pub struct DwarfInfo { + pub e: Endian, + pub tags: TagMap, +} + impl Tag { #[inline] pub fn attribute(&self, kind: AttributeKind) -> Option<&Attribute> { @@ -410,7 +454,7 @@ impl Tag { } } -pub fn read_debug_section(reader: &mut R) -> Result +pub fn read_debug_section(reader: &mut R, e: Endian) -> Result where R: BufRead + Seek + ?Sized { let len = { let old_pos = reader.stream_position()?; @@ -419,20 +463,20 @@ where R: BufRead + Seek + ?Sized { len }; - let mut tags = BTreeMap::new(); + let mut info = DwarfInfo { e, tags: BTreeMap::new() }; loop { let position = reader.stream_position()?; if position >= len { break; } - let tag = read_tag(reader)?; - tags.insert(position as u32, tag); + let tag = read_tag(reader, e)?; + info.tags.insert(position as u32, tag); } - Ok(tags) + Ok(info) } #[allow(unused)] -pub fn read_aranges_section(reader: &mut R) -> Result<()> +pub fn read_aranges_section(reader: &mut R, e: Endian) -> Result<()> where R: BufRead + Seek + ?Sized { let len = { let old_pos = reader.stream_position()?; @@ -448,23 +492,23 @@ where R: BufRead + Seek + ?Sized { break; } - let size = u32::from_reader(reader, Endian::Big)?; - let version = u8::from_reader(reader, Endian::Big)?; + let size = u32::from_reader(reader, e)?; + let version = u8::from_reader(reader, e)?; ensure!(version == 1, "Expected version 1, got {version}"); - let _debug_offs = u32::from_reader(reader, Endian::Big)?; - let _debug_size = u32::from_reader(reader, Endian::Big)?; + let _debug_offs = u32::from_reader(reader, e)?; + let _debug_size = u32::from_reader(reader, e)?; while reader.stream_position()? < position + size as u64 { - let _address = u32::from_reader(reader, Endian::Big)?; - let _length = u32::from_reader(reader, Endian::Big)?; + let _address = u32::from_reader(reader, e)?; + let _length = u32::from_reader(reader, e)?; } } Ok(()) } -fn read_tag(reader: &mut R) -> Result +fn read_tag(reader: &mut R, e: Endian) -> Result where R: BufRead + Seek + ?Sized { let position = reader.stream_position()?; - let size = u32::from_reader(reader, Endian::Big)?; + let size = u32::from_reader(reader, e)?; if size < 8 { // Null entry if size > 4 { @@ -473,15 +517,14 @@ where R: BufRead + Seek + ?Sized { return Ok(Tag { key: position as u32, kind: TagKind::Padding, attributes: vec![] }); } - let tag = TagKind::try_from(u16::from_reader(reader, Endian::Big)?) - .context("Unknown DWARF tag type")?; + let tag_num = u16::from_reader(reader, e)?; + let tag = TagKind::try_from(tag_num).context("Unknown DWARF tag type")?; let mut attributes = Vec::new(); if tag == TagKind::Padding { reader.seek(SeekFrom::Start(position + size as u64))?; // Skip padding } else { while reader.stream_position()? < position + size as u64 { - let attribute = read_attribute(reader)?; - attributes.push(attribute); + attributes.push(read_attribute(reader, e)?); } } Ok(Tag { key: position as u32, kind: tag, attributes }) @@ -502,29 +545,29 @@ where R: BufRead + ?Sized { Ok(str) } -fn read_attribute(reader: &mut R) -> Result +fn read_attribute(reader: &mut R, e: Endian) -> Result where R: BufRead + Seek + ?Sized { - let attr_type = u16::from_reader(reader, Endian::Big)?; + let attr_type = u16::from_reader(reader, e)?; let attr = AttributeKind::try_from(attr_type).context("Unknown DWARF attribute type")?; let form = FormKind::try_from(attr_type & FORM_MASK).context("Unknown DWARF form type")?; let value = match form { - FormKind::Addr => AttributeValue::Address(u32::from_reader(reader, Endian::Big)?), - FormKind::Ref => AttributeValue::Reference(u32::from_reader(reader, Endian::Big)?), + FormKind::Addr => AttributeValue::Address(u32::from_reader(reader, e)?), + FormKind::Ref => AttributeValue::Reference(u32::from_reader(reader, e)?), FormKind::Block2 => { - let size = u16::from_reader(reader, Endian::Big)?; + let size = u16::from_reader(reader, e)?; let mut data = vec![0u8; size as usize]; reader.read_exact(&mut data)?; AttributeValue::Block(data) } FormKind::Block4 => { - let size = u32::from_reader(reader, Endian::Big)?; + let size = u32::from_reader(reader, e)?; let mut data = vec![0u8; size as usize]; reader.read_exact(&mut data)?; AttributeValue::Block(data) } - FormKind::Data2 => AttributeValue::Data2(u16::from_reader(reader, Endian::Big)?), - FormKind::Data4 => AttributeValue::Data4(u32::from_reader(reader, Endian::Big)?), - FormKind::Data8 => AttributeValue::Data8(u64::from_reader(reader, Endian::Big)?), + FormKind::Data2 => AttributeValue::Data2(u16::from_reader(reader, e)?), + FormKind::Data4 => AttributeValue::Data4(u32::from_reader(reader, e)?), + FormKind::Data8 => AttributeValue::Data8(u64::from_reader(reader, e)?), FormKind::String => AttributeValue::String(read_string(reader)?), }; Ok(Attribute { kind: attr, value }) @@ -536,6 +579,14 @@ pub struct ArrayDimension { pub size: Option, } +#[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)] +#[repr(u16)] +pub enum ArrayOrdering { + RowMajor = 0, + // ORD_row_major + ColMajor = 1, // ORD_col_major +} + #[derive(Debug, Clone)] pub struct ArrayType { pub element_type: Box, @@ -722,10 +773,10 @@ impl UserDefinedType { } } - pub fn size(&self, tags: &TagMap) -> Result { + pub fn size(&self, info: &DwarfInfo) -> Result { Ok(match self { UserDefinedType::Array(t) => { - let mut size = t.element_type.size(tags)?; + let mut size = t.element_type.size(info)?; for dim in &t.dimensions { size *= dim.size.map(|u| u.get()).unwrap_or_default(); } @@ -738,7 +789,7 @@ impl UserDefinedType { for member in &t.members { let size = match member.byte_size { Some(byte_size) => byte_size, - None => member.kind.size(tags)?, + None => member.kind.size(info)?, }; max_end = max(max_end, member.offset + size); } @@ -766,18 +817,19 @@ pub struct Type { } impl Type { - pub fn size(&self, tags: &TagMap) -> Result { + pub fn size(&self, info: &DwarfInfo) -> Result { if self.modifiers.iter().any(|m| matches!(m, Modifier::PointerTo | Modifier::ReferenceTo)) { return Ok(4); } match self.kind { TypeKind::Fundamental(ft) => ft.size(), TypeKind::UserDefined(key) => { - let tag = tags + let tag = info + .tags .get(&key) .ok_or_else(|| anyhow!("Failed to locate user defined type {}", key))?; - let ud_type = ud_type(tags, tag)?; - ud_type.size(tags) + let ud_type = ud_type(info, tag)?; + ud_type.size(info) } } } @@ -849,7 +901,7 @@ impl Display for TypeString { } pub fn type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &Type, include_anonymous_def: bool, @@ -860,38 +912,43 @@ pub fn type_string( } TypeKind::UserDefined(key) => { if let Some(&td_key) = typedefs.get(&key).and_then(|v| v.first()) { - let tag = - tags.get(&td_key).ok_or_else(|| anyhow!("Failed to locate typedef {}", key))?; + let tag = info + .tags + .get(&td_key) + .ok_or_else(|| anyhow!("Failed to locate typedef {}", key))?; let td_name = tag .string_attribute(AttributeKind::Name) .ok_or_else(|| anyhow!("typedef without name"))?; TypeString { prefix: td_name.clone(), ..Default::default() } } else { - let tag = tags + let tag = info + .tags .get(&key) .ok_or_else(|| anyhow!("Failed to locate user defined type {}", key))?; - ud_type_string(tags, typedefs, &ud_type(tags, tag)?, true, include_anonymous_def)? + ud_type_string(info, typedefs, &ud_type(info, tag)?, true, include_anonymous_def)? } } }; apply_modifiers(str, &t.modifiers) } -fn type_name(tags: &TagMap, typedefs: &TypedefMap, t: &Type) -> Result { +fn type_name(info: &DwarfInfo, typedefs: &TypedefMap, t: &Type) -> Result { Ok(match t.kind { TypeKind::Fundamental(ft) => ft.name()?.to_string(), TypeKind::UserDefined(key) => { if let Some(&td_key) = typedefs.get(&key).and_then(|v| v.first()) { - tags.get(&td_key) + info.tags + .get(&td_key) .ok_or_else(|| anyhow!("Failed to locate typedef {}", key))? .string_attribute(AttributeKind::Name) .ok_or_else(|| anyhow!("typedef without name"))? .clone() } else { - let tag = tags + let tag = info + .tags .get(&key) .ok_or_else(|| anyhow!("Failed to locate user defined type {}", key))?; - let udt = ud_type(tags, tag)?; + let udt = ud_type(info, tag)?; udt.name().ok_or_else(|| anyhow!("User defined type without name"))? } } @@ -899,12 +956,12 @@ fn type_name(tags: &TagMap, typedefs: &TypedefMap, t: &Type) -> Result { } fn array_type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &ArrayType, include_anonymous_def: bool, ) -> Result { - let mut out = type_string(tags, typedefs, t.element_type.as_ref(), include_anonymous_def)?; + let mut out = type_string(info, typedefs, t.element_type.as_ref(), include_anonymous_def)?; for dim in &t.dimensions { ensure!( matches!( @@ -912,7 +969,7 @@ fn array_type_string( TypeKind::Fundamental(FundType::Long | FundType::Integer) ), "Unsupported array index type '{}'", - type_string(tags, typedefs, &dim.index_type, true)? + type_string(info, typedefs, &dim.index_type, true)? ); match dim.size { None => out.suffix.insert_str(0, "[]"), @@ -923,7 +980,7 @@ fn array_type_string( } fn structure_type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &StructureType, include_keyword: bool, @@ -939,7 +996,7 @@ fn structure_type_string( name.clone() } } else if include_anonymous_def { - struct_def_string(tags, typedefs, t)? + struct_def_string(info, typedefs, t)? } else if include_keyword { match t.kind { StructureKind::Struct => "struct [anonymous]".to_string(), @@ -955,7 +1012,7 @@ fn structure_type_string( } fn enumeration_type_string( - _tags: &TagMap, + _info: &DwarfInfo, _typedefs: &TypedefMap, t: &EnumerationType, include_keyword: bool, @@ -978,7 +1035,7 @@ fn enumeration_type_string( } fn union_type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &UnionType, include_keyword: bool, @@ -991,7 +1048,7 @@ fn union_type_string( name.clone() } } else if include_anonymous_def { - union_def_string(tags, typedefs, t)? + union_def_string(info, typedefs, t)? } else if include_keyword { "union [anonymous]".to_string() } else { @@ -1001,39 +1058,40 @@ fn union_type_string( } pub fn ud_type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &UserDefinedType, include_keyword: bool, include_anonymous_def: bool, ) -> Result { Ok(match t { - UserDefinedType::Array(t) => array_type_string(tags, typedefs, t, include_anonymous_def)?, + UserDefinedType::Array(t) => array_type_string(info, typedefs, t, include_anonymous_def)?, UserDefinedType::Structure(t) => { - structure_type_string(tags, typedefs, t, include_keyword, include_anonymous_def)? + structure_type_string(info, typedefs, t, include_keyword, include_anonymous_def)? } UserDefinedType::Enumeration(t) => { - enumeration_type_string(tags, typedefs, t, include_keyword, include_anonymous_def)? + enumeration_type_string(info, typedefs, t, include_keyword, include_anonymous_def)? } UserDefinedType::Union(t) => { - union_type_string(tags, typedefs, t, include_keyword, include_anonymous_def)? + union_type_string(info, typedefs, t, include_keyword, include_anonymous_def)? } - UserDefinedType::Subroutine(t) => subroutine_type_string(tags, typedefs, t)?, - UserDefinedType::PtrToMember(t) => ptr_to_member_type_string(tags, typedefs, t)?, + UserDefinedType::Subroutine(t) => subroutine_type_string(info, typedefs, t)?, + UserDefinedType::PtrToMember(t) => ptr_to_member_type_string(info, typedefs, t)?, }) } fn ptr_to_member_type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &PtrToMemberType, ) -> Result { - let ts = type_string(tags, typedefs, &t.kind, true)?; - let containing_type = tags + let ts = type_string(info, typedefs, &t.kind, true)?; + let containing_type = info + .tags .get(&t.containing_type) .ok_or_else(|| anyhow!("Failed to locate containing type {}", t.containing_type))?; let containing_ts = - ud_type_string(tags, typedefs, &ud_type(tags, containing_type)?, false, false)?; + ud_type_string(info, typedefs, &ud_type(info, containing_type)?, false, false)?; Ok(TypeString { prefix: format!("{} ({}::*", ts.prefix, containing_ts.prefix), suffix: format!("{}){}", containing_ts.suffix, ts.suffix), @@ -1041,29 +1099,29 @@ fn ptr_to_member_type_string( }) } -pub fn ud_type_def(tags: &TagMap, typedefs: &TypedefMap, t: &UserDefinedType) -> Result { +pub fn ud_type_def(info: &DwarfInfo, typedefs: &TypedefMap, t: &UserDefinedType) -> Result { match t { UserDefinedType::Array(t) => { - let ts = array_type_string(tags, typedefs, t, false)?; + let ts = array_type_string(info, typedefs, t, false)?; Ok(format!("// Array: {}{}", ts.prefix, ts.suffix)) } - UserDefinedType::Subroutine(t) => Ok(subroutine_def_string(tags, typedefs, t)?), - UserDefinedType::Structure(t) => Ok(struct_def_string(tags, typedefs, t)?), + UserDefinedType::Subroutine(t) => Ok(subroutine_def_string(info, typedefs, t)?), + UserDefinedType::Structure(t) => Ok(struct_def_string(info, typedefs, t)?), UserDefinedType::Enumeration(t) => Ok(enum_def_string(t)?), - UserDefinedType::Union(t) => Ok(union_def_string(tags, typedefs, t)?), + UserDefinedType::Union(t) => Ok(union_def_string(info, typedefs, t)?), UserDefinedType::PtrToMember(t) => { - let ts = ptr_to_member_type_string(tags, typedefs, t)?; + let ts = ptr_to_member_type_string(info, typedefs, t)?; Ok(format!("// PtrToMember: {}{}", ts.prefix, ts.suffix)) } } } pub fn subroutine_type_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &SubroutineType, ) -> Result { - let mut out = type_string(tags, typedefs, &t.return_type, true)?; + let mut out = type_string(info, typedefs, &t.return_type, true)?; let mut parameters = String::new(); if t.parameters.is_empty() { if t.var_args { @@ -1076,7 +1134,7 @@ pub fn subroutine_type_string( if idx > 0 { write!(parameters, ", ")?; } - let ts = type_string(tags, typedefs, ¶meter.kind, true)?; + let ts = type_string(info, typedefs, ¶meter.kind, true)?; if let Some(name) = ¶meter.name { write!(parameters, "{} {}{}", ts.prefix, name, ts.suffix)?; } else { @@ -1092,7 +1150,8 @@ pub fn subroutine_type_string( } out.suffix = format!("({}){}", parameters, out.suffix); if let Some(member_of) = t.member_of { - let tag = tags + let tag = info + .tags .get(&member_of) .ok_or_else(|| anyhow!("Failed to locate member_of tag {}", member_of))?; let base_name = tag @@ -1104,11 +1163,11 @@ pub fn subroutine_type_string( } pub fn subroutine_def_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &SubroutineType, ) -> Result { - let rt = type_string(tags, typedefs, &t.return_type, true)?; + let rt = type_string(info, typedefs, &t.return_type, true)?; let mut out = if t.local { "static ".to_string() } else { String::new() }; if t.inline { out.push_str("inline "); @@ -1118,7 +1177,8 @@ pub fn subroutine_def_string( let mut name_written = false; if let Some(member_of) = t.member_of { - let tag = tags + let tag = info + .tags .get(&member_of) .ok_or_else(|| anyhow!("Failed to locate member_of tag {}", member_of))?; let base_name = tag @@ -1154,7 +1214,7 @@ pub fn subroutine_def_string( if idx > 0 { write!(parameters, ", ")?; } - let ts = type_string(tags, typedefs, ¶meter.kind, true)?; + let ts = type_string(info, typedefs, ¶meter.kind, true)?; if let Some(name) = ¶meter.name { write!(parameters, "{} {}{}", ts.prefix, name, ts.suffix)?; } else { @@ -1174,7 +1234,7 @@ pub fn subroutine_def_string( writeln!(out, "\n // Local variables")?; let mut var_out = String::new(); for variable in &t.variables { - let ts = type_string(tags, typedefs, &variable.kind, true)?; + let ts = type_string(info, typedefs, &variable.kind, true)?; write!( var_out, "{} {}{};", @@ -1193,15 +1253,16 @@ pub fn subroutine_def_string( if !t.references.is_empty() { writeln!(out, "\n // References")?; for &reference in &t.references { - let tag = tags + let tag = info + .tags .get(&reference) .ok_or_else(|| anyhow!("Failed to locate reference tag {}", reference))?; if tag.kind == TagKind::Padding { writeln!(out, " // -> ??? ({})", reference)?; continue; } - let variable = process_variable_tag(tags, tag)?; - writeln!(out, " // -> {}", variable_string(tags, typedefs, &variable, false)?)?; + let variable = process_variable_tag(info, tag)?; + writeln!(out, " // -> {}", variable_string(info, typedefs, &variable, false)?)?; } } @@ -1215,7 +1276,7 @@ pub fn subroutine_def_string( if !t.blocks.is_empty() { writeln!(out, "\n // Blocks")?; for block in &t.blocks { - let block_str = subroutine_block_string(tags, typedefs, block)?; + let block_str = subroutine_block_string(info, typedefs, block)?; out.push_str(&indent_all_by(4, block_str)); } } @@ -1223,14 +1284,15 @@ pub fn subroutine_def_string( if !t.inlines.is_empty() { writeln!(out, "\n // Inlines")?; for inline in &t.inlines { - let spec_tag = tags + let spec_tag = info + .tags .get(&inline.specification) .ok_or_else(|| anyhow!("Failed to locate inline tag {}", inline.specification))?; - let subroutine = process_subroutine_tag(tags, spec_tag)?; + let subroutine = process_subroutine_tag(info, spec_tag)?; writeln!( out, " // -> {} ({:#X} - {:#X})", - subroutine_type_string(tags, typedefs, &subroutine)?, + subroutine_type_string(info, typedefs, &subroutine)?, inline.start_address, inline.end_address, )?; @@ -1242,7 +1304,7 @@ pub fn subroutine_def_string( } fn subroutine_block_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, block: &SubroutineBlock, ) -> Result { @@ -1255,7 +1317,7 @@ fn subroutine_block_string( writeln!(out, "{{\n // Range: {:#X} -> {:#X}", block.start_address, block.end_address)?; let mut var_out = String::new(); for variable in &block.variables { - let ts = type_string(tags, typedefs, &variable.kind, true)?; + let ts = type_string(info, typedefs, &variable.kind, true)?; write!( var_out, "{} {}{};", @@ -1270,7 +1332,7 @@ fn subroutine_block_string( } write!(out, "{}", indent_all_by(4, var_out))?; for block in &block.blocks { - let block_str = subroutine_block_string(tags, typedefs, block)?; + let block_str = subroutine_block_string(info, typedefs, block)?; out.push_str(&indent_all_by(4, block_str)); } writeln!(out, "}}")?; @@ -1278,7 +1340,7 @@ fn subroutine_block_string( } pub fn struct_def_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, t: &StructureType, ) -> Result { @@ -1308,7 +1370,7 @@ pub fn struct_def_string( if let Some(name) = &base.name { out.push_str(name); } else { - out.push_str(&type_name(tags, typedefs, &base.base_type)?); + out.push_str(&type_name(info, typedefs, &base.base_type)?); } } out.push_str(" {\n"); @@ -1329,12 +1391,12 @@ pub fn struct_def_string( } } let mut var_out = String::new(); - let ts = type_string(tags, typedefs, &member.kind, true)?; + let ts = type_string(info, typedefs, &member.kind, true)?; write!(var_out, "{} {}{}", ts.prefix, member.name, ts.suffix)?; if let Some(bit) = &member.bit { write!(var_out, " : {}", bit.bit_size)?; } - let size = if let Some(size) = member.byte_size { size } else { member.kind.size(tags)? }; + let size = if let Some(size) = member.byte_size { size } else { member.kind.size(info)? }; writeln!(var_out, "; // offset {:#X}, size {:#X}", member.offset, size)?; out.push_str(&indent_all_by(4, var_out)); } @@ -1354,16 +1416,16 @@ pub fn enum_def_string(t: &EnumerationType) -> Result { Ok(out) } -pub fn union_def_string(tags: &TagMap, typedefs: &TypedefMap, t: &UnionType) -> Result { +pub fn union_def_string(info: &DwarfInfo, typedefs: &TypedefMap, t: &UnionType) -> Result { let mut out = match t.name.as_ref() { Some(name) => format!("union {} {{\n", name), None => "union {\n".to_string(), }; let mut var_out = String::new(); for member in t.members.iter() { - let ts = type_string(tags, typedefs, &member.kind, true)?; + let ts = type_string(info, typedefs, &member.kind, true)?; write!(var_out, "{} {}{};", ts.prefix, member.name, ts.suffix)?; - let size = if let Some(size) = member.byte_size { size } else { member.kind.size(tags)? }; + let size = if let Some(size) = member.byte_size { size } else { member.kind.size(info)? }; write!(var_out, " // offset {:#X}, size {:#X}", member.offset, size)?; writeln!(var_out)?; } @@ -1372,18 +1434,18 @@ pub fn union_def_string(tags: &TagMap, typedefs: &TypedefMap, t: &UnionType) -> Ok(out) } -pub fn process_offset(block: &[u8]) -> Result { +pub fn process_offset(block: &[u8], e: Endian) -> Result { if block.len() == 6 && block[0] == LocationOp::Const as u8 && block[5] == LocationOp::Add as u8 { - Ok(u32::from_be_bytes(*array_ref!(block, 1, 4))) + Ok(u32::from_bytes(*array_ref!(block, 1, 4), e)) } else { Err(anyhow!("Unhandled location data, expected offset")) } } -pub fn process_address(block: &[u8]) -> Result { +pub fn process_address(block: &[u8], e: Endian) -> Result { if block.len() == 5 && block[0] == LocationOp::Address as u8 { - Ok(u32::from_be_bytes(*array_ref!(block, 1, 4))) + Ok(u32::from_bytes(*array_ref!(block, 1, 4), e)) } else { Err(anyhow!("Unhandled location data, expected address")) } @@ -1414,13 +1476,13 @@ pub const fn register_name(reg: u32) -> &'static str { } } -pub fn process_variable_location(block: &[u8]) -> Result { +pub fn process_variable_location(block: &[u8], e: Endian) -> Result { if block.len() == 5 && (block[0] == LocationOp::Register as u8 || block[0] == LocationOp::BaseRegister as u8) { - Ok(register_name(u32::from_be_bytes(*array_ref!(block, 1, 4))).to_string()) + Ok(register_name(u32::from_bytes(*array_ref!(block, 1, 4), e)).to_string()) } else if block.len() == 5 && block[0] == LocationOp::Address as u8 { - Ok(format!("@ {:#010X}", u32::from_be_bytes(*array_ref!(block, 1, 4)))) + Ok(format!("@ {:#010X}", u32::from_bytes(*array_ref!(block, 1, 4), e))) } else if block.len() == 11 && block[0] == LocationOp::BaseRegister as u8 && block[5] == LocationOp::Const as u8 @@ -1428,15 +1490,15 @@ pub fn process_variable_location(block: &[u8]) -> Result { { Ok(format!( "{}+{:#X}", - register_name(u32::from_be_bytes(*array_ref!(block, 1, 4))), - u32::from_be_bytes(*array_ref!(block, 6, 4)) + register_name(u32::from_bytes(*array_ref!(block, 1, 4), e)), + u32::from_bytes(*array_ref!(block, 6, 4), e) )) } else { Err(anyhow!("Unhandled location data {:?}, expected variable loc", block)) } } -fn process_inheritance_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_inheritance_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::Inheritance, "{:?} is not an Inheritance tag", tag.kind); let mut name = None; @@ -1454,9 +1516,9 @@ fn process_inheritance_tag(tags: &TagMap, tag: &Tag) -> Result { | AttributeKind::UserDefType | AttributeKind::ModUDType, _, - ) => base_type = Some(process_type(attr)?), + ) => base_type = Some(process_type(attr, info.e)?), (AttributeKind::Location, AttributeValue::Block(block)) => { - offset = Some(process_offset(block)?) + offset = Some(process_offset(block, info.e)?) } (AttributeKind::Private, _) => visibility = Some(Visibility::Private), (AttributeKind::Protected, _) => visibility = Some(Visibility::Protected), @@ -1468,7 +1530,7 @@ fn process_inheritance_tag(tags: &TagMap, tag: &Tag) -> Result { } } - if let Some(child) = tag.children(tags).first() { + if let Some(child) = tag.children(&info.tags).first() { bail!("Unhandled Inheritance child {:?}", child.kind); } @@ -1479,7 +1541,7 @@ fn process_inheritance_tag(tags: &TagMap, tag: &Tag) -> Result { Ok(StructureBase { name, base_type, offset, visibility, virtual_base }) } -fn process_structure_member_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_structure_member_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::Member, "{:?} is not a Member tag", tag.kind); let mut name = None; @@ -1499,9 +1561,9 @@ fn process_structure_member_tag(tags: &TagMap, tag: &Tag) -> Result member_type = Some(process_type(attr)?), + ) => member_type = Some(process_type(attr, info.e)?), (AttributeKind::Location, AttributeValue::Block(block)) => { - offset = Some(process_offset(block)?) + offset = Some(process_offset(block, info.e)?) } (AttributeKind::ByteSize, &AttributeValue::Data4(value)) => byte_size = Some(value), (AttributeKind::BitSize, &AttributeValue::Data4(value)) => bit_size = Some(value), @@ -1518,7 +1580,7 @@ fn process_structure_member_tag(tags: &TagMap, tag: &Tag) -> Result Result Result { +fn process_structure_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!( matches!(tag.kind, TagKind::StructureType | TagKind::ClassType), "{:?} is not a Structure type tag", @@ -1566,10 +1628,10 @@ fn process_structure_tag(tags: &TagMap, tag: &Tag) -> Result { let mut members = Vec::new(); let mut bases = Vec::new(); - for child in tag.children(tags) { + for child in tag.children(&info.tags) { match child.kind { - TagKind::Inheritance => bases.push(process_inheritance_tag(tags, child)?), - TagKind::Member => members.push(process_structure_member_tag(tags, child)?), + TagKind::Inheritance => bases.push(process_inheritance_tag(info, child)?), + TagKind::Member => members.push(process_structure_member_tag(info, child)?), TagKind::Typedef => { // TODO? // info!("Structure {:?} Typedef: {:?}", name, child); @@ -1603,7 +1665,7 @@ fn process_structure_tag(tags: &TagMap, tag: &Tag) -> Result { }) } -fn process_array_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_array_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::ArrayType, "{:?} is not an ArrayType tag", tag.kind); let mut subscr_data = None; @@ -1612,17 +1674,26 @@ fn process_array_tag(tags: &TagMap, tag: &Tag) -> Result { (AttributeKind::Sibling, _) => {} (AttributeKind::SubscrData, AttributeValue::Block(data)) => { subscr_data = - Some(process_array_subscript_data(data).with_context(|| { + Some(process_array_subscript_data(data, info.e).with_context(|| { format!("Failed to process SubscrData for tag: {:?}", tag) })?) } + (AttributeKind::Ordering, val) => match val { + AttributeValue::Data2(d2) => { + let order = ArrayOrdering::try_from_primitive(*d2)?; + if order == ArrayOrdering::ColMajor { + log::warn!("Column Major Ordering in Tag {}, Cannot guarantee array will be correct if original source is in different programming language.", tag.key); + } + } + _ => bail!("Unhandled ArrayType attribute {:?}", attr), + }, _ => { bail!("Unhandled ArrayType attribute {:?}", attr) } } } - if let Some(child) = tag.children(tags).first() { + if let Some(child) = tag.children(&info.tags).first() { bail!("Unhandled ArrayType child {:?}", child.kind); } @@ -1631,7 +1702,7 @@ fn process_array_tag(tags: &TagMap, tag: &Tag) -> Result { Ok(ArrayType { element_type: Box::from(element_type), dimensions }) } -fn process_array_subscript_data(data: &[u8]) -> Result<(Type, Vec)> { +fn process_array_subscript_data(data: &[u8], e: Endian) -> Result<(Type, Vec)> { let mut element_type = None; let mut dimensions = Vec::new(); let mut data = data; @@ -1643,11 +1714,11 @@ fn process_array_subscript_data(data: &[u8]) -> Result<(Type, Vec { - let index_type = FundType::try_from(u16::from_be_bytes(data[..2].try_into()?)) + let index_type = FundType::try_from(u16::from_bytes(data[..2].try_into()?, e)) .context("Invalid fundamental type ID")?; - let low_bound = u32::from_be_bytes(data[2..6].try_into()?); + let low_bound = u32::from_bytes(data[2..6].try_into()?, e); ensure!(low_bound == 0, "Invalid array low bound {low_bound}, expected 0"); - let high_bound = u32::from_be_bytes(data[6..10].try_into()?); + let high_bound = u32::from_bytes(data[6..10].try_into()?, e); data = &data[10..]; dimensions.push(ArrayDimension { index_type: Type { kind: TypeKind::Fundamental(index_type), modifiers: vec![] }, @@ -1656,13 +1727,13 @@ fn process_array_subscript_data(data: &[u8]) -> Result<(Type, Vec { - let index_type = FundType::try_from(u16::from_be_bytes(*array_ref!(data, 0, 2))) + let index_type = FundType::try_from(u16::from_bytes(*array_ref!(data, 0, 2), e)) .context("Invalid fundamental type ID")?; - let low_bound = u32::from_be_bytes(*array_ref!(data, 2, 4)); + let low_bound = u32::from_bytes(*array_ref!(data, 2, 4), e); ensure!(low_bound == 0, "Invalid array low bound {low_bound}, expected 0"); - let size = u16::from_be_bytes(*array_ref!(data, 6, 2)); + let size = u16::from_bytes(*array_ref!(data, 6, 2), e); let (block, remain) = data[8..].split_at(size as usize); - let location = if block.is_empty() { 0 } else { process_offset(block)? }; + let location = if block.is_empty() { 0 } else { process_offset(block, e)? }; data = remain; dimensions.push(ArrayDimension { index_type: Type { kind: TypeKind::Fundamental(index_type), modifiers: vec![] }, @@ -1671,8 +1742,8 @@ fn process_array_subscript_data(data: &[u8]) -> Result<(Type, Vec { let mut cursor = Cursor::new(data); - let type_attr = read_attribute(&mut cursor)?; - element_type = Some(process_type(&type_attr)?); + let type_attr = read_attribute(&mut cursor, e)?; + element_type = Some(process_type(&type_attr, e)?); data = &data[cursor.position() as usize..]; } _ => bail!("Unhandled subscript format type {:?}", format), @@ -1682,7 +1753,7 @@ fn process_array_subscript_data(data: &[u8]) -> Result<(Type, Vec Result { +fn process_enumeration_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::EnumerationType, "{:?} is not an EnumerationType tag", tag.kind); let mut name = None; @@ -1696,7 +1767,7 @@ fn process_enumeration_tag(tags: &TagMap, tag: &Tag) -> Result (AttributeKind::ElementList, AttributeValue::Block(data)) => { let mut cursor = Cursor::new(data); while cursor.position() < data.len() as u64 { - let value = i32::from_reader(&mut cursor, Endian::Big)?; + let value = i32::from_reader(&mut cursor, info.e)?; let name = read_string(&mut cursor)?; members.push(EnumerationMember { name, value }); } @@ -1707,7 +1778,7 @@ fn process_enumeration_tag(tags: &TagMap, tag: &Tag) -> Result } } - if let Some(child) = tag.children(tags).first() { + if let Some(child) = tag.children(&info.tags).first() { bail!("Unhandled EnumerationType child {:?}", child.kind); } @@ -1716,7 +1787,7 @@ fn process_enumeration_tag(tags: &TagMap, tag: &Tag) -> Result Ok(EnumerationType { name, byte_size, members }) } -fn process_union_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_union_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::UnionType, "{:?} is not a UnionType tag", tag.kind); let mut name = None; @@ -1736,9 +1807,9 @@ fn process_union_tag(tags: &TagMap, tag: &Tag) -> Result { } let mut members = Vec::new(); - for child in tag.children(tags) { + for child in tag.children(&info.tags) { match child.kind { - TagKind::Member => members.push(process_structure_member_tag(tags, child)?), + TagKind::Member => members.push(process_structure_member_tag(info, child)?), TagKind::StructureType | TagKind::ArrayType | TagKind::EnumerationType @@ -1756,7 +1827,7 @@ fn process_union_tag(tags: &TagMap, tag: &Tag) -> Result { Ok(UnionType { name, byte_size, members }) } -fn process_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_subroutine_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!( matches!( tag.kind, @@ -1786,7 +1857,7 @@ fn process_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { | AttributeKind::UserDefType | AttributeKind::ModUDType, _, - ) => return_type = Some(process_type(attr)?), + ) => return_type = Some(process_type(attr, info.e)?), (AttributeKind::Prototyped, _) => prototyped = true, (AttributeKind::LowPc, _) | (AttributeKind::HighPc, _) => { // TODO? @@ -1794,6 +1865,9 @@ fn process_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { (AttributeKind::MwGlobalRef, &AttributeValue::Reference(key)) => { references.push(key); } + (AttributeKind::MwGlobalRefsBlock, AttributeValue::Block(_)) => { + // Global references block + } (AttributeKind::ReturnAddr, AttributeValue::Block(_block)) => { // let location = process_variable_location(block)?; // info!("ReturnAddr: {}", location); @@ -1807,13 +1881,40 @@ fn process_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { (AttributeKind::MwEpilogueStart, &AttributeValue::Address(_addr)) => { // Epilogue start } + ( + AttributeKind::MwRestoreSp + | AttributeKind::MwRestoreS0 + | AttributeKind::MwRestoreS1 + | AttributeKind::MwRestoreS2 + | AttributeKind::MwRestoreS3 + | AttributeKind::MwRestoreS4 + | AttributeKind::MwRestoreS5 + | AttributeKind::MwRestoreS6 + | AttributeKind::MwRestoreS7 + | AttributeKind::MwRestoreS8 + | AttributeKind::MwRestoreF20 + | AttributeKind::MwRestoreF21 + | AttributeKind::MwRestoreF22 + | AttributeKind::MwRestoreF23 + | AttributeKind::MwRestoreF24 + | AttributeKind::MwRestoreF25 + | AttributeKind::MwRestoreF26 + | AttributeKind::MwRestoreF27 + | AttributeKind::MwRestoreF28 + | AttributeKind::MwRestoreF29 + | AttributeKind::MwRestoreF30, + AttributeValue::Block(_), + ) => { + // Restore register + } (AttributeKind::Inline, _) => inline = true, (AttributeKind::Specification, &AttributeValue::Reference(key)) => { - let spec_tag = tags + let spec_tag = info + .tags .get(&key) .ok_or_else(|| anyhow!("Failed to locate specification tag {}", key))?; // Merge attributes from specification tag - let spec = process_subroutine_tag(tags, spec_tag)?; + let spec = process_subroutine_tag(info, spec_tag)?; name = name.or(spec.name); mangled_name = mangled_name.or(spec.mangled_name); return_type = return_type.or(Some(spec.return_type)); @@ -1834,21 +1935,21 @@ fn process_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { let mut labels = Vec::new(); let mut blocks = Vec::new(); let mut inlines = Vec::new(); - for child in tag.children(tags) { + for child in tag.children(&info.tags) { ensure!(!var_args, "{:?} after UnspecifiedParameters", child.kind); match child.kind { TagKind::FormalParameter => { - parameters.push(process_subroutine_parameter_tag(tags, child)?) + parameters.push(process_subroutine_parameter_tag(info, child)?) } TagKind::UnspecifiedParameters => var_args = true, - TagKind::LocalVariable => variables.push(process_local_variable_tag(tags, child)?), + TagKind::LocalVariable => variables.push(process_local_variable_tag(info, child)?), TagKind::GlobalVariable => { // TODO GlobalVariable refs? } - TagKind::Label => labels.push(process_subroutine_label_tag(tags, child)?), - TagKind::LexicalBlock => blocks.push(process_subroutine_block_tag(tags, child)?), + TagKind::Label => labels.push(process_subroutine_label_tag(info, child)?), + TagKind::LexicalBlock => blocks.push(process_subroutine_block_tag(info, child)?), TagKind::InlinedSubroutine => { - inlines.push(process_inlined_subroutine_tag(tags, child)?) + inlines.push(process_inlined_subroutine_tag(info, child)?) } TagKind::StructureType | TagKind::ArrayType @@ -1884,7 +1985,7 @@ fn process_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { }) } -fn process_subroutine_label_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_subroutine_label_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::Label, "{:?} is not a Label tag", tag.kind); let mut name = None; @@ -1898,7 +1999,7 @@ fn process_subroutine_label_tag(tags: &TagMap, tag: &Tag) -> Result Result Result { +fn process_subroutine_block_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::LexicalBlock, "{:?} is not a LexicalBlock tag", tag.kind); let mut name = None; @@ -1925,13 +2026,13 @@ fn process_subroutine_block_tag(tags: &TagMap, tag: &Tag) -> Result variables.push(process_local_variable_tag(tags, child)?), + TagKind::LocalVariable => variables.push(process_local_variable_tag(info, child)?), TagKind::GlobalVariable => { // TODO GlobalVariable refs? } - TagKind::LexicalBlock => blocks.push(process_subroutine_block_tag(tags, child)?), + TagKind::LexicalBlock => blocks.push(process_subroutine_block_tag(info, child)?), TagKind::StructureType | TagKind::ArrayType | TagKind::EnumerationType @@ -1952,7 +2053,7 @@ fn process_subroutine_block_tag(tags: &TagMap, tag: &Tag) -> Result Result { +fn process_inlined_subroutine_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!( tag.kind == TagKind::InlinedSubroutine, "{:?} is not an InlinedSubroutine tag", @@ -1974,7 +2075,7 @@ fn process_inlined_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result { // TODO GlobalVariable refs? @@ -1992,7 +2093,7 @@ fn process_inlined_subroutine_tag(tags: &TagMap, tag: &Tag) -> Result Result { +fn process_subroutine_parameter_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::FormalParameter, "{:?} is not a FormalParameter tag", tag.kind); let mut name = None; @@ -2008,20 +2109,21 @@ fn process_subroutine_parameter_tag(tags: &TagMap, tag: &Tag) -> Result kind = Some(process_type(attr)?), + ) => kind = Some(process_type(attr, info.e)?), (AttributeKind::Location, AttributeValue::Block(block)) => { - location = Some(process_variable_location(block)?) + location = Some(process_variable_location(block, info.e)?) } (AttributeKind::MwDwarf2Location, AttributeValue::Block(_block)) => { // TODO? // info!("MwDwarf2Location: {:?} in {:?}", block, tag); } (AttributeKind::Specification, &AttributeValue::Reference(key)) => { - let spec_tag = tags + let spec_tag = info + .tags .get(&key) .ok_or_else(|| anyhow!("Failed to locate specification tag {}", key))?; // Merge attributes from specification tag - let spec = process_subroutine_parameter_tag(tags, spec_tag)?; + let spec = process_subroutine_parameter_tag(info, spec_tag)?; name = name.or(spec.name); kind = kind.or(Some(spec.kind)); location = location.or(spec.location); @@ -2030,7 +2132,7 @@ fn process_subroutine_parameter_tag(tags: &TagMap, tag: &Tag) -> Result Result Result { +fn process_local_variable_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::LocalVariable, "{:?} is not a LocalVariable tag", tag.kind); let mut name = None; @@ -2054,10 +2156,10 @@ fn process_local_variable_tag(tags: &TagMap, tag: &Tag) -> Result kind = Some(process_type(attr)?), + ) => kind = Some(process_type(attr, info.e)?), (AttributeKind::Location, AttributeValue::Block(block)) => { if !block.is_empty() { - location = Some(process_variable_location(block)?); + location = Some(process_variable_location(block, info.e)?); } } (AttributeKind::MwDwarf2Location, AttributeValue::Block(_block)) => { @@ -2065,11 +2167,12 @@ fn process_local_variable_tag(tags: &TagMap, tag: &Tag) -> Result { - let spec_tag = tags + let spec_tag = info + .tags .get(&key) .ok_or_else(|| anyhow!("Failed to locate specification tag {}", key))?; // Merge attributes from specification tag - let spec = process_local_variable_tag(tags, spec_tag)?; + let spec = process_local_variable_tag(info, spec_tag)?; name = name.or(spec.name); kind = kind.or(Some(spec.kind)); location = location.or(spec.location); @@ -2080,7 +2183,7 @@ fn process_local_variable_tag(tags: &TagMap, tag: &Tag) -> Result Result Result { +fn process_ptr_to_member_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::PtrToMemberType, "{:?} is not a PtrToMemberType tag", tag.kind); let mut kind = None; @@ -2102,7 +2205,7 @@ fn process_ptr_to_member_tag(tags: &TagMap, tag: &Tag) -> Result kind = Some(process_type(attr)?), + ) => kind = Some(process_type(attr, info.e)?), (AttributeKind::ContainingType, &AttributeValue::Reference(key)) => { containing_type = Some(key) } @@ -2112,7 +2215,7 @@ fn process_ptr_to_member_tag(tags: &TagMap, tag: &Tag) -> Result Result Result { +pub fn ud_type(info: &DwarfInfo, tag: &Tag) -> Result { match tag.kind { - TagKind::ArrayType => Ok(UserDefinedType::Array(process_array_tag(tags, tag)?)), + TagKind::ArrayType => Ok(UserDefinedType::Array(process_array_tag(info, tag)?)), TagKind::StructureType | TagKind::ClassType => { - Ok(UserDefinedType::Structure(process_structure_tag(tags, tag)?)) + Ok(UserDefinedType::Structure(process_structure_tag(info, tag)?)) } TagKind::EnumerationType => { - Ok(UserDefinedType::Enumeration(process_enumeration_tag(tags, tag)?)) + Ok(UserDefinedType::Enumeration(process_enumeration_tag(info, tag)?)) } - TagKind::UnionType => Ok(UserDefinedType::Union(process_union_tag(tags, tag)?)), + TagKind::UnionType => Ok(UserDefinedType::Union(process_union_tag(info, tag)?)), TagKind::SubroutineType | TagKind::GlobalSubroutine | TagKind::Subroutine => { - Ok(UserDefinedType::Subroutine(process_subroutine_tag(tags, tag)?)) + Ok(UserDefinedType::Subroutine(process_subroutine_tag(info, tag)?)) } TagKind::PtrToMemberType => { - Ok(UserDefinedType::PtrToMember(process_ptr_to_member_tag(tags, tag)?)) + Ok(UserDefinedType::PtrToMember(process_ptr_to_member_tag(info, tag)?)) } kind => Err(anyhow!("Unhandled user defined type {kind:?}")), } @@ -2150,7 +2253,7 @@ pub fn process_modifiers(block: &[u8]) -> Result> { Ok(out) } -pub fn process_type(attr: &Attribute) -> Result { +pub fn process_type(attr: &Attribute, e: Endian) -> Result { match (attr.kind, &attr.value) { (AttributeKind::FundType, &AttributeValue::Data2(type_id)) => { let fund_type = FundType::try_from(type_id) @@ -2158,7 +2261,7 @@ pub fn process_type(attr: &Attribute) -> Result { Ok(Type { kind: TypeKind::Fundamental(fund_type), modifiers: vec![] }) } (AttributeKind::ModFundType, AttributeValue::Block(ops)) => { - let type_id = u16::from_be_bytes(ops[ops.len() - 2..].try_into()?); + let type_id = u16::from_bytes(ops[ops.len() - 2..].try_into()?, e); let fund_type = FundType::try_from(type_id) .with_context(|| format!("Invalid fundamental type ID '{}'", type_id))?; let modifiers = process_modifiers(&ops[..ops.len() - 2])?; @@ -2168,7 +2271,7 @@ pub fn process_type(attr: &Attribute) -> Result { Ok(Type { kind: TypeKind::UserDefined(key), modifiers: vec![] }) } (AttributeKind::ModUDType, AttributeValue::Block(ops)) => { - let ud_ref = u32::from_be_bytes(ops[ops.len() - 4..].try_into()?); + let ud_ref = u32::from_bytes(ops[ops.len() - 4..].try_into()?, e); let modifiers = process_modifiers(&ops[..ops.len() - 4])?; Ok(Type { kind: TypeKind::UserDefined(ud_ref), modifiers }) } @@ -2176,11 +2279,11 @@ pub fn process_type(attr: &Attribute) -> Result { } } -pub fn process_root_tag(tags: &TagMap, tag: &Tag) -> Result { +pub fn process_root_tag(info: &DwarfInfo, tag: &Tag) -> Result { match tag.kind { - TagKind::Typedef => Ok(TagType::Typedef(process_typedef_tag(tags, tag)?)), + TagKind::Typedef => Ok(TagType::Typedef(process_typedef_tag(info, tag)?)), TagKind::GlobalVariable | TagKind::LocalVariable => { - Ok(TagType::Variable(process_variable_tag(tags, tag)?)) + Ok(TagType::Variable(process_variable_tag(info, tag)?)) } TagKind::StructureType | TagKind::ArrayType @@ -2190,7 +2293,7 @@ pub fn process_root_tag(tags: &TagMap, tag: &Tag) -> Result { | TagKind::SubroutineType | TagKind::GlobalSubroutine | TagKind::Subroutine - | TagKind::PtrToMemberType => Ok(TagType::UserDefined(ud_type(tags, tag)?)), + | TagKind::PtrToMemberType => Ok(TagType::UserDefined(ud_type(info, tag)?)), kind => Err(anyhow!("Unhandled root tag type {:?}", kind)), } } @@ -2204,12 +2307,16 @@ pub fn should_skip_tag(tag_type: &TagType) -> bool { } } -pub fn tag_type_string(tags: &TagMap, typedefs: &TypedefMap, tag_type: &TagType) -> Result { +pub fn tag_type_string( + info: &DwarfInfo, + typedefs: &TypedefMap, + tag_type: &TagType, +) -> Result { match tag_type { - TagType::Typedef(t) => typedef_string(tags, typedefs, t), - TagType::Variable(v) => variable_string(tags, typedefs, v, true), + TagType::Typedef(t) => typedef_string(info, typedefs, t), + TagType::Variable(v) => variable_string(info, typedefs, v, true), TagType::UserDefined(ud) => { - let ud_str = ud_type_def(tags, typedefs, ud)?; + let ud_str = ud_type_def(info, typedefs, ud)?; match ud { UserDefinedType::Structure(_) | UserDefinedType::Enumeration(_) @@ -2220,18 +2327,18 @@ pub fn tag_type_string(tags: &TagMap, typedefs: &TypedefMap, tag_type: &TagType) } } -fn typedef_string(tags: &TagMap, typedefs: &TypedefMap, typedef: &TypedefTag) -> Result { - let ts = type_string(tags, typedefs, &typedef.kind, true)?; +fn typedef_string(info: &DwarfInfo, typedefs: &TypedefMap, typedef: &TypedefTag) -> Result { + let ts = type_string(info, typedefs, &typedef.kind, true)?; Ok(format!("typedef {} {}{};", ts.prefix, typedef.name, ts.suffix)) } fn variable_string( - tags: &TagMap, + info: &DwarfInfo, typedefs: &TypedefMap, variable: &VariableTag, include_extra: bool, ) -> Result { - let ts = type_string(tags, typedefs, &variable.kind, include_extra)?; + let ts = type_string(info, typedefs, &variable.kind, include_extra)?; let mut out = if variable.local { "static ".to_string() } else { String::new() }; out.push_str(&ts.prefix); out.push(' '); @@ -2243,13 +2350,13 @@ fn variable_string( } out.push(';'); if include_extra { - let size = variable.kind.size(tags)?; + let size = variable.kind.size(info)?; out.push_str(&format!(" // size: {:#X}", size)); } Ok(out) } -fn process_typedef_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_typedef_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!(tag.kind == TagKind::Typedef, "{:?} is not a typedef tag", tag.kind); let mut name = None; @@ -2264,14 +2371,14 @@ fn process_typedef_tag(tags: &TagMap, tag: &Tag) -> Result { | AttributeKind::UserDefType | AttributeKind::ModUDType, _, - ) => kind = Some(process_type(attr)?), + ) => kind = Some(process_type(attr, info.e)?), _ => { bail!("Unhandled Typedef attribute {:?}", attr); } } } - if let Some(child) = tag.children(tags).first() { + if let Some(child) = tag.children(&info.tags).first() { bail!("Unhandled Typedef child {:?}", child.kind); } @@ -2280,7 +2387,7 @@ fn process_typedef_tag(tags: &TagMap, tag: &Tag) -> Result { Ok(TypedefTag { name, kind }) } -fn process_variable_tag(tags: &TagMap, tag: &Tag) -> Result { +fn process_variable_tag(info: &DwarfInfo, tag: &Tag) -> Result { ensure!( matches!(tag.kind, TagKind::GlobalVariable | TagKind::LocalVariable), "{:?} is not a variable tag", @@ -2302,9 +2409,9 @@ fn process_variable_tag(tags: &TagMap, tag: &Tag) -> Result { | AttributeKind::UserDefType | AttributeKind::ModUDType, _, - ) => kind = Some(process_type(attr)?), + ) => kind = Some(process_type(attr, info.e)?), (AttributeKind::Location, AttributeValue::Block(block)) => { - address = Some(process_address(block)?) + address = Some(process_address(block, info.e)?) } _ => { bail!("Unhandled Variable attribute {:?}", attr); @@ -2312,7 +2419,7 @@ fn process_variable_tag(tags: &TagMap, tag: &Tag) -> Result { } } - if let Some(child) = tag.children(tags).first() { + if let Some(child) = tag.children(&info.tags).first() { bail!("Unhandled Variable child {:?}", child.kind); } diff --git a/src/util/reader.rs b/src/util/reader.rs index f0ccfdd..db8f264 100644 --- a/src/util/reader.rs +++ b/src/util/reader.rs @@ -11,6 +11,15 @@ pub enum Endian { Little, } +impl From for Endian { + fn from(value: object::Endianness) -> Self { + match value { + object::Endianness::Big => Endian::Big, + object::Endianness::Little => Endian::Little, + } + } +} + pub const DYNAMIC_SIZE: usize = 0; pub const fn struct_size(fields: [usize; N]) -> usize { @@ -52,9 +61,23 @@ pub trait FromReader: Sized { } } +pub trait FromBytes: Sized { + fn from_bytes(bytes: [u8; N], e: Endian) -> Self; +} + macro_rules! impl_from_reader { ($($t:ty),*) => { $( + impl FromBytes<{ <$t>::STATIC_SIZE }> for $t { + #[inline] + fn from_bytes(bytes: [u8; Self::STATIC_SIZE], e: Endian) -> Self { + match e { + Endian::Big => Self::from_be_bytes(bytes), + Endian::Little => Self::from_le_bytes(bytes), + } + } + } + impl FromReader for $t { const STATIC_SIZE: usize = std::mem::size_of::(); @@ -65,10 +88,7 @@ macro_rules! impl_from_reader { where R: Read + Seek + ?Sized { let mut buf = [0u8; Self::STATIC_SIZE]; reader.read_exact(&mut buf)?; - Ok(match e { - Endian::Big => Self::from_be_bytes(buf), - Endian::Little => Self::from_le_bytes(buf), - }) + Ok(Self::from_bytes(buf, e)) } } )*