summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bertschinger <tahbertschinger@gmail.com>2024-05-01 20:45:30 -0600
committerThomas Bertschinger <tahbertschinger@gmail.com>2024-05-07 21:29:32 -0400
commite74310fb24e91e5f7522ad60bbf7726dbe0ccb03 (patch)
tree6eb311045452756d20bbfb899ebdcc843dc83b13
parent16f2849433aafd33eae8539536169f86df124dfd (diff)
WIP: process embedded structs/unions in dwarf info
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
-rw-r--r--src/commands/debug/bkey_types.rs122
1 files changed, 77 insertions, 45 deletions
diff --git a/src/commands/debug/bkey_types.rs b/src/commands/debug/bkey_types.rs
index 340e89cf..5178af5b 100644
--- a/src/commands/debug/bkey_types.rs
+++ b/src/commands/debug/bkey_types.rs
@@ -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);
- }
- }
+ 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)?;
+ };
- None
- })?;
- let Some(size) = size else {
- return None;
+ let Some(size) = get_size(unit, &entry) else {
+ return Ok(());
};
- Some(BchMember { name, offset, size })
+ 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
}