@@ -24,7 +24,7 @@ use binaryninja::{
2424 } ,
2525} ;
2626
27- use gimli:: { constants, AttributeValue , DebuggingInformationEntry , Dwarf , Operation , Unit } ;
27+ use gimli:: { constants, AttributeValue , DebuggingInformationEntry , DwAt , Dwarf , Operation , Unit } ;
2828
2929use log:: { debug, error, warn} ;
3030
@@ -220,10 +220,6 @@ fn do_structure_parse<R: ReaderType>(
220220 continue ;
221221 } ;
222222
223- /*
224- TODO: apply correct member size when that's supported
225- let child_type_width = get_size_as_u64(child_entry).unwrap_or_else(|| child_type.width());
226- */
227223 if let Ok ( Some ( raw_struct_offset) ) =
228224 child_entry. attr ( constants:: DW_AT_data_member_location )
229225 {
@@ -246,36 +242,65 @@ fn do_structure_parse<R: ReaderType>(
246242 MemberAccess :: NoAccess , // TODO : Resolve actual scopes, if possible
247243 MemberScope :: NoScope ,
248244 ) ;
249- } else if let Ok ( Some ( raw_struct_offset_bits) ) =
250- child_entry. attr ( constants:: DW_AT_data_bit_offset )
251- {
252- //TODO: support misaligned offsets when bitwise data structures get in
253- let Some ( struct_offset_bits) = get_attr_as_u64 ( & raw_struct_offset_bits)
254- . or_else ( || get_expr_value ( unit, raw_struct_offset_bits) )
255- else {
256- log:: warn!(
257- "Failed to get DW_AT_data_bit_offset for offset {:#x} in unit {:?}" ,
258- child_entry. offset( ) . 0 ,
259- unit. header. offset( )
260- ) ;
261- continue ;
262- } ;
263-
264- structure_builder. insert (
265- & child_type,
266- & child_name,
267- struct_offset_bits / 8 ,
268- false ,
269- MemberAccess :: NoAccess , // TODO : Resolve actual scopes, if possible
270- MemberScope :: NoScope ,
271- ) ;
272245 } else {
273- structure_builder. append (
274- & child_type,
275- & child_name,
276- MemberAccess :: NoAccess ,
277- MemberScope :: NoScope ,
278- ) ;
246+ let select_value =
247+ |e : & DebuggingInformationEntry < R > , attr : DwAt | -> Option < u64 > {
248+ get_attr_as_u64 ( & e. attr ( attr) . ok ( ) ??)
249+ } ;
250+
251+ // If no byte offset, try the bitfield using DW_AT_bit_offset/DW_AT_data_bit_offset + DW_AT_bit_size
252+ let bit_size = select_value ( child_entry, constants:: DW_AT_bit_size ) ;
253+ let bit_offset = select_value ( child_entry, constants:: DW_AT_bit_offset ) ;
254+ let data_bit_offset =
255+ select_value ( child_entry, constants:: DW_AT_data_bit_offset ) ;
256+
257+ match ( bit_size, bit_offset, data_bit_offset) {
258+ ( Some ( bit_size) , Some ( bit_offset) , _) => {
259+ // Heuristic storage unit bits from the member type width (bytes -> bits). Fallback to 8.
260+ let storage_bits = {
261+ let w = child_type. width ( ) ;
262+ if w > 0 {
263+ w * 8
264+ } else {
265+ 8
266+ }
267+ } ;
268+
269+ // DW_AT_bit_offset is from the MSB of the storage unit:
270+ // absolute = base_byte_off*8 + storage_bits - (boffs + bit_sz)
271+ // With no base_byte_off available here, treat base as 0.
272+ let total_bit_off = storage_bits. saturating_sub ( bit_offset + bit_size) ;
273+
274+ structure_builder. insert_bitwise (
275+ & child_type,
276+ & child_name,
277+ total_bit_off,
278+ Some ( bit_size as u8 ) ,
279+ false ,
280+ MemberAccess :: NoAccess ,
281+ MemberScope :: NoScope ,
282+ ) ;
283+ }
284+ ( Some ( bit_size) , None , Some ( data_bit_offset) ) => {
285+ structure_builder. insert_bitwise (
286+ & child_type,
287+ & child_name,
288+ data_bit_offset,
289+ Some ( bit_size as u8 ) ,
290+ false ,
291+ MemberAccess :: NoAccess ,
292+ MemberScope :: NoScope ,
293+ ) ;
294+ }
295+ _ => {
296+ structure_builder. append (
297+ & child_type,
298+ & child_name,
299+ MemberAccess :: NoAccess ,
300+ MemberScope :: NoScope ,
301+ ) ;
302+ }
303+ }
279304 }
280305 }
281306 constants:: DW_TAG_inheritance => {
@@ -316,7 +341,6 @@ fn do_structure_parse<R: ReaderType>(
316341
317342 structure_builder. base_structures ( & base_structures) ;
318343 let finalized_structure = Type :: structure ( & structure_builder. finalize ( ) ) ;
319-
320344 if let Some ( full_name) = full_name {
321345 debug_info_builder. add_type (
322346 get_uid ( dwarf, unit, entry) + 1 , // TODO : This is super broke (uid + 1 is not guaranteed to be unique)
0 commit comments