Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions trace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
impl Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(file) = self.file.clone() {
write!(f, "{}", file)?;

Check warning on line 38 in trace/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/lib.rs:38:13 | 38 | write!(f, "{}", file)?; | ^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 38 - write!(f, "{}", file)?; 38 + write!(f, "{file}")?; |
if let Some(line) = self.line {
write!(f, ":{}", line)?;

Check warning on line 40 in trace/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/lib.rs:40:17 | 40 | write!(f, ":{}", line)?; | ^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 40 - write!(f, ":{}", line)?; 40 + write!(f, ":{line}")?; |
if let Some(column) = self.column {
write!(f, ":{}", column)?;

Check warning on line 42 in trace/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/lib.rs:42:21 | 42 | write!(f, ":{}", column)?; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 42 - write!(f, ":{}", column)?; 42 + write!(f, ":{column}")?; |
}
}
}
Expand Down Expand Up @@ -147,13 +147,17 @@
pub type_value: TypeValueTree<ADDR>,
/// 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<String>,
/// The address of the variable (if it's specified in the debug info (and is simple as an address))
pub address: Option<u64>,
}

impl<ADDR: funty::Integral> Variable<ADDR> {
pub fn display(&self, theme: Theme) -> String {
let mut kind_text = self.kind.to_string();
if !kind_text.is_empty() {
kind_text = theme.color_info(format!("({}) ", kind_text)).to_string();

Check warning on line 160 in trace/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/lib.rs:160:42 | 160 | kind_text = theme.color_info(format!("({}) ", kind_text)).to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 160 - kind_text = theme.color_info(format!("({}) ", kind_text)).to_string(); 160 + kind_text = theme.color_info(format!("({kind_text}) ")).to_string(); |
}

let mut location_text = self.location.to_string();
Expand Down
50 changes: 48 additions & 2 deletions trace/src/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -43,12 +43,12 @@
/// Create the stacktrace for the given platform.
///
/// - device_memory: All the captured memory of the device.
/// It is not necessary to include any data that is present in the elf file because that will automatically be added.

Check warning on line 46 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

doc list item without indentation

warning: doc list item without indentation --> trace/src/platform/mod.rs:46:5 | 46 | /// It is not necessary to include any data that is present in the elf file because that will automatically be added. | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation = note: `#[warn(clippy::doc_lazy_continuation)]` on by default help: indent this line | 46 | /// It is not necessary to include any data that is present in the elf file because that will automatically be added. | ++
/// It is required to have a decent chunk of the stack present. If not all of the stack is present,

Check warning on line 47 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

doc list item without indentation

warning: doc list item without indentation --> trace/src/platform/mod.rs:47:5 | 47 | /// It is required to have a decent chunk of the stack present. If not all of the stack is present, | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation help: indent this line | 47 | /// It is required to have a decent chunk of the stack present. If not all of the stack is present, | ++
/// then eventually the tracing procedure will find a corrupt frame.

Check warning on line 48 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

doc list item without indentation

warning: doc list item without indentation --> trace/src/platform/mod.rs:48:5 | 48 | /// then eventually the tracing procedure will find a corrupt frame. | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation help: indent this line | 48 | /// then eventually the tracing procedure will find a corrupt frame. | ++
/// The standard set of registers is also required to be present.

Check warning on line 49 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

doc list item without indentation

warning: doc list item without indentation --> trace/src/platform/mod.rs:49:5 | 49 | /// The standard set of registers is also required to be present. | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation help: indent this line | 49 | /// The standard set of registers is also required to be present. | ++
/// - elf_data: The raw bytes of the elf file.
/// This must be the exact same elf file as the one the device was running. Even a recompilation of the exact same code can change the debug info.

Check warning on line 51 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

doc list item without indentation

warning: doc list item without indentation --> trace/src/platform/mod.rs:51:5 | 51 | /// This must be the exact same elf file as the one the device was running. Even a recompilation of the exact same code can change the de... | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation help: indent this line | 51 | /// This must be the exact same elf file as the one the device was running. Even a recompilation of the exact same code can change the debug info. | ++
pub fn trace<'data, P: Platform<'data>>(
mut device_memory: DeviceMemory<P::Word>,
elf_data: &'data [u8],
Expand Down Expand Up @@ -161,8 +161,54 @@
}

// 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) {

Check warning on line 175 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> trace/src/platform/mod.rs:175:50 | 175 | if let Some(symbol) = elf.symbol_by_name(&linkage_name) { | ^^^^^^^^^^^^^ help: change this to: `linkage_name` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default
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) {

Check warning on line 202 in trace/src/platform/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

binary comparison to literal `Option::None`

warning: binary comparison to literal `Option::None` --> trace/src/platform/mod.rs:202:16 | 202 | if var.address == None || var.address == Some(0) { | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `var.address.is_none()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none = note: `#[warn(clippy::partialeq_to_none)]` on by default
// 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 {
Expand Down
48 changes: 43 additions & 5 deletions trace/src/variables/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,32 @@
}
Err(_) if entry.tag() == gimli::constants::DW_TAG_array_type => {
// Arrays can be anonymous
return Ok("array".into());

Check warning on line 71 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

unneeded `return` statement

warning: unneeded `return` statement --> trace/src/variables/mod.rs:71:17 | 71 | return Ok("array".into()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return = note: `#[warn(clippy::needless_return)]` on by default help: remove `return` | 71 - return Ok("array".into()); 71 + Ok("array".into()) |
}
Err(_) if entry.tag() == gimli::constants::DW_TAG_subroutine_type => {
// Subroutines can be anonymous
return Ok("subroutine".into());

Check warning on line 75 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

unneeded `return` statement

warning: unneeded `return` statement --> trace/src/variables/mod.rs:75:17 | 75 | return Ok("subroutine".into()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return help: remove `return` | 75 - return Ok("subroutine".into()); 75 + Ok("subroutine".into()) |
}
Err(e) => Err(e),
}
}
}

/// 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<DefaultReader>,
unit: &Unit<DefaultReader, usize>,
entry: &DebuggingInformationEntry<DefaultReader, usize>,
) -> Result<Option<String>, 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<DefaultReader>,
Expand Down Expand Up @@ -126,7 +141,7 @@
TraceError::WrongAttributeValueType {
attribute_name: abstract_origin_attr.name().to_string(),
expected_type_name: "UnitRef or DebugInfoRef",
gotten_value: format!("{:X?}", value),

Check warning on line 144 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/variables/mod.rs:144:31 | 144 | gotten_value: format!("{:X?}", value), | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 144 - gotten_value: format!("{:X?}", value), 144 + gotten_value: format!("{value:X?}"), |
},
)),
}
Expand Down Expand Up @@ -179,7 +194,7 @@
TraceError::WrongAttributeValueType {
attribute_name: type_attr.name().to_string(),
expected_type_name: "UnitRef or DebugInfoRef",
gotten_value: format!("{:X?}", value),

Check warning on line 197 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/variables/mod.rs:197:31 | 197 | gotten_value: format!("{:X?}", value), | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 197 - gotten_value: format!("{:X?}", value), 197 + gotten_value: format!("{value:X?}"), |
},
)),
}
Expand All @@ -191,7 +206,7 @@
}

impl GetEntryTreeError {
fn as_trace_error(self) -> TraceError {

Check warning on line 209 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

methods called `as_*` usually take `self` by reference or `self` by mutable reference

warning: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> trace/src/variables/mod.rs:209:23 | 209 | fn as_trace_error(self) -> TraceError { | ^^^^ | = help: consider choosing a less ambiguous name = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention = note: `#[warn(clippy::wrong_self_convention)]` on by default
match self {
Self::TraceError(e) => e,
Self::WrongUnit(_) => TraceError::UnitNotFoundAgain,
Expand All @@ -210,7 +225,7 @@
$abbreviations,
$entry,
) {
Err(crate::variables::GetEntryTreeError::WrongUnit(target_unit)) => {

Check warning on line 228 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

`crate` references the macro call's crate

warning: `crate` references the macro call's crate --> trace/src/variables/mod.rs:228:17 | 228 | Err(crate::variables::GetEntryTreeError::WrongUnit(target_unit)) => { | ^^^^^ help: to reference the macro definition's crate, use: `$crate` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def = note: `#[warn(clippy::crate_in_macro_def)]` on by default
__unit_header = target_unit;
crate::variables::get_entry_abstract_origin_reference_tree(
$dwarf,
Expand All @@ -236,7 +251,7 @@
$abbreviations,
$entry,
) {
Err(crate::variables::GetEntryTreeError::WrongUnit(target_unit)) => {

Check warning on line 254 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

`crate` references the macro call's crate

warning: `crate` references the macro call's crate --> trace/src/variables/mod.rs:254:17 | 254 | Err(crate::variables::GetEntryTreeError::WrongUnit(target_unit)) => { | ^^^^^ help: to reference the macro definition's crate, use: `$crate` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
__unit_header = target_unit;
crate::variables::get_entry_type_reference_tree(
$dwarf,
Expand Down Expand Up @@ -270,7 +285,7 @@
let frame_base_data = get_variable_data(
device_memory,
core::mem::size_of::<W>() as u64 * 8,
frame_base_location,
&frame_base_location,
);

Ok(frame_base_data.ok().map(|data| data.load_le()))
Expand Down Expand Up @@ -488,7 +503,7 @@
/// Runs the location evaluation of gimli.
///
/// - `location`: The `DW_AT_location` attribute value of the entry of the variable we want to get the location of.
/// This may be a None if the variable has no location attribute.

Check warning on line 506 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

doc list item without indentation

warning: doc list item without indentation --> trace/src/variables/mod.rs:506:5 | 506 | /// This may be a None if the variable has no location attribute. | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation help: indent this line | 506 | /// This may be a None if the variable has no location attribute. | ++
fn evaluate_location<W: funty::Integral>(
dwarf: &Dwarf<DefaultReader>,
unit: &Unit<DefaultReader, usize>,
Expand Down Expand Up @@ -566,7 +581,7 @@
// The evaluation stops when it requires some memory that we need to provide.
let mut result = evaluation.evaluate()?;
while result != EvaluationResult::Complete {
log::trace!("Location evaluation result: {:?}", result);

Check warning on line 584 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/variables/mod.rs:584:9 | 584 | log::trace!("Location evaluation result: {:?}", result); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 584 - log::trace!("Location evaluation result: {:?}", result); 584 + log::trace!("Location evaluation result: {result:?}"); |
match result {
EvaluationResult::RequiresRegister {
register,
Expand Down Expand Up @@ -599,7 +614,7 @@
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(
Expand Down Expand Up @@ -720,7 +735,7 @@
fn get_variable_data<W: funty::Integral>(
device_memory: &DeviceMemory<W>,
variable_size: u64,
variable_location: VariableLocationResult,
variable_location: &VariableLocationResult,
) -> Result<BitVec<u8, Lsb0>, VariableDataError>
where
<W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
Expand All @@ -737,7 +752,7 @@

// Get all the data of the pieces
for piece in pieces {
let piece_data = get_piece_data(device_memory, &piece, variable_size_bytes)?;

Check warning on line 755 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> trace/src/variables/mod.rs:755:64 | 755 | let piece_data = get_piece_data(device_memory, &piece, variable_size_bytes)?; | ^^^^^^ help: change this to: `piece` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

if let Some(mut piece_data) = piece_data {
// TODO: Is this always in sequential order? We now assume that it is
Expand All @@ -754,11 +769,27 @@
Ok(data)
}
VariableLocationResult::LocationEvaluationStepNotImplemented(step) => Err(
VariableDataError::UnimplementedLocationEvaluationStep(format!("{:?}", step)),

Check warning on line 772 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> trace/src/variables/mod.rs:772:68 | 772 | VariableDataError::UnimplementedLocationEvaluationStep(format!("{:?}", step)), | ^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 772 - VariableDataError::UnimplementedLocationEvaluationStep(format!("{:?}", step)), 772 + VariableDataError::UnimplementedLocationEvaluationStep(format!("{step:?}")), |
),
}
}

/// Returns the first found address in the location (if any)
fn get_variable_address(variable_location: &VariableLocationResult) -> Option<u64> {
match variable_location {
VariableLocationResult::LocationsFound(pieces) => {
for piece in pieces {
match piece.location {
gimli::Location::Address { address } => return Some(address),
_ => {}
}

Check warning on line 785 in trace/src/variables/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`

warning: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> trace/src/variables/mod.rs:782:17 | 782 | / match piece.location { 783 | | gimli::Location::Address { address } => return Some(address), 784 | | _ => {} 785 | | } | |_________________^ help: try: `if let gimli::Location::Address { address } = piece.location { return Some(address) }` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match = note: `#[warn(clippy::single_match)]` on by default
}
None
}
_ => None,
}
}

fn read_base_type<W: funty::Integral>(
encoding: gimli::DwAte,
data: &BitSlice<u8, Lsb0>,
Expand Down Expand Up @@ -1098,6 +1129,9 @@
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)
Expand Down Expand Up @@ -1138,7 +1172,7 @@
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)
Expand All @@ -1153,6 +1187,8 @@
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)) => {
Expand All @@ -1174,7 +1210,7 @@
let variable_data = get_variable_data(
device_memory,
variable_type_value_tree.data().bit_length(),
variable_location,
&variable_location,
);

match variable_data {
Expand All @@ -1199,6 +1235,8 @@
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)) => {
Expand Down
Loading