diff options
| author | Mason Reed <mason@vector35.com> | 2025-09-21 21:51:37 -0400 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2025-10-23 14:29:15 -0400 |
| commit | c35849163319ee606a28eb4d8bfd585b1f4eddcf (patch) | |
| tree | b6e2269effe50de773aecf71fca3f71801067ead /plugins/dwarf | |
| parent | 24e66649863d724aa532ff884c6f27c141a0eede (diff) | |
Support bitfields in type system
Also adds support for parsing bitfields in PDB, DWARF and SVD plugins
WIP: API needs to be considered more, also need to find type related apis that may need to be rethought.
Diffstat (limited to 'plugins/dwarf')
| -rw-r--r-- | plugins/dwarf/dwarf_import/src/types.rs | 94 |
1 files changed, 59 insertions, 35 deletions
diff --git a/plugins/dwarf/dwarf_import/src/types.rs b/plugins/dwarf/dwarf_import/src/types.rs index 38f0dbc0..f870707b 100644 --- a/plugins/dwarf/dwarf_import/src/types.rs +++ b/plugins/dwarf/dwarf_import/src/types.rs @@ -24,7 +24,7 @@ use binaryninja::{ }, }; -use gimli::{constants, AttributeValue, DebuggingInformationEntry, Dwarf, Operation, Unit}; +use gimli::{constants, AttributeValue, DebuggingInformationEntry, DwAt, Dwarf, Operation, Unit}; use log::{debug, error, warn}; @@ -220,10 +220,6 @@ fn do_structure_parse<R: ReaderType>( continue; }; - /* - TODO: apply correct member size when that's supported - let child_type_width = get_size_as_u64(child_entry).unwrap_or_else(|| child_type.width()); - */ if let Ok(Some(raw_struct_offset)) = child_entry.attr(constants::DW_AT_data_member_location) { @@ -246,36 +242,65 @@ fn do_structure_parse<R: ReaderType>( MemberAccess::NoAccess, // TODO : Resolve actual scopes, if possible MemberScope::NoScope, ); - } else if let Ok(Some(raw_struct_offset_bits)) = - child_entry.attr(constants::DW_AT_data_bit_offset) - { - //TODO: support misaligned offsets when bitwise data structures get in - let Some(struct_offset_bits) = get_attr_as_u64(&raw_struct_offset_bits) - .or_else(|| get_expr_value(unit, raw_struct_offset_bits)) - else { - log::warn!( - "Failed to get DW_AT_data_bit_offset for offset {:#x} in unit {:?}", - child_entry.offset().0, - unit.header.offset() - ); - continue; - }; - - structure_builder.insert( - &child_type, - &child_name, - struct_offset_bits / 8, - false, - MemberAccess::NoAccess, // TODO : Resolve actual scopes, if possible - MemberScope::NoScope, - ); } else { - structure_builder.append( - &child_type, - &child_name, - MemberAccess::NoAccess, - MemberScope::NoScope, - ); + let select_value = + |e: &DebuggingInformationEntry<R>, attr: DwAt| -> Option<u64> { + get_attr_as_u64(&e.attr(attr).ok()??) + }; + + // If no byte offset, try the bitfield using DW_AT_bit_offset/DW_AT_data_bit_offset + DW_AT_bit_size + let bit_size = select_value(child_entry, constants::DW_AT_bit_size); + let bit_offset = select_value(child_entry, constants::DW_AT_bit_offset); + let data_bit_offset = + select_value(child_entry, constants::DW_AT_data_bit_offset); + + match (bit_size, bit_offset, data_bit_offset) { + (Some(bit_size), Some(bit_offset), _) => { + // Heuristic storage unit bits from the member type width (bytes -> bits). Fallback to 8. + let storage_bits = { + let w = child_type.width(); + if w > 0 { + w * 8 + } else { + 8 + } + }; + + // DW_AT_bit_offset is from the MSB of the storage unit: + // absolute = base_byte_off*8 + storage_bits - (boffs + bit_sz) + // With no base_byte_off available here, treat base as 0. + let total_bit_off = storage_bits.saturating_sub(bit_offset + bit_size); + + structure_builder.insert_bitwise( + &child_type, + &child_name, + total_bit_off, + Some(bit_size as u8), + false, + MemberAccess::NoAccess, + MemberScope::NoScope, + ); + } + (Some(bit_size), None, Some(data_bit_offset)) => { + structure_builder.insert_bitwise( + &child_type, + &child_name, + data_bit_offset, + Some(bit_size as u8), + false, + MemberAccess::NoAccess, + MemberScope::NoScope, + ); + } + _ => { + structure_builder.append( + &child_type, + &child_name, + MemberAccess::NoAccess, + MemberScope::NoScope, + ); + } + } } } constants::DW_TAG_inheritance => { @@ -316,7 +341,6 @@ fn do_structure_parse<R: ReaderType>( structure_builder.base_structures(&base_structures); let finalized_structure = Type::structure(&structure_builder.finalize()); - if let Some(full_name) = full_name { debug_info_builder.add_type( get_uid(dwarf, unit, entry) + 1, // TODO : This is super broke (uid + 1 is not guaranteed to be unique) |
