summaryrefslogtreecommitdiff
path: root/rust/examples/dwarf/dwarf_import/src/helpers.rs
diff options
context:
space:
mode:
authorKyleMiles <krm504@nyu.edu>2023-08-25 14:08:25 -0400
committerKyleMiles <krm504@nyu.edu>2023-09-29 12:02:59 -0400
commit20e79d4e43a8734cdc5c4f9ca5b204a2c44aca8e (patch)
tree067c27dd7c35158ef2d9f8fa4073e81574088406 /rust/examples/dwarf/dwarf_import/src/helpers.rs
parenta452691f145583f092893dff6ecab14375d0613f (diff)
DWARF Import : Misc code cleanup, improvements, and enabling by default changes
This includes: Gracefully handle missing DIE references Partially revert 7849cda Misc DWARFv5 Fixes Speed Improvements Fix crash on unexpected EOF Partially revert 0d5fe9ec8963a26361b8bf1af17e029afc87f952 and Correctly initialize DWARF Import plugin
Diffstat (limited to 'rust/examples/dwarf/dwarf_import/src/helpers.rs')
-rw-r--r--rust/examples/dwarf/dwarf_import/src/helpers.rs236
1 files changed, 106 insertions, 130 deletions
diff --git a/rust/examples/dwarf/dwarf_import/src/helpers.rs b/rust/examples/dwarf/dwarf_import/src/helpers.rs
index f3b7dd81..05cf6f82 100644
--- a/rust/examples/dwarf/dwarf_import/src/helpers.rs
+++ b/rust/examples/dwarf/dwarf_import/src/helpers.rs
@@ -12,12 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+use crate::DebugInfoBuilderContext;
+
use gimli::{
constants, Attribute, AttributeValue,
- AttributeValue::{DebugInfoRef, DebugInfoRefSup, UnitRef},
- DebuggingInformationEntry, Dwarf, Operation, Reader, Unit, UnitOffset, UnitSectionOffset,
+ AttributeValue::{DebugInfoRef, UnitRef},
+ DebuggingInformationEntry, Operation, Reader, Unit, UnitOffset, UnitSectionOffset,
};
+use log::warn;
use std::ffi::CString;
pub(crate) fn get_uid<R: Reader<Offset = usize>>(
@@ -33,182 +36,136 @@ pub(crate) fn get_uid<R: Reader<Offset = usize>>(
////////////////////////////////////
// DIE attr convenience functions
-pub(crate) enum DieReference<R: Reader<Offset = usize>> {
- Offset(UnitOffset),
- UnitAndOffset((Unit<R>, UnitOffset)),
-}
-
-fn get_unit_copy<'a, R: Reader<Offset = usize>>(dwarf: &'a Dwarf<R>, unit: &'a Unit<R>) -> Unit<R> {
- let mut iter = dwarf.units();
- while let Ok(Some(header)) = iter.next() {
- if header.offset() == unit.header.offset() {
- return dwarf.unit(header).unwrap();
- }
- }
- unreachable!()
+pub(crate) enum DieReference<'a, R: Reader<Offset = usize>> {
+ UnitAndOffset((&'a Unit<R>, UnitOffset)),
+ Err,
}
pub(crate) fn get_attr_die<'a, R: Reader<Offset = usize>>(
- dwarf: &'a Dwarf<R>,
- _unit: &'a Unit<R>,
- entry: &'a DebuggingInformationEntry<R>,
+ unit: &'a Unit<R>,
+ entry: &DebuggingInformationEntry<R>,
+ debug_info_builder_context: &'a DebugInfoBuilderContext<R>,
attr: constants::DwAt,
-) -> Option<DieReference<R>> {
+) -> Option<DieReference<'a, R>> {
match entry.attr_value(attr) {
- Ok(Some(UnitRef(offset))) => Some(DieReference::Offset(offset)),
- Ok(Some(DebugInfoRef(offset))) | Ok(Some(DebugInfoRefSup(offset))) => {
- let mut iter = dwarf.units();
- while let Ok(Some(header)) = iter.next() {
- if let Some(new_offset) = offset.to_unit_offset(&header) {
- return Some(DieReference::UnitAndOffset((
- dwarf.unit(header).unwrap(),
- new_offset,
- )));
+ Ok(Some(UnitRef(offset))) => Some(DieReference::UnitAndOffset((unit, offset))),
+ Ok(Some(DebugInfoRef(offset))) => {
+ for source_unit in debug_info_builder_context.units() {
+ if let Some(new_offset) = offset.to_unit_offset(&source_unit.header) {
+ return Some(DieReference::UnitAndOffset((source_unit, new_offset)));
}
}
- unreachable!() //None
+ warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ None
}
+ // Ok(Some(DebugInfoRefSup(offset))) TODO - dwarf 5 stuff
_ => None,
}
}
pub(crate) fn resolve_specification<'a, R: Reader<Offset = usize>>(
- dwarf: &'a Dwarf<R>,
unit: &'a Unit<R>,
- entry: &'a DebuggingInformationEntry<R>,
-) -> DieReference<R> {
- if let Some(die_reference) = get_attr_die(dwarf, unit, entry, constants::DW_AT_specification) {
- match die_reference {
- DieReference::Offset(entry_offset) => {
- resolve_specification(dwarf, unit, &unit.entry(entry_offset).unwrap())
- }
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
- resolve_specification_slowpath(
- dwarf,
- &entry_unit,
- &entry_unit.entry(entry_offset).unwrap(),
- )
- }
- }
- } else if let Some(die_reference) =
- get_attr_die(dwarf, unit, entry, constants::DW_AT_abstract_origin)
- {
- match die_reference {
- DieReference::Offset(entry_offset) => {
- resolve_specification(dwarf, unit, &unit.entry(entry_offset).unwrap())
- }
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
- resolve_specification_slowpath(
- dwarf,
- &entry_unit,
- &entry_unit.entry(entry_offset).unwrap(),
- )
- }
- }
- } else {
- DieReference::Offset(entry.offset())
- }
-}
-
-fn resolve_specification_slowpath<'a, R: Reader<Offset = usize>>(
- dwarf: &'a Dwarf<R>,
- unit: &'a Unit<R>,
- entry: &'a DebuggingInformationEntry<R>,
-) -> DieReference<R> {
- if let Some(die_reference) = get_attr_die(dwarf, unit, entry, constants::DW_AT_specification) {
+ entry: &DebuggingInformationEntry<R>,
+ debug_info_builder_context: &'a DebugInfoBuilderContext<R>,
+) -> DieReference<'a, R> {
+ if let Some(die_reference) = get_attr_die(
+ unit,
+ entry,
+ debug_info_builder_context,
+ constants::DW_AT_specification,
+ ) {
match die_reference {
- DieReference::Offset(entry_offset) => {
- resolve_specification_slowpath(dwarf, unit, &unit.entry(entry_offset).unwrap())
- }
DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
- resolve_specification_slowpath(
- dwarf,
- &entry_unit,
- &entry_unit.entry(entry_offset).unwrap(),
- )
+ if let Ok(entry) = entry_unit.entry(entry_offset) {
+ resolve_specification(entry_unit, &entry, debug_info_builder_context)
+ } else {
+ warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ DieReference::Err
+ }
}
+ DieReference::Err => DieReference::Err,
}
- } else if let Some(die_reference) =
- get_attr_die(dwarf, unit, entry, constants::DW_AT_abstract_origin)
- {
+ } else if let Some(die_reference) = get_attr_die(
+ unit,
+ entry,
+ debug_info_builder_context,
+ constants::DW_AT_abstract_origin,
+ ) {
match die_reference {
- DieReference::Offset(entry_offset) => {
- resolve_specification_slowpath(dwarf, unit, &unit.entry(entry_offset).unwrap())
- }
DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
- resolve_specification_slowpath(
- dwarf,
- &entry_unit,
- &entry_unit.entry(entry_offset).unwrap(),
- )
+ if let Ok(entry) = entry_unit.entry(entry_offset) {
+ resolve_specification(entry_unit, &entry, debug_info_builder_context)
+ } else {
+ warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ DieReference::Err
+ }
}
+ DieReference::Err => DieReference::Err,
}
} else {
- DieReference::UnitAndOffset((get_unit_copy(dwarf, unit), entry.offset()))
+ DieReference::UnitAndOffset((unit, entry.offset()))
}
}
// Get name from DIE, or referenced dependencies
pub(crate) fn get_name<R: Reader<Offset = usize>>(
- dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
+ debug_info_builder_context: &DebugInfoBuilderContext<R>,
) -> Option<CString> {
- match resolve_specification(dwarf, unit, entry) {
- DieReference::Offset(entry_offset) => {
- if let Ok(Some(attr_val)) = unit
- .entry(entry_offset)
- .unwrap()
- .attr_value(constants::DW_AT_name)
- {
- if let Ok(attr_string) = dwarf.attr_string(unit, attr_val) {
- if let Ok(attr_string) = attr_string.to_string() {
- return Some(CString::new(attr_string.to_string()).unwrap());
- }
- }
- }
- None
- }
+ match resolve_specification(unit, entry, debug_info_builder_context) {
DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
if let Ok(Some(attr_val)) = entry_unit
.entry(entry_offset)
.unwrap()
.attr_value(constants::DW_AT_name)
{
- if let Ok(attr_string) = dwarf.attr_string(&entry_unit, attr_val) {
+ if let Ok(attr_string) = debug_info_builder_context
+ .dwarf()
+ .attr_string(entry_unit, attr_val)
+ {
if let Ok(attr_string) = attr_string.to_string() {
return Some(CString::new(attr_string.to_string()).unwrap());
}
}
}
+
+ // if let Some(raw_name) = get_raw_name(unit, entry, debug_info_builder_context) {
+ // if let Some(arch) = debug_info_builder_context.default_architecture() {
+ // if let Ok((_, names)) = demangle_gnu3(&arch, raw_name, true) {
+ // return Some(CString::new(names.join("::")).unwrap());
+ // }
+ // }
+ // }
None
}
+ DieReference::Err => None,
}
}
// Get raw name from DIE, or referenced dependencies
-pub(crate) fn get_raw_name<R: Reader>(
- dwarf: &Dwarf<R>,
+pub(crate) fn get_raw_name<R: Reader<Offset = usize>>(
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
+ debug_info_builder_context: &DebugInfoBuilderContext<R>,
) -> Option<CString> {
if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_linkage_name) {
- if let Ok(attr_string) = dwarf.attr_string(unit, attr_val) {
+ if let Ok(attr_string) = debug_info_builder_context
+ .dwarf()
+ .attr_string(unit, attr_val)
+ {
if let Ok(attr_string) = attr_string.to_string() {
- Some(CString::new(attr_string.to_string()).unwrap())
- } else {
- None
+ return Some(CString::new(attr_string.to_string()).unwrap());
}
- } else {
- None
}
- } else {
- None
}
+ None
}
// Get the size of an object as a usize
-pub(crate) fn get_size_as_usize<R: Reader>(entry: &DebuggingInformationEntry<R>) -> Option<usize> {
+pub(crate) fn get_size_as_usize<R: Reader<Offset = usize>>(
+ entry: &DebuggingInformationEntry<R>,
+) -> Option<usize> {
if let Ok(Some(attr)) = entry.attr(constants::DW_AT_byte_size) {
get_attr_as_usize(attr)
} else if let Ok(Some(attr)) = entry.attr(constants::DW_AT_bit_size) {
@@ -219,7 +176,9 @@ pub(crate) fn get_size_as_usize<R: Reader>(entry: &DebuggingInformationEntry<R>)
}
// Get the size of an object as a u64
-pub(crate) fn get_size_as_u64<R: Reader>(entry: &DebuggingInformationEntry<R>) -> Option<u64> {
+pub(crate) fn get_size_as_u64<R: Reader<Offset = usize>>(
+ entry: &DebuggingInformationEntry<R>,
+) -> Option<u64> {
if let Ok(Some(attr)) = entry.attr(constants::DW_AT_byte_size) {
get_attr_as_u64(&attr)
} else if let Ok(Some(attr)) = entry.attr(constants::DW_AT_bit_size) {
@@ -230,7 +189,9 @@ pub(crate) fn get_size_as_u64<R: Reader>(entry: &DebuggingInformationEntry<R>) -
}
// Get the size of a subrange as a u64
-pub(crate) fn get_subrange_size<R: Reader>(entry: &DebuggingInformationEntry<R>) -> u64 {
+pub(crate) fn get_subrange_size<R: Reader<Offset = usize>>(
+ entry: &DebuggingInformationEntry<R>,
+) -> u64 {
if let Ok(Some(attr)) = entry.attr(constants::DW_AT_upper_bound) {
get_attr_as_u64(&attr).map_or(0, |v| v + 1)
} else if let Ok(Some(attr)) = entry.attr(constants::DW_AT_count) {
@@ -243,24 +204,36 @@ pub(crate) fn get_subrange_size<R: Reader>(entry: &DebuggingInformationEntry<R>)
}
// Get the start address of a function
-pub(crate) fn get_start_address<R: Reader>(
- dwarf: &Dwarf<R>,
+pub(crate) fn get_start_address<R: Reader<Offset = usize>>(
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
+ debug_info_builder_context: &DebugInfoBuilderContext<R>,
) -> Option<u64> {
if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_low_pc) {
- match dwarf.attr_address(unit, attr_val) {
+ match debug_info_builder_context
+ .dwarf()
+ .attr_address(unit, attr_val)
+ {
Ok(Some(val)) => Some(val),
_ => None,
}
} else if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_entry_pc) {
- match dwarf.attr_address(unit, attr_val) {
+ match debug_info_builder_context
+ .dwarf()
+ .attr_address(unit, attr_val)
+ {
Ok(Some(val)) => Some(val),
_ => None,
}
} else if let Ok(Some(attr_value)) = entry.attr_value(constants::DW_AT_ranges) {
- if let Ok(Some(ranges_offset)) = dwarf.attr_ranges_offset(unit, attr_value) {
- if let Ok(mut ranges) = dwarf.ranges(unit, ranges_offset) {
+ if let Ok(Some(ranges_offset)) = debug_info_builder_context
+ .dwarf()
+ .attr_ranges_offset(unit, attr_value)
+ {
+ if let Ok(mut ranges) = debug_info_builder_context
+ .dwarf()
+ .ranges(unit, ranges_offset)
+ {
if let Ok(Some(range)) = ranges.next() {
return Some(range.begin);
}
@@ -273,7 +246,7 @@ pub(crate) fn get_start_address<R: Reader>(
}
// Get an attribute value as a u64 if it can be coerced
-pub(crate) fn get_attr_as_u64<R: Reader>(attr: &Attribute<R>) -> Option<u64> {
+pub(crate) fn get_attr_as_u64<R: Reader<Offset = usize>>(attr: &Attribute<R>) -> Option<u64> {
if let Some(value) = attr.u8_value() {
Some(value.into())
} else if let Some(value) = attr.u16_value() {
@@ -286,7 +259,7 @@ pub(crate) fn get_attr_as_u64<R: Reader>(attr: &Attribute<R>) -> Option<u64> {
}
// Get an attribute value as a usize if it can be coerced
-pub(crate) fn get_attr_as_usize<R: Reader>(attr: Attribute<R>) -> Option<usize> {
+pub(crate) fn get_attr_as_usize<R: Reader<Offset = usize>>(attr: Attribute<R>) -> Option<usize> {
if let Some(value) = attr.u8_value() {
Some(value.into())
} else if let Some(value) = attr.u16_value() {
@@ -300,7 +273,10 @@ pub(crate) fn get_attr_as_usize<R: Reader>(attr: Attribute<R>) -> Option<usize>
// Get an attribute value as a usize if it can be coerced
// Parses DW_OP_address, DW_OP_const
-pub(crate) fn get_expr_value<R: Reader>(unit: &Unit<R>, attr: Attribute<R>) -> Option<u64> {
+pub(crate) fn get_expr_value<R: Reader<Offset = usize>>(
+ unit: &Unit<R>,
+ attr: Attribute<R>,
+) -> Option<u64> {
if let AttributeValue::Exprloc(mut expression) = attr.value() {
match Operation::parse(&mut expression.0, unit.encoding()) {
Ok(Operation::PlusConstant { value }) => Some(value),