mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-24 00:00:19 +03:00
WIP: process embedded structs/unions in dwarf info
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
This commit is contained in:
parent
16f2849433
commit
e74310fb24
@ -4,8 +4,8 @@
|
||||
|
||||
use gimli::Reader as _;
|
||||
use object::{Object, ObjectSection};
|
||||
use std::{borrow, error, fs};
|
||||
use std::collections::HashSet;
|
||||
use std::{borrow, error, fs};
|
||||
|
||||
/// A list of the known bcachefs bkey types.
|
||||
#[derive(Debug)]
|
||||
@ -161,6 +161,12 @@ fn process_unit(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum CompType {
|
||||
Union,
|
||||
Struct,
|
||||
}
|
||||
|
||||
fn process_tree(
|
||||
dwarf: &gimli::Dwarf<Reader>,
|
||||
unit: &gimli::Unit<Reader>,
|
||||
@ -174,7 +180,9 @@ fn process_tree(
|
||||
if let Ok(name) = dwarf.attr_string(unit, name.value()) {
|
||||
let name = name.to_string_lossy()?.into_owned();
|
||||
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(())
|
||||
}
|
||||
|
||||
fn process_struct(
|
||||
name: std::string::String,
|
||||
fn process_compound_type(
|
||||
dwarf: &gimli::Dwarf<Reader>,
|
||||
unit: &gimli::Unit<Reader>,
|
||||
node: gimli::EntriesTreeNode<Reader>,
|
||||
struct_list: &mut BkeyTypes,
|
||||
members: &mut Vec<BchMember>,
|
||||
starting_offset: u64,
|
||||
comp: CompType,
|
||||
) -> gimli::Result<()> {
|
||||
let mut bch_struct = BchStruct {
|
||||
name,
|
||||
members: Vec::new(),
|
||||
};
|
||||
|
||||
let mut children = node.children();
|
||||
while let Some(child) = children.next()? {
|
||||
if let Some(member) = process_struct_member(dwarf, unit, child) {
|
||||
bch_struct.members.push(member);
|
||||
}
|
||||
process_comp_member(dwarf, unit, child, members, starting_offset, comp)?;
|
||||
}
|
||||
struct_list.0.push(bch_struct);
|
||||
|
||||
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>,
|
||||
unit: &gimli::Unit<Reader>,
|
||||
node: gimli::EntriesTreeNode<Reader>,
|
||||
) -> Option<BchMember> {
|
||||
let entry = node.entry();
|
||||
members: &mut Vec<BchMember>,
|
||||
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| {
|
||||
if let Ok(name) = dwarf.attr_string(unit, name.value()) {
|
||||
Some(name.to_string_lossy().ok()?.into_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
let Some(name) = name else {
|
||||
return None;
|
||||
let offset = match comp {
|
||||
CompType::Union => Some(0),
|
||||
CompType::Struct => entry
|
||||
.attr(gimli::DW_AT_data_member_location)?
|
||||
.and_then(|offset| offset.value().udata_value()),
|
||||
};
|
||||
|
||||
let offset: Option<u64> = entry
|
||||
.attr(gimli::DW_AT_data_member_location)
|
||||
.ok()?
|
||||
.map(|offset| offset.value().udata_value())?;
|
||||
let Some(offset) = offset else {
|
||||
return None;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let size = entry.attr(gimli::DW_AT_type).ok()?.map(|ty| {
|
||||
if let gimli::AttributeValue::UnitRef(offset) = ty.value() {
|
||||
let mut ty_entry = unit.entries_at_offset(offset).ok()?;
|
||||
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;
|
||||
if let Some((ref_type, comp)) = get_comp_ref(unit, &entry) {
|
||||
let mut tree = unit.entries_tree(Some(ref_type))?;
|
||||
process_compound_type(dwarf, unit, tree.root()?, members, offset, comp)?;
|
||||
};
|
||||
|
||||
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(
|
||||
@ -285,5 +308,14 @@ pub fn get_bkey_type_info() -> BkeyTypes {
|
||||
let mut struct_list = BkeyTypes::new();
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user