diff --git a/src/debuginfo/dwarf/mod.rs b/src/debuginfo/dwarf/mod.rs index 75f069f..2aebf7d 100644 --- a/src/debuginfo/dwarf/mod.rs +++ b/src/debuginfo/dwarf/mod.rs @@ -421,13 +421,13 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); if let TypeInfo { datatype: - DbgDataType::Class { + DbgDataType::Struct { inheritance, members, .. @@ -467,6 +467,10 @@ mod test { _ )) )); + // "static unsigned long class_static" has no storage inside the class. + // Dwarf 3 describes it as a DW_TAG_member with DW_AT_declaration and no + // location; it must not be treated as a member of the class. + assert!(members.get("class_static").is_none()); } let varinfo = debugdata.variables.get("class2").unwrap(); @@ -474,7 +478,7 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); @@ -484,7 +488,7 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); @@ -494,7 +498,7 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); @@ -514,17 +518,28 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Struct { .. }, + datatype: DbgDataType::Struct { is_class: false, .. }, .. } )); + if let TypeInfo { + datatype: DbgDataType::Struct { members, .. }, + .. + } = typeinfo + { + // val2 and val3 are members of an anonymous union, so they are transferred + // into the containing struct. Some compilers omit DW_AT_data_member_location + // for union members, because all of them are at offset zero. + assert!(matches!(members.get("val2"), Some((_, 4)))); + assert!(matches!(members.get("val3"), Some((_, 4)))); + } let varinfo = debugdata.variables.get("bitfield").unwrap(); let typeinfo = debugdata.types.get(&varinfo[0].typeref).unwrap(); assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Struct { .. }, + datatype: DbgDataType::Struct { is_class: false, .. }, .. } )); diff --git a/src/debuginfo/dwarf/typereader.rs b/src/debuginfo/dwarf/typereader.rs index 3156641..9e7c68c 100644 --- a/src/debuginfo/dwarf/typereader.rs +++ b/src/debuginfo/dwarf/typereader.rs @@ -6,6 +6,10 @@ use object::Endianness; use std::collections::HashMap; use std::num::Wrapping; +/// maps the name of a struct member or base class to its type and its offset +/// inside the containing type +type MemberMap = IndexMap; + #[derive(Debug)] struct WipItemInfo { offset: usize, @@ -198,24 +202,18 @@ impl DebugDataReader<'_> { self.get_enumeration_type(current_unit, offset, typereader_data)?, None, ), - gimli::constants::DW_TAG_structure_type => { - let size = get_byte_size_attribute(entry) - .ok_or_else(|| "missing struct byte size attribute".to_string())?; - let members = self.get_struct_or_union_members( - entries_tree_node, - current_unit, - typereader_data, - )?; - (DbgDataType::Struct { size, members }, None) - } + gimli::constants::DW_TAG_structure_type => ( + self.get_struct_or_class_type(false, current_unit, offset, typereader_data)?, + None, + ), gimli::constants::DW_TAG_class_type => ( - self.get_class_type(current_unit, offset, typereader_data)?, + self.get_struct_or_class_type(true, current_unit, offset, typereader_data)?, None, ), gimli::constants::DW_TAG_union_type => { let size = get_byte_size_attribute(entry) .ok_or_else(|| "missing union byte size attribute".to_string())?; - let members = self.get_struct_or_union_members( + let (members, _) = self.get_struct_or_union_members( entries_tree_node, current_unit, typereader_data, @@ -506,12 +504,18 @@ impl DebugDataReader<'_> { }) } - fn get_class_type( + /// Read a struct or class type. + /// Structs and classes are handled identically: in C++ both can have base classes + /// and members, and the debug info describes them in the same way. Only the wording + /// of messages differs, which is what `is_class` is used for. + fn get_struct_or_class_type( &self, + is_class: bool, current_unit: usize, offset: UnitOffset, typereader_data: &mut TypeReaderData, ) -> Result { + let kind = if is_class { "class" } else { "struct" }; let (unit, abbrev) = &self.units[current_unit]; let mut entries_tree = unit .entries_tree(abbrev, Some(offset)) @@ -520,21 +524,13 @@ impl DebugDataReader<'_> { let entry = entries_tree_node.entry(); let size = get_byte_size_attribute(entry) - .ok_or_else(|| "missing class byte size attribute".to_string())?; - let (unit, abbrev) = &self.units[current_unit]; - let mut entries_tree2 = unit - .entries_tree(abbrev, Some(entries_tree_node.entry().offset())) - .unwrap(); - let entries_tree_node2 = entries_tree2.root().unwrap(); - let inheritance = self - .get_class_inheritance(entries_tree_node2, current_unit, typereader_data) - .unwrap_or_default(); - let mut members = + .ok_or_else(|| format!("missing {kind} byte size attribute"))?; + let (mut members, inheritance) = self.get_struct_or_union_members(entries_tree_node, current_unit, typereader_data)?; // copy all inherited members from the base classes // this allows the inherited members ot be accessed without naming the base class for (baseclass_type, baseclass_offset) in inheritance.values() { - if let DbgDataType::Class { + if let DbgDataType::Struct { members: baseclass_members, .. } = &baseclass_type.datatype @@ -550,30 +546,49 @@ impl DebugDataReader<'_> { } } } - Ok(DbgDataType::Class { + Ok(DbgDataType::Struct { size, + is_class, inheritance, members, }) } - // get all the members of a struct or union or class + /// get all the members and base classes of a struct or union or class + /// Unions never have base classes, so the returned inheritance map is empty for them. fn get_struct_or_union_members( &self, entries_tree: EntriesTreeNode>, current_unit: usize, typereader_data: &mut TypeReaderData, - ) -> Result, String> { + ) -> Result<(MemberMap, MemberMap), String> { let (unit, _) = &self.units[current_unit]; - let mut members = IndexMap::::new(); + let mut members = MemberMap::new(); + let mut inheritance = MemberMap::new(); let mut iter = entries_tree.children(); while let Ok(Some(child_node)) = iter.next() { let child_entry = child_node.entry(); - if child_entry.tag() == gimli::constants::DW_TAG_member { + if child_entry.tag() == gimli::constants::DW_TAG_inheritance { + // failing to read one base class should not make the whole type unusable, + // so errors are silently ignored here + if let Ok((name, baseclass_type, baseclass_offset)) = + self.get_inherited_class(child_entry, current_unit, typereader_data) + { + inheritance.insert(name, (baseclass_type, baseclass_offset)); + } + } else if child_entry.tag() == gimli::constants::DW_TAG_member { + // Static and constexpr data members are only declared inside the struct: they have + // no storage of their own and are not part of the struct's layout, so skip them. + if get_declaration_attribute(child_entry).unwrap_or(false) { + continue; + } + // the name can be missing if this struct/union contains an anonymous struct/union - let opt_name = get_name_attribute(child_entry, &self.dwarf, unit) - .map_err(|_| "missing struct/union member name".to_string()); + let opt_name = get_name_attribute(child_entry, &self.dwarf, unit).ok(); + // Union members and Dwarf 4/5 bitfields have no DW_AT_data_member_location. + // Zero is the correct default for union members; for bitfields the byte offset is + // derived from DW_AT_data_bit_offset in get_bitfield_entry() below. let mut offset = get_data_member_location_attribute( self, child_entry, @@ -598,15 +613,15 @@ impl DebugDataReader<'_> { membertype, ); } - if let Ok(name) = opt_name { + if let Some(name) = opt_name { // in bitfields it's actually possible for the name to be empty! // "int :31;" is valid C! if !name.is_empty() { // refer to the loaded type instead of duplicating it in the members - if matches!(membertype.datatype, DbgDataType::Struct { .. }) - || matches!(membertype.datatype, DbgDataType::Union { .. }) - || matches!(membertype.datatype, DbgDataType::Class { .. }) - { + if matches!( + membertype.datatype, + DbgDataType::Struct { .. } | DbgDataType::Union { .. } + ) { membertype.datatype = DbgDataType::TypeRef( new_dbginfo_offset.0, membertype.get_size(), @@ -618,11 +633,7 @@ impl DebugDataReader<'_> { // no name: the member is an anon struct / union // In this case, the contained members are transferred match membertype.datatype { - DbgDataType::Class { - members: anon_members, - .. - } - | DbgDataType::Struct { + DbgDataType::Struct { members: anon_members, .. } @@ -640,7 +651,7 @@ impl DebugDataReader<'_> { } } } - Ok(members) + Ok((members, inheritance)) } fn get_bitfield_entry( @@ -718,55 +729,43 @@ impl DebugDataReader<'_> { } } - // get all the members of a struct or union or class - fn get_class_inheritance( + /// read one `DW_TAG_inheritance` entry, i.e. one base class of a struct or class, + /// and return its name, type and offset inside the derived type + fn get_inherited_class( &self, - entries_tree: EntriesTreeNode>, + child_entry: &gimli::DebuggingInformationEntry, usize>, current_unit: usize, typereader_data: &mut TypeReaderData, - ) -> Result, String> { + ) -> Result<(String, TypeInfo, u64), String> { let (unit, _) = &self.units[current_unit]; - let mut inheritance = IndexMap::::new(); - let mut iter = entries_tree.children(); - while let Ok(Some(child_node)) = iter.next() { - let child_entry = child_node.entry(); - if child_entry.tag() == gimli::constants::DW_TAG_inheritance { - let data_location = get_data_member_location_attribute( - self, - child_entry, - unit.encoding(), - current_unit, - ) + let data_location = + get_data_member_location_attribute(self, child_entry, unit.encoding(), current_unit) .ok_or_else(|| "missing byte offset for inherited class".to_string())?; - let Some((new_cur_unit, new_dbginfo_offset)) = - get_type_attribute(child_entry, &self.units, current_unit)? - else { - // a member whose type is "nothing"? Skip it - continue; - }; + let Some((new_cur_unit, new_dbginfo_offset)) = + get_type_attribute(child_entry, &self.units, current_unit)? + else { + // a base class whose type is "nothing"? + return Err("missing type for inherited class".to_string()); + }; - let (unit, abbrev) = &self.units[new_cur_unit]; - let new_unit_offset = new_dbginfo_offset.to_unit_offset(unit).ok_or_else(|| { - format!( - "invalid type offset 0x{:X} for unit {}", - new_dbginfo_offset.0, new_cur_unit - ) - })?; - let mut baseclass_tree = unit - .entries_tree(abbrev, Some(new_unit_offset)) - .map_err(|err| err.to_string())?; - let baseclass_tree_node = baseclass_tree.root().map_err(|err| err.to_string())?; - let baseclass_entry = baseclass_tree_node.entry(); - let baseclass_name = get_name_attribute(baseclass_entry, &self.dwarf, unit)?; - - let baseclass_type = - self.get_type(new_cur_unit, new_dbginfo_offset, typereader_data)?; - - inheritance.insert(baseclass_name, (baseclass_type, data_location)); - } - } - Ok(inheritance) + let (unit, abbrev) = &self.units[new_cur_unit]; + let new_unit_offset = new_dbginfo_offset.to_unit_offset(unit).ok_or_else(|| { + format!( + "invalid type offset 0x{:X} for unit {}", + new_dbginfo_offset.0, new_cur_unit + ) + })?; + let mut baseclass_tree = unit + .entries_tree(abbrev, Some(new_unit_offset)) + .map_err(|err| err.to_string())?; + let baseclass_tree_node = baseclass_tree.root().map_err(|err| err.to_string())?; + let baseclass_entry = baseclass_tree_node.entry(); + let baseclass_name = get_name_attribute(baseclass_entry, &self.dwarf, unit)?; + + let baseclass_type = self.get_type(new_cur_unit, new_dbginfo_offset, typereader_data)?; + + Ok((baseclass_name, baseclass_type, data_location)) } } diff --git a/src/debuginfo/iter.rs b/src/debuginfo/iter.rs index bad4695..d9c28e3 100644 --- a/src/debuginfo/iter.rs +++ b/src/debuginfo/iter.rs @@ -52,9 +52,7 @@ impl<'dbg> TypeInfoIter<'dbg> { fn next_core(&mut self) -> Option<(String, &'dbg TypeInfo, u64)> { match &self.type_stack.last()?.datatype { - DbgDataType::Class { members, .. } - | DbgDataType::Struct { members, .. } - | DbgDataType::Union { members, .. } => { + DbgDataType::Struct { members, .. } | DbgDataType::Union { members, .. } => { let depth = self.type_stack.len() - 1; let position = self.position_stack[depth]; let base = self.offset_stack[depth]; @@ -289,6 +287,8 @@ mod test { let typeinfo_inner_1 = TypeInfo { datatype: DbgDataType::Struct { size: 64, + is_class: false, + inheritance: IndexMap::new(), members: structmembers_a, }, ..DEFAULT_TYPEINFO.clone() @@ -300,6 +300,8 @@ mod test { let typeinfo_inner_2 = TypeInfo { datatype: DbgDataType::Struct { size: 64, + is_class: false, + inheritance: IndexMap::new(), members: structmembers_b, }, ..DEFAULT_TYPEINFO.clone() @@ -320,6 +322,8 @@ mod test { let typeinfo = TypeInfo { datatype: DbgDataType::Struct { size: 64, + is_class: false, + inheritance: IndexMap::new(), members: structmembers, }, ..DEFAULT_TYPEINFO.clone() @@ -392,6 +396,8 @@ mod test { let structtype = TypeInfo { datatype: DbgDataType::Struct { size: 64, + is_class: false, + inheritance: IndexMap::new(), members: structmembers, }, ..DEFAULT_TYPEINFO.clone() diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index f960349..606a0c8 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -42,12 +42,11 @@ pub(crate) enum DbgDataType { bit_size: u16, }, Pointer(u64, usize), + /// A struct or a class. In this code there is no practical difference + /// between them; `is_class` only affects the displayed name. Struct { size: u64, - members: IndexMap, - }, - Class { - size: u64, + is_class: bool, inheritance: IndexMap, members: IndexMap, }, @@ -130,7 +129,6 @@ impl TypeInfo { DbgDataType::Pointer(size, _) | DbgDataType::Other(size) | DbgDataType::Struct { size, .. } - | DbgDataType::Class { size, .. } | DbgDataType::Union { size, .. } | DbgDataType::Enum { size, .. } | DbgDataType::Array { size, .. } @@ -141,9 +139,9 @@ impl TypeInfo { pub(crate) fn get_members(&self) -> Option<&IndexMap> { match &self.datatype { - DbgDataType::Struct { members, .. } - | DbgDataType::Class { members, .. } - | DbgDataType::Union { members, .. } => Some(members), + DbgDataType::Struct { members, .. } | DbgDataType::Union { members, .. } => { + Some(members) + } _ => None, } @@ -310,35 +308,32 @@ impl TypeInfo { && basetype.compare_internal(basetype2, types, depth + 1) } ( - DbgDataType::Struct { size, members }, DbgDataType::Struct { - size: size2, - members: members2, - }, - ) => size == size2 && Self::compare_members(members, members2, types, depth), - ( - DbgDataType::Union { size, members }, - DbgDataType::Union { - size: size2, - members: members2, - }, - ) => size == size2 && Self::compare_members(members, members2, types, depth), - ( - DbgDataType::Class { size, members, inheritance, + .. }, - DbgDataType::Class { + DbgDataType::Struct { size: size2, members: members2, inheritance: inheritance2, + .. }, ) => { + // is_class is deliberately not compared: a struct and a class with + // identical layout are interchangeable size == size2 && Self::compare_members(members, members2, types, depth) && Self::compare_members(inheritance, inheritance2, types, depth) } + ( + DbgDataType::Union { size, members }, + DbgDataType::Union { + size: size2, + members: members2, + }, + ) => size == size2 && Self::compare_members(members, members2, types, depth), (DbgDataType::FuncPtr(size1), DbgDataType::FuncPtr(size2)) => size1 == size2, _ => false, }) @@ -396,18 +391,14 @@ impl Display for TypeInfo { DbgDataType::Pointer(_, _) => write!(f, "Pointer(...)"), DbgDataType::Other(osize) => write!(f, "Other({osize})"), DbgDataType::FuncPtr(osize) => write!(f, "function pointer({osize})"), - DbgDataType::Struct { members, .. } => { - if let Some(name) = &self.name { - write!(f, "Struct {name}({} members)", members.len()) - } else { - write!(f, "Struct ({} members)", members.len()) - } - } - DbgDataType::Class { members, .. } => { + DbgDataType::Struct { + members, is_class, .. + } => { + let kind = if *is_class { "Class" } else { "Struct" }; if let Some(name) = &self.name { - write!(f, "Class {name}({} members)", members.len()) + write!(f, "{kind} {name}({} members)", members.len()) } else { - write!(f, "Class ({} members)", members.len()) + write!(f, "{kind} ({} members)", members.len()) } } DbgDataType::Union { members, .. } => { diff --git a/src/debuginfo/pdb/mod.rs b/src/debuginfo/pdb/mod.rs index b94c764..e5f13dd 100644 --- a/src/debuginfo/pdb/mod.rs +++ b/src/debuginfo/pdb/mod.rs @@ -262,13 +262,13 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); if let TypeInfo { datatype: - DbgDataType::Class { + DbgDataType::Struct { inheritance, members, .. @@ -315,7 +315,7 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); @@ -325,7 +325,7 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); @@ -335,7 +335,7 @@ mod test { assert!(matches!( typeinfo, TypeInfo { - datatype: DbgDataType::Class { .. }, + datatype: DbgDataType::Struct { is_class: true, .. }, .. } )); diff --git a/src/debuginfo/pdb/typereader.rs b/src/debuginfo/pdb/typereader.rs index d51b508..a601d58 100644 --- a/src/debuginfo/pdb/typereader.rs +++ b/src/debuginfo/pdb/typereader.rs @@ -217,6 +217,8 @@ fn read_type_from_typedata( read_forward_referenced_type(type_index, typereader_data, pdb_data)?.unwrap_or(( DbgDataType::Struct { size: class_type.size, + is_class: is_class(class_type), + inheritance: IndexMap::new(), members: IndexMap::new(), }, None, @@ -359,66 +361,65 @@ fn read_forward_referenced_type( } } +/// Both `struct` and `class` are represented as `TypeData::Class` in a PDB file; +/// only `kind` distinguishes them, and it only affects the displayed name. +fn is_class(class_type: &pdb2::ClassType<'_>) -> bool { + !matches!(class_type.kind, pdb2::ClassKind::Struct) +} + fn read_class( class_type: &pdb2::ClassType<'_>, typereader_data: &mut TypeReaderData, pdb_data: &PdbData<'_>, ) -> Result<(DbgDataType, Option), String> { let size = class_type.size; - let fields_index = class_type.fields.map(|tidx| tidx.0); - let datatype = if let Some(fields_index) = fields_index { - let mut members = read_fields(fields_index, typereader_data, pdb_data)?; - let inheritance = read_class_inheritance(fields_index, typereader_data, pdb_data)?; - - if inheritance.is_empty() { - DbgDataType::Struct { size, members } - } else { - // copy all inherited members from the base classes - // this allows the inherited members ot be accessed without naming the base class - for (baseclass_type, baseclass_offset) in inheritance.values() { - match &baseclass_type.datatype { - DbgDataType::Struct { - members: baseclass_members, - .. - } - | DbgDataType::Class { - members: baseclass_members, - .. - } => { - for (name, (m_type, m_offset)) in baseclass_members { - if !members.contains_key(name) { - // if the derived class has a member with the same name as an inherited member, the derived class member takes precedence - members.insert( - name.clone(), - (m_type.clone(), m_offset + baseclass_offset), - ); - } - } - } - _ => { - return Err(format!( - "Base class type 0x{:?} is not a struct or class", - baseclass_type.datatype - )); - } - } - } - - DbgDataType::Class { + let is_class = is_class(class_type); + let Some(fields_index) = class_type.fields.map(|tidx| tidx.0) else { + // empty struct / class + return Ok(( + DbgDataType::Struct { size, - members, - inheritance, + is_class, + inheritance: IndexMap::new(), + members: IndexMap::new(), + }, + None, + )); + }; + + let mut members = read_fields(fields_index, typereader_data, pdb_data)?; + let inheritance = read_class_inheritance(fields_index, typereader_data, pdb_data)?; + + // copy all inherited members from the base classes + // this allows the inherited members ot be accessed without naming the base class + for (baseclass_type, baseclass_offset) in inheritance.values() { + let DbgDataType::Struct { + members: baseclass_members, + .. + } = &baseclass_type.datatype + else { + return Err(format!( + "Base class type 0x{:?} is not a struct or class", + baseclass_type.datatype + )); + }; + for (name, (m_type, m_offset)) in baseclass_members { + if !members.contains_key(name) { + // if the derived class has a member with the same name as an inherited member, the derived class member takes precedence + members.insert(name.clone(), (m_type.clone(), m_offset + baseclass_offset)); } } - } else { - // empty struct / class + } + + Ok(( DbgDataType::Struct { size, - members: IndexMap::new(), - } - }; - - Ok((datatype, None)) + is_class, + inheritance, + members, + }, + None, + )) } fn read_union( @@ -470,9 +471,7 @@ fn read_fields( let typeinfo = if matches!( member_typeinfo.datatype, - DbgDataType::Struct { .. } - | DbgDataType::Class { .. } - | DbgDataType::Union { .. } + DbgDataType::Struct { .. } | DbgDataType::Union { .. } ) { // create a reference to the type instead of embedding it let name = member_typeinfo.name.clone(); diff --git a/src/insert.rs b/src/insert.rs index c05f12f..157f12c 100644 --- a/src/insert.rs +++ b/src/insert.rs @@ -601,7 +601,6 @@ pub(crate) fn insert_many<'param>( DbgDataType::Other(_) | DbgDataType::Pointer(_, _) | DbgDataType::Struct { .. } - | DbgDataType::Class { .. } | DbgDataType::Union { .. } => { if enable_structures && check_and_insert_instance(&mut isupp, &sym_info, log_msgs) { skip_children = true; diff --git a/src/symbol.rs b/src/symbol.rs index afe49af..d10de20 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -249,7 +249,7 @@ fn find_membertype<'a>( Ok((address, typeinfo)) } else { match &typeinfo.datatype { - DbgDataType::Class { + DbgDataType::Struct { members, inheritance, .. @@ -285,7 +285,7 @@ fn find_membertype<'a>( )) } } - DbgDataType::Struct { members, .. } | DbgDataType::Union { members, .. } => { + DbgDataType::Union { members, .. } => { if let Some((membertype, offset)) = members.get(components[component_index]) { let membertype = membertype.get_reference(&debug_data.types); find_membertype( @@ -540,6 +540,8 @@ mod test { TypeInfo { datatype: DbgDataType::Struct { members: structmembers, + is_class: false, + inheritance: IndexMap::new(), size: 4, }, unit_idx: 0, diff --git a/src/update/typedef.rs b/src/update/typedef.rs index 7336e18..99a10a8 100644 --- a/src/update/typedef.rs +++ b/src/update/typedef.rs @@ -1246,9 +1246,7 @@ impl<'dbg, 'a2l, 'rl, 'log> TypedefUpdater<'dbg, 'a2l, 'rl, 'log> { .map_or(typeinfo, |(_, t)| t); match &typeinfo.datatype { - DbgDataType::Struct { members, .. } - | DbgDataType::Union { members, .. } - | DbgDataType::Class { members, .. } => { + DbgDataType::Struct { members, .. } | DbgDataType::Union { members, .. } => { // typical case: the data type of the typedef struct is "structlike" and has a list of members self.update_typedef_struct_content(td_struct, members, enum_convlist, is_calib); } @@ -1605,10 +1603,7 @@ fn is_structure_typeinfo(typeinfo: &TypeInfo, types: &HashMap) false } } - DbgDataType::Struct { .. } - | DbgDataType::Class { .. } - | DbgDataType::Union { .. } - | DbgDataType::Array { .. } => true, + DbgDataType::Struct { .. } | DbgDataType::Union { .. } | DbgDataType::Array { .. } => true, _ => false, } } @@ -1643,7 +1638,6 @@ fn is_measurement_typeinfo(typeinfo: &TypeInfo, types: &HashMap } DbgDataType::Other(_) | DbgDataType::Struct { .. } - | DbgDataType::Class { .. } | DbgDataType::Union { .. } | DbgDataType::Array { .. } | DbgDataType::TypeRef(_, _) => false, @@ -1735,14 +1729,13 @@ fn make_typedef_name(debug_data: &DebugData, typeinfo: &TypeInfo, is_calib: bool outstr.push_str(&basename); outstr } - DbgDataType::Struct { .. } => typeinfo - .name - .as_deref() - .unwrap_or("_unnamed_struct_") - .to_string(), - DbgDataType::Class { .. } => { - // there is no such thing as an unnamed class - typeinfo.name.clone().unwrap() + DbgDataType::Struct { is_class, .. } => { + let fallback = if *is_class { + "_unnamed_class_" + } else { + "_unnamed_struct_" + }; + typeinfo.name.as_deref().unwrap_or(fallback).to_string() } DbgDataType::Union { .. } => typeinfo .name