Skip to content

Commit 60d2361

Browse files
committed
Move registers out of HubrisArchive
1 parent 73ca69e commit 60d2361

4 files changed

Lines changed: 76 additions & 68 deletions

File tree

humility-cli/src/lib.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,7 @@ impl Cli {
278278
validate: Option<HubrisValidate>,
279279
) -> Result<Box<dyn Core>> {
280280
let mut core = if let Some(dump) = &self.dump {
281-
let Some(hubris) = hubris else {
282-
bail!("cannot load dump without archive");
283-
};
284-
humility::core::attach_dump(dump, hubris)?
281+
humility::core::attach_dump(dump)?
285282
} else if let Some(ip) = &self.ip {
286283
let Some(hubris) = hubris else {
287284
bail!("cannot connect over the network without archive");
@@ -328,9 +325,9 @@ impl Cli {
328325
/// Attaches to a dump
329326
///
330327
/// Reads from the `--dump` argument to pick a target file
331-
pub fn attach_dump(&self, hubris: &HubrisArchive) -> Result<Box<dyn Core>> {
328+
pub fn attach_dump(&self) -> Result<Box<dyn Core>> {
332329
let core = if let Some(dump) = &self.dump {
333-
humility::core::attach_dump(dump, hubris)?
330+
humility::core::attach_dump(dump)?
334331
} else {
335332
bail!("must be run against a dump");
336333
};

humility-core/src/core.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,8 @@ pub enum NetAgent {
129129
Hiffy,
130130
}
131131

132-
pub fn attach_dump(
133-
dump: &str,
134-
hubris: &HubrisArchive,
135-
) -> Result<Box<dyn Core>> {
136-
let core = DumpCore::new(dump, hubris)?;
132+
pub fn attach_dump(dump: &str) -> Result<Box<dyn Core>> {
133+
let core = DumpCore::new(dump)?;
137134
crate::msg!("attached to dump");
138135
Ok(Box::new(core))
139136
}

humility-core/src/dump.rs

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

55
use crate::core::Core;
6-
use crate::hubris::HubrisArchive;
7-
use anyhow::{Result, anyhow, bail};
6+
use crate::hubris::OXIDE_NT_HUBRIS_REGISTERS;
7+
use anyhow::{Context, Result, anyhow, bail};
88
use goblin::elf::Elf;
99
use humility_arch_arm::ARMRegister;
10+
use num_traits::FromPrimitive;
1011
use std::collections::{BTreeMap, HashMap};
1112
use std::fs::File;
1213
use std::io::Read;
@@ -15,11 +16,11 @@ use std::path::Path;
1516
pub struct DumpCore {
1617
contents: Vec<u8>,
1718
regions: BTreeMap<u32, (u32, usize)>,
18-
registers: HashMap<ARMRegister, u32>,
19+
registers: Option<HashMap<ARMRegister, u32>>,
1920
}
2021

2122
impl DumpCore {
22-
pub(crate) fn new(dump: &str, hubris: &HubrisArchive) -> Result<DumpCore> {
23+
pub(crate) fn new(dump: &str) -> Result<DumpCore> {
2324
let mut file = File::open(dump)?;
2425
let mut regions = BTreeMap::new();
2526

@@ -41,7 +42,23 @@ impl DumpCore {
4142
);
4243
}
4344

44-
Ok(Self { contents, regions, registers: hubris.dump_registers() })
45+
let mut registers = None;
46+
if let Some(notes) = elf.iter_note_headers(&contents) {
47+
for note in notes {
48+
let note = note.context("failed to parse note")?;
49+
if note.n_type == OXIDE_NT_HUBRIS_REGISTERS {
50+
if registers.is_some() {
51+
bail!(
52+
"multiple copies of OXIDE_NT_HUBRIS_REGISTERS \
53+
found in dump"
54+
);
55+
}
56+
registers = Some(load_registers(note.desc)?);
57+
}
58+
}
59+
}
60+
61+
Ok(Self { contents, regions, registers })
4562
}
4663

4764
fn check_offset(&self, addr: u32, rsize: usize, offs: usize) -> Result<()> {
@@ -67,6 +84,38 @@ impl DumpCore {
6784
}
6885
}
6986

87+
fn load_registers(r: &[u8]) -> Result<HashMap<ARMRegister, u32>> {
88+
if !r.len().is_multiple_of(8) {
89+
bail!("bad length {} in registers note", r.len());
90+
}
91+
let mut registers = HashMap::new();
92+
for (i, chunk) in r.chunks_exact(8).enumerate() {
93+
let (id, val) = chunk.split_at(4);
94+
// We unwrap here because it can only fail if the length is wrong,
95+
// but we've explicitly broken a chunk of 8 into two chunks of 4,
96+
// so a failure here would mean this code has been changed.
97+
let id = u32::from_le_bytes(id.try_into().unwrap());
98+
let val = u32::from_le_bytes(val.try_into().unwrap());
99+
100+
let reg = match ARMRegister::from_u32(id) {
101+
Some(r) => r,
102+
None => {
103+
// This can totally happen if we encounter a future coredump
104+
// where we decided to store, say, additional MSRs or a
105+
// floating point register. Since this version of Humility
106+
// doesn't understand them, we'll just skip it.
107+
continue;
108+
}
109+
};
110+
111+
if registers.insert(reg, val).is_some() {
112+
bail!("duplicate register {} ({}) at offset {}", reg, id, i * 8);
113+
}
114+
}
115+
116+
Ok(registers)
117+
}
118+
70119
#[rustfmt::skip::macros(bail)]
71120
impl Core for DumpCore {
72121
fn info(&self) -> (String, Option<String>) {
@@ -114,10 +163,15 @@ impl Core for DumpCore {
114163
}
115164

116165
fn read_reg(&mut self, reg: ARMRegister) -> Result<u32> {
117-
if let Some(val) = self.registers.get(&reg) {
118-
Ok(*val)
119-
} else {
120-
bail!("register {} not found in dump", reg);
166+
match &self.registers {
167+
Some(regs) => {
168+
if let Some(val) = regs.get(&reg) {
169+
Ok(*val)
170+
} else {
171+
bail!("register {} not found in dump", reg);
172+
}
173+
}
174+
None => bail!("dump does not include register info"),
121175
}
122176
}
123177

humility-core/src/hubris.rs

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ use rustc_demangle::demangle;
3333
use scroll::{IOwrite, Pwrite};
3434
use zerocopy::{FromBytes, IntoBytes};
3535

36-
const OXIDE_NT_NAME: &str = "Oxide Computer Company";
37-
const OXIDE_NT_BASE: u32 = 0x1de << 20;
38-
const OXIDE_NT_HUBRIS_ARCHIVE: u32 = OXIDE_NT_BASE + 1;
39-
const OXIDE_NT_HUBRIS_REGISTERS: u32 = OXIDE_NT_BASE + 2;
40-
const OXIDE_NT_HUBRIS_TASK: u32 = OXIDE_NT_BASE + 3;
36+
pub const OXIDE_NT_NAME: &str = "Oxide Computer Company";
37+
pub const OXIDE_NT_BASE: u32 = 0x1de << 20;
38+
pub const OXIDE_NT_HUBRIS_ARCHIVE: u32 = OXIDE_NT_BASE + 1;
39+
pub const OXIDE_NT_HUBRIS_REGISTERS: u32 = OXIDE_NT_BASE + 2;
40+
pub const OXIDE_NT_HUBRIS_TASK: u32 = OXIDE_NT_BASE + 3;
4141

4242
const MAX_HUBRIS_VERSION: u32 = 11;
4343

@@ -743,9 +743,6 @@ pub struct HubrisArchive {
743743
// Manual stack pushes before a syscall
744744
syscall_pushes: HashMap<u32, Option<Vec<ARMRegister>>>,
745745

746-
// Current registers (if a dump)
747-
registers: HashMap<ARMRegister, u32>,
748-
749746
// Modules: text address to module
750747
modules: BTreeMap<u32, HubrisModule>,
751748

@@ -838,7 +835,6 @@ impl HubrisArchive {
838835
task_dump: None,
839836
instrs: HashMap::new(),
840837
syscall_pushes: HashMap::new(),
841-
registers: HashMap::new(),
842838
modules: BTreeMap::new(),
843839
tasks: HashMap::new(),
844840
frames: HashMap::new(),
@@ -1784,38 +1780,6 @@ impl HubrisArchive {
17841780
flash.chip
17851781
}
17861782

1787-
fn load_registers(&mut self, r: &[u8]) -> Result<()> {
1788-
if !r.len().is_multiple_of(8) {
1789-
bail!("bad length {} in registers note", r.len());
1790-
}
1791-
1792-
for (i, chunk) in r.chunks_exact(8).enumerate() {
1793-
let (id, val) = chunk.split_at(4);
1794-
// We unwrap here because it can only fail if the length is wrong,
1795-
// but we've explicitly broken a chunk of 8 into two chunks of 4,
1796-
// so a failure here would mean this code has been changed.
1797-
let id = u32::from_le_bytes(id.try_into().unwrap());
1798-
let val = u32::from_le_bytes(val.try_into().unwrap());
1799-
1800-
let reg = match ARMRegister::from_u32(id) {
1801-
Some(r) => r,
1802-
None => {
1803-
// This can totally happen if we encounter a future coredump
1804-
// where we decided to store, say, additional MSRs or a
1805-
// floating point register. Since this version of Humility
1806-
// doesn't understand them, we'll just skip it.
1807-
continue;
1808-
}
1809-
};
1810-
1811-
if self.registers.insert(reg, val).is_some() {
1812-
bail!("duplicate register {} ({}) at offset {}", reg, id, i * 8);
1813-
}
1814-
}
1815-
1816-
Ok(())
1817-
}
1818-
18191783
/// Destroys the `HubrisArchive`, returning the raw archive data
18201784
pub fn take_raw_archive(self) -> Vec<u8> {
18211785
self.archive
@@ -1850,9 +1814,6 @@ impl HubrisArchive {
18501814

18511815
self.archive = note.desc.to_vec();
18521816
}
1853-
OXIDE_NT_HUBRIS_REGISTERS => {
1854-
self.load_registers(note.desc)?;
1855-
}
18561817
OXIDE_NT_HUBRIS_TASK => {
18571818
match DumpTask::read_from_prefix(note.desc) {
18581819
Ok((task, _)) => {
@@ -1866,6 +1827,9 @@ impl HubrisArchive {
18661827
}
18671828
}
18681829
}
1830+
OXIDE_NT_HUBRIS_REGISTERS => {
1831+
// unused when building the archive, but valid
1832+
}
18691833
_ => {
18701834
bail!("unrecognized note 0x{:x}", note.n_type);
18711835
}
@@ -2852,10 +2816,6 @@ impl HubrisArchive {
28522816
Ok(regions)
28532817
}
28542818

2855-
pub fn dump_registers(&self) -> HashMap<ARMRegister, u32> {
2856-
self.registers.clone()
2857-
}
2858-
28592819
pub fn registers(
28602820
&self,
28612821
core: &mut dyn crate::core::Core,

0 commit comments

Comments
 (0)