Skip to content

Commit 4894ec9

Browse files
committed
Filter away statics we don't want to see
1 parent dd9a190 commit 4894ec9

File tree

3 files changed

+95
-7
lines changed

3 files changed

+95
-7
lines changed

trace/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ pub struct Variable<ADDR: funty::Integral> {
147147
pub type_value: TypeValueTree<ADDR>,
148148
/// The code location of where this variable is declared
149149
pub location: Location,
150+
/// The linkage name of the variable (if specified in the debug info)
151+
pub linkage_name: Option<String>,
152+
/// The address of the variable (if it's specified in the debug info (and is simple as an address))
153+
pub address: Option<u64>,
150154
}
151155

152156
impl<ADDR: funty::Integral> Variable<ADDR> {

trace/src/platform/mod.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{error::TraceError, type_value_tree::TypeValueTree, Frame, FrameType, Location};
22
use funty::Fundamental;
33
use gimli::{DebugInfoOffset, EndianRcSlice, RunTimeEndian};
4-
use object::{Object, ObjectSection, SectionKind};
4+
use object::{Object, ObjectSection, ObjectSymbol, SectionKind};
55
use stackdump_core::{device_memory::DeviceMemory, memory_region::VecMemoryRegion};
66
use std::collections::HashMap;
77

@@ -161,8 +161,54 @@ where
161161
}
162162

163163
// We're done with the stack data, but we can also decode the static variables and make a frame out of that
164-
let static_variables =
164+
let mut static_variables =
165165
crate::variables::find_static_variables(&dwarf, &device_memory, &mut type_cache)?;
166+
167+
// Filter out static variables that are not real (like defmt ones)
168+
static_variables.retain(|var| {
169+
let Some(linkage_name) = &var.linkage_name else {
170+
// For some reason, some variables don't have a linkage name.
171+
// So just show them, I guess?
172+
return true;
173+
};
174+
175+
if let Some(symbol) = elf.symbol_by_name(&linkage_name) {
176+
if let Some(section_index) = symbol.section_index() {
177+
match elf.section_by_index(section_index) {
178+
// Filter out all weird sections (including defmt)
179+
Ok(section) if section.kind() == SectionKind::Other => false,
180+
Ok(_section) => true,
181+
Err(e) => {
182+
log::error!("Could not get section by index: {e}");
183+
true
184+
}
185+
}
186+
} else {
187+
// The symbol is not defined in a section?
188+
// Idk man, just show it I guess
189+
true
190+
}
191+
} else {
192+
// We have a linkage name from debug info, but the symbol doesn't exist...
193+
// There's two things that might be going on that I know about:
194+
// 1. LTO ran and removed the symbol because it was never used.
195+
// 2. LLVM merged some globals (including this one) into one symbol.
196+
//
197+
// If 1, we want to return false. If 2, we want to return true.
198+
199+
// For 1, if the variable has an address, it tends to be address 0 as far as I can see.
200+
// This makes sense because it doesn't exist, and so doesn't have a 'real' address.
201+
202+
if var.address == None || var.address == Some(0) {
203+
// We're likely in number 1 territory
204+
false
205+
} else {
206+
// We _may_ be in number 2 territory
207+
true
208+
}
209+
}
210+
});
211+
166212
let static_frame = Frame {
167213
function: "Static".into(),
168214
location: Location {

trace/src/variables/mod.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@ fn get_entry_name(
7979
}
8080
}
8181

82+
/// Gets the string value from the `DW_AT_linkage_name` attribute of the given entry if it's present
83+
fn get_entry_linkage_name(
84+
dwarf: &Dwarf<DefaultReader>,
85+
unit: &Unit<DefaultReader, usize>,
86+
entry: &DebuggingInformationEntry<DefaultReader, usize>,
87+
) -> Result<Option<String>, TraceError> {
88+
// Find the attribute
89+
let Some(linkage_name_attr) = entry.attr(gimli::constants::DW_AT_linkage_name)? else {
90+
return Ok(None);
91+
};
92+
93+
let attr_string = dwarf.attr_string(unit, linkage_name_attr.value())?;
94+
Ok(Some(attr_string.to_string()?.into()))
95+
}
96+
8297
/// If available, get the EntriesTree of the `DW_AT_abstract_origin` attribute of the given entry
8398
fn get_entry_abstract_origin_reference_tree<'abbrev, 'unit>(
8499
dwarf: &Dwarf<DefaultReader>,
@@ -270,7 +285,7 @@ where
270285
let frame_base_data = get_variable_data(
271286
device_memory,
272287
core::mem::size_of::<W>() as u64 * 8,
273-
frame_base_location,
288+
&frame_base_location,
274289
);
275290

276291
Ok(frame_base_data.ok().map(|data| data.load_le()))
@@ -599,7 +614,7 @@ where
599614
let entry_data = get_variable_data(
600615
device_memory,
601616
W::BITS as u64,
602-
VariableLocationResult::LocationsFound(entry_pieces),
617+
&VariableLocationResult::LocationsFound(entry_pieces),
603618
)?;
604619

605620
result = evaluation.resume_with_entry_value(gimli::Value::Generic(
@@ -720,7 +735,7 @@ where
720735
fn get_variable_data<W: funty::Integral>(
721736
device_memory: &DeviceMemory<W>,
722737
variable_size: u64,
723-
variable_location: VariableLocationResult,
738+
variable_location: &VariableLocationResult,
724739
) -> Result<BitVec<u8, Lsb0>, VariableDataError>
725740
where
726741
<W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
@@ -759,6 +774,22 @@ where
759774
}
760775
}
761776

777+
/// Returns the first found address in the location (if any)
778+
fn get_variable_address(variable_location: &VariableLocationResult) -> Option<u64> {
779+
match variable_location {
780+
VariableLocationResult::LocationsFound(pieces) => {
781+
for piece in pieces {
782+
match piece.location {
783+
gimli::Location::Address { address } => return Some(address),
784+
_ => {}
785+
}
786+
}
787+
None
788+
}
789+
_ => None,
790+
}
791+
}
792+
762793
fn read_base_type<W: funty::Integral>(
763794
encoding: gimli::DwAte,
764795
data: &BitSlice<u8, Lsb0>,
@@ -1098,6 +1129,9 @@ where
10981129
variable_name = Ok("param".into());
10991130
}
11001131

1132+
// Get the name of the variable
1133+
let variable_linkage_name = get_entry_linkage_name(dwarf, unit, entry)?;
1134+
11011135
// Get the type of the variable or its abstract origin
11021136
get_entry_type_reference_tree_recursive!(
11031137
variable_type_tree = (dwarf, unit, abbreviations, entry)
@@ -1138,7 +1172,7 @@ where
11381172
parameter: entry.tag() == gimli::constants::DW_TAG_formal_parameter,
11391173
};
11401174

1141-
// Get the location of the variable
1175+
// Get the (file) location of the variable
11421176
let mut variable_file_location = find_entry_location(dwarf, unit, entry)?;
11431177
if let (None, Some(abstract_origin_entry)) =
11441178
(&variable_file_location.file, abstract_origin_entry)
@@ -1153,6 +1187,8 @@ where
11531187
kind: variable_kind,
11541188
type_value: variable_type_value_tree,
11551189
location: variable_file_location,
1190+
linkage_name: variable_linkage_name,
1191+
address: None, // We don't care about the address of a ZST
11561192
}))
11571193
}
11581194
(Ok(variable_name), Ok(mut variable_type_value_tree)) => {
@@ -1174,7 +1210,7 @@ where
11741210
let variable_data = get_variable_data(
11751211
device_memory,
11761212
variable_type_value_tree.data().bit_length(),
1177-
variable_location,
1213+
&variable_location,
11781214
);
11791215

11801216
match variable_data {
@@ -1199,6 +1235,8 @@ where
11991235
kind: variable_kind,
12001236
type_value: variable_type_value_tree,
12011237
location: variable_file_location,
1238+
linkage_name: variable_linkage_name,
1239+
address: get_variable_address(&variable_location),
12021240
}))
12031241
}
12041242
(Ok(variable_name), Err(type_error)) => {

0 commit comments

Comments
 (0)