Skip to content

Commit 1ce2c68

Browse files
committed
Implement "exported" variables allowing to pull data from firmware.
1 parent 2015a66 commit 1ce2c68

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

teleprobe-meta/teleprobe.x

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ SECTIONS
88
{
99
KEEP(*(.teleprobe.timeout));
1010
}
11-
}
11+
.teleprobe.export (INFO) :
12+
{
13+
KEEP(*(.teleprobe.export));
14+
}
15+
}

teleprobe/src/run.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ struct Runner {
5656
defmt_stream: Box<dyn StreamDecoder>,
5757

5858
di: DebugInfo,
59+
60+
exports: BTreeMap<String, u32>,
5961
}
6062

6163
unsafe fn fuck_it<'a, 'b, T>(wtf: &'a T) -> &'b T {
@@ -117,6 +119,36 @@ impl Runner {
117119
let vector_table = vector_table.ok_or_else(|| anyhow!("`.vector_table` section is missing"))?;
118120
log::debug!("vector table: {:x?}", vector_table);
119121

122+
// Build a map of exported variables, based on addresses found in the
123+
// '.teleprobe.export' section.
124+
let mut export_map = BTreeMap::new();
125+
126+
if let Some(section) = elf.section_by_name(".teleprobe.export") {
127+
let ptrs = section
128+
.data()?
129+
.chunks_exact(4)
130+
.map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()))
131+
.collect::<Vec<_>>();
132+
133+
if ptrs.len() > 0 {
134+
info!("Found {} exported variables: {:#0x?}", ptrs.len(), ptrs);
135+
136+
// TODO: Is there a better way?
137+
for symbol in elf.symbols() {
138+
if ptrs.contains(&(symbol.address() as u32)) {
139+
let addr = symbol.address() as u32;
140+
let name = String::from(symbol.name().unwrap());
141+
// Filter out private symbols, otherwise we get some false-positives
142+
if name.starts_with("__") {
143+
continue;
144+
}
145+
export_map.insert(String::from(symbol.name().unwrap()), addr);
146+
info!("Found match for addr {:?} -> {:?}", &addr, &name);
147+
}
148+
}
149+
}
150+
}
151+
120152
// reset ALL cores other than the main one.
121153
// This is needed for rp2040 core1.
122154
for (i, _) in sess.list_cores() {
@@ -244,6 +276,7 @@ impl Runner {
244276
defmt,
245277
defmt_stream,
246278
di,
279+
exports: export_map,
247280
})
248281
}
249282

@@ -342,6 +375,30 @@ impl Runner {
342375
bail!("Firmware crashed");
343376
}
344377

378+
// Look up exported symbols
379+
for (symbol, addr) in &self.exports {
380+
let mut buf = [0; 64];
381+
/*
382+
// XXX: Ideally we should use demangling information to
383+
// either handle references ie bytestrings are stored as
384+
// pointers to data. But for now, we only support hardcoded
385+
// byte arrays of length 64.
386+
let ptr = core.read_word_32(*addr as u64).unwrap();
387+
let _ = core.read(ptr as u64, &mut buf).unwrap();
388+
*/
389+
// TODO: Error handling?
390+
let _ = core.read(*addr as u64, &mut buf).unwrap();
391+
match String::from_utf8(buf.to_vec()) {
392+
Ok(s) => {
393+
info!("Found: {} -> {}", symbol, s);
394+
}
395+
Err(_) => {
396+
warn!("Data for {} not found!", symbol);
397+
}
398+
}
399+
}
400+
// TODO: Export our wanted symbols?
401+
345402
Ok(())
346403
}
347404

@@ -439,7 +496,7 @@ impl Runner {
439496
fn dump_state(&mut self, core: &mut Core, force: bool) -> anyhow::Result<bool> {
440497
core.halt(TIMEOUT)?;
441498

442-
// determine if the target is handling an interupt
499+
// determine if the target is handling an interrupt
443500
let xpsr: u32 = core.read_core_reg(XPSR)?;
444501
let exception_number = xpsr & 0xff;
445502
match exception_number {

0 commit comments

Comments
 (0)