WIP: process embedded structs/unions in dwarf info

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
This commit is contained in:
Thomas Bertschinger 2024-05-01 20:45:30 -06:00
parent 16f2849433
commit e74310fb24

View File

@ -4,8 +4,8 @@
use gimli::Reader as _; use gimli::Reader as _;
use object::{Object, ObjectSection}; use object::{Object, ObjectSection};
use std::{borrow, error, fs};
use std::collections::HashSet; use std::collections::HashSet;
use std::{borrow, error, fs};
/// A list of the known bcachefs bkey types. /// A list of the known bcachefs bkey types.
#[derive(Debug)] #[derive(Debug)]
@ -161,6 +161,12 @@ fn process_unit(
Ok(()) Ok(())
} }
#[derive(Clone, Copy)]
enum CompType {
Union,
Struct,
}
fn process_tree( fn process_tree(
dwarf: &gimli::Dwarf<Reader>, dwarf: &gimli::Dwarf<Reader>,
unit: &gimli::Unit<Reader>, unit: &gimli::Unit<Reader>,
@ -174,7 +180,9 @@ fn process_tree(
if let Ok(name) = dwarf.attr_string(unit, name.value()) { if let Ok(name) = dwarf.attr_string(unit, name.value()) {
let name = name.to_string_lossy()?.into_owned(); let name = name.to_string_lossy()?.into_owned();
if bkey_types.remove(&name.clone()) { if bkey_types.remove(&name.clone()) {
process_struct(name, dwarf, unit, node, struct_list)?; let mut members: Vec<BchMember> = Vec::new();
process_compound_type(dwarf, unit, node, &mut members, 0, CompType::Struct)?;
struct_list.0.push(BchStruct { name, members });
} }
} }
} }
@ -187,71 +195,86 @@ fn process_tree(
Ok(()) Ok(())
} }
fn process_struct( fn process_compound_type(
name: std::string::String,
dwarf: &gimli::Dwarf<Reader>, dwarf: &gimli::Dwarf<Reader>,
unit: &gimli::Unit<Reader>, unit: &gimli::Unit<Reader>,
node: gimli::EntriesTreeNode<Reader>, node: gimli::EntriesTreeNode<Reader>,
struct_list: &mut BkeyTypes, members: &mut Vec<BchMember>,
starting_offset: u64,
comp: CompType,
) -> gimli::Result<()> { ) -> gimli::Result<()> {
let mut bch_struct = BchStruct {
name,
members: Vec::new(),
};
let mut children = node.children(); let mut children = node.children();
while let Some(child) = children.next()? { while let Some(child) = children.next()? {
if let Some(member) = process_struct_member(dwarf, unit, child) { process_comp_member(dwarf, unit, child, members, starting_offset, comp)?;
bch_struct.members.push(member);
}
} }
struct_list.0.push(bch_struct);
Ok(()) Ok(())
} }
fn process_struct_member( // Given a DIE, checks if that DIE has a reference to a compound type (i.e., struct or union) and
// if so, returns the offset in the DIE tree for that type, and the kind of compound type it is.
fn get_comp_ref(
unit: &gimli::Unit<Reader>,
entry: &gimli::DebuggingInformationEntry<Reader>,
) -> Option<(gimli::UnitOffset, CompType)> {
let ref_type = entry.attr(gimli::DW_AT_type).ok()??;
let ref_offset = match ref_type.value() {
gimli::AttributeValue::UnitRef(offset) => offset,
_ => return None,
};
let mut ty_entry = unit.entries_at_offset(ref_offset).ok()?;
ty_entry.next_entry().ok()??;
let ty_entry = ty_entry.current()?;
match ty_entry.tag() {
gimli::DW_TAG_structure_type => Some((ty_entry.offset(), CompType::Struct)),
gimli::DW_TAG_union_type => Some((ty_entry.offset(), CompType::Union)),
_ => None,
}
}
fn process_comp_member(
dwarf: &gimli::Dwarf<Reader>, dwarf: &gimli::Dwarf<Reader>,
unit: &gimli::Unit<Reader>, unit: &gimli::Unit<Reader>,
node: gimli::EntriesTreeNode<Reader>, node: gimli::EntriesTreeNode<Reader>,
) -> Option<BchMember> { members: &mut Vec<BchMember>,
let entry = node.entry(); starting_offset: u64,
comp: CompType,
) -> gimli::Result<()> {
let entry = node.entry().clone();
let name: Option<String> = entry.attr(gimli::DW_AT_name).ok()?.map(|name| { let offset = match comp {
if let Ok(name) = dwarf.attr_string(unit, name.value()) { CompType::Union => Some(0),
Some(name.to_string_lossy().ok()?.into_owned()) CompType::Struct => entry
} else { .attr(gimli::DW_AT_data_member_location)?
None .and_then(|offset| offset.value().udata_value()),
}
})?;
let Some(name) = name else {
return None;
}; };
let offset: Option<u64> = entry
.attr(gimli::DW_AT_data_member_location)
.ok()?
.map(|offset| offset.value().udata_value())?;
let Some(offset) = offset else { let Some(offset) = offset else {
return None; return Ok(());
}; };
let size = entry.attr(gimli::DW_AT_type).ok()?.map(|ty| { if let Some((ref_type, comp)) = get_comp_ref(unit, &entry) {
if let gimli::AttributeValue::UnitRef(offset) = ty.value() { let mut tree = unit.entries_tree(Some(ref_type))?;
let mut ty_entry = unit.entries_at_offset(offset).ok()?; process_compound_type(dwarf, unit, tree.root()?, members, offset, comp)?;
ty_entry.next_entry().ok()?;
if let Some(t) = ty_entry.current() {
return get_size(unit, t);
}
}
None
})?;
let Some(size) = size else {
return None;
}; };
Some(BchMember { name, offset, size }) let Some(size) = get_size(unit, &entry) else {
return Ok(());
};
let name = entry.attr(gimli::DW_AT_name)?;
let Some(name) = name else { return Ok(()) };
let name = dwarf.attr_string(unit, name.value())?;
let name = name.to_string_lossy()?.into_owned();
members.push(BchMember {
name,
offset: offset + starting_offset,
size,
});
Ok(())
} }
fn get_size( fn get_size(
@ -285,5 +308,14 @@ pub fn get_bkey_type_info() -> BkeyTypes {
let mut struct_list = BkeyTypes::new(); let mut struct_list = BkeyTypes::new();
process_file(&object, &mut struct_list).unwrap(); process_file(&object, &mut struct_list).unwrap();
/*
for s in struct_list.0.iter() {
for m in s.members.iter() {
println!("{} {} {} {}", s.name, m.name, m.offset, m.size);
}
println!("");
}
*/
struct_list struct_list
} }