diff --git a/trace/src/lib.rs b/trace/src/lib.rs index 301c795..802a174 100644 --- a/trace/src/lib.rs +++ b/trace/src/lib.rs @@ -147,6 +147,10 @@ pub struct Variable { pub type_value: TypeValueTree, /// The code location of where this variable is declared pub location: Location, + /// The linkage name of the variable (if specified in the debug info) + pub linkage_name: Option, + /// The address of the variable (if it's specified in the debug info (and is simple as an address)) + pub address: Option, } impl Variable { diff --git a/trace/src/platform/mod.rs b/trace/src/platform/mod.rs index 1716fd0..85577ea 100644 --- a/trace/src/platform/mod.rs +++ b/trace/src/platform/mod.rs @@ -1,7 +1,7 @@ use crate::{error::TraceError, type_value_tree::TypeValueTree, Frame, FrameType, Location}; use funty::Fundamental; use gimli::{DebugInfoOffset, EndianRcSlice, RunTimeEndian}; -use object::{Object, ObjectSection, SectionKind}; +use object::{Object, ObjectSection, ObjectSymbol, SectionKind}; use stackdump_core::{device_memory::DeviceMemory, memory_region::VecMemoryRegion}; use std::collections::HashMap; @@ -161,8 +161,54 @@ where } // We're done with the stack data, but we can also decode the static variables and make a frame out of that - let static_variables = + let mut static_variables = crate::variables::find_static_variables(&dwarf, &device_memory, &mut type_cache)?; + + // Filter out static variables that are not real (like defmt ones) + static_variables.retain(|var| { + let Some(linkage_name) = &var.linkage_name else { + // For some reason, some variables don't have a linkage name. + // So just show them, I guess? + return true; + }; + + if let Some(symbol) = elf.symbol_by_name(&linkage_name) { + if let Some(section_index) = symbol.section_index() { + match elf.section_by_index(section_index) { + // Filter out all weird sections (including defmt) + Ok(section) if section.kind() == SectionKind::Other => false, + Ok(_section) => true, + Err(e) => { + log::error!("Could not get section by index: {e}"); + true + } + } + } else { + // The symbol is not defined in a section? + // Idk man, just show it I guess + true + } + } else { + // We have a linkage name from debug info, but the symbol doesn't exist... + // There's two things that might be going on that I know about: + // 1. LTO ran and removed the symbol because it was never used. + // 2. LLVM merged some globals (including this one) into one symbol. + // + // If 1, we want to return false. If 2, we want to return true. + + // For 1, if the variable has an address, it tends to be address 0 as far as I can see. + // This makes sense because it doesn't exist, and so doesn't have a 'real' address. + + if var.address == None || var.address == Some(0) { + // We're likely in number 1 territory + false + } else { + // We _may_ be in number 2 territory + true + } + } + }); + let static_frame = Frame { function: "Static".into(), location: Location { diff --git a/trace/src/variables/mod.rs b/trace/src/variables/mod.rs index 8dfef9c..c2d0b70 100644 --- a/trace/src/variables/mod.rs +++ b/trace/src/variables/mod.rs @@ -79,6 +79,21 @@ fn get_entry_name( } } +/// Gets the string value from the `DW_AT_linkage_name` attribute of the given entry if it's present +fn get_entry_linkage_name( + dwarf: &Dwarf, + unit: &Unit, + entry: &DebuggingInformationEntry, +) -> Result, TraceError> { + // Find the attribute + let Some(linkage_name_attr) = entry.attr(gimli::constants::DW_AT_linkage_name)? else { + return Ok(None); + }; + + let attr_string = dwarf.attr_string(unit, linkage_name_attr.value())?; + Ok(Some(attr_string.to_string()?.into())) +} + /// If available, get the EntriesTree of the `DW_AT_abstract_origin` attribute of the given entry fn get_entry_abstract_origin_reference_tree<'abbrev, 'unit>( dwarf: &Dwarf, @@ -270,7 +285,7 @@ where let frame_base_data = get_variable_data( device_memory, core::mem::size_of::() as u64 * 8, - frame_base_location, + &frame_base_location, ); Ok(frame_base_data.ok().map(|data| data.load_le())) @@ -599,7 +614,7 @@ where let entry_data = get_variable_data( device_memory, W::BITS as u64, - VariableLocationResult::LocationsFound(entry_pieces), + &VariableLocationResult::LocationsFound(entry_pieces), )?; result = evaluation.resume_with_entry_value(gimli::Value::Generic( @@ -720,7 +735,7 @@ where fn get_variable_data( device_memory: &DeviceMemory, variable_size: u64, - variable_location: VariableLocationResult, + variable_location: &VariableLocationResult, ) -> Result, VariableDataError> where ::Bytes: bitvec::view::BitView, @@ -759,6 +774,22 @@ where } } +/// Returns the first found address in the location (if any) +fn get_variable_address(variable_location: &VariableLocationResult) -> Option { + match variable_location { + VariableLocationResult::LocationsFound(pieces) => { + for piece in pieces { + match piece.location { + gimli::Location::Address { address } => return Some(address), + _ => {} + } + } + None + } + _ => None, + } +} + fn read_base_type( encoding: gimli::DwAte, data: &BitSlice, @@ -1098,6 +1129,9 @@ where variable_name = Ok("param".into()); } + // Get the name of the variable + let variable_linkage_name = get_entry_linkage_name(dwarf, unit, entry)?; + // Get the type of the variable or its abstract origin get_entry_type_reference_tree_recursive!( variable_type_tree = (dwarf, unit, abbreviations, entry) @@ -1138,7 +1172,7 @@ where parameter: entry.tag() == gimli::constants::DW_TAG_formal_parameter, }; - // Get the location of the variable + // Get the (file) location of the variable let mut variable_file_location = find_entry_location(dwarf, unit, entry)?; if let (None, Some(abstract_origin_entry)) = (&variable_file_location.file, abstract_origin_entry) @@ -1153,6 +1187,8 @@ where kind: variable_kind, type_value: variable_type_value_tree, location: variable_file_location, + linkage_name: variable_linkage_name, + address: None, // We don't care about the address of a ZST })) } (Ok(variable_name), Ok(mut variable_type_value_tree)) => { @@ -1174,7 +1210,7 @@ where let variable_data = get_variable_data( device_memory, variable_type_value_tree.data().bit_length(), - variable_location, + &variable_location, ); match variable_data { @@ -1199,6 +1235,8 @@ where kind: variable_kind, type_value: variable_type_value_tree, location: variable_file_location, + linkage_name: variable_linkage_name, + address: get_variable_address(&variable_location), })) } (Ok(variable_name), Err(type_error)) => {