Skip to content

Commit 46cdc7f

Browse files
authored
Rework host commands (#710)
* Rework `host` commands This aims to support oxidecomputer/hubris#2518, but also remedy oxidecomputer/hubris#2586. * Update snapshot tests * De-dupe some code
1 parent 2797e9a commit 46cdc7f

3 files changed

Lines changed: 148 additions & 35 deletions

File tree

cmd/host/src/lib.rs

Lines changed: 146 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,15 @@
100100
//! # etc...
101101
//! ```
102102
103-
use anyhow::{Result, anyhow};
103+
use anyhow::{Result, bail};
104104
use chrono::DateTime;
105105
use clap::Parser;
106106

107107
use humility::{
108108
core::Core,
109109
hubris::HubrisArchive,
110110
log::{Logger, info, warn},
111-
reflect,
112-
reflect::Load,
111+
reflect::{self, Load, Value},
113112
};
114113
use humility_cli::{ExecutionContext, humility_cmd};
115114
use humility_doppel as doppel;
@@ -154,9 +153,24 @@ static SEPARATE_HOST_BOOT_FAIL_NAME: &str = "LAST_HOST_BOOT_FAIL";
154153

155154
static SEPARATE_LAST_HOST_PANIC_NAME: &str = "LAST_HOST_PANIC";
156155

157-
static HOST_STATE_BUF_NAME: &str =
156+
// Pre-2544
157+
static HOST_STATE_BUF_NAME_1: &str =
158158
"task_host_sp_comms::ServerImpl::claim_static_resources::BUFS";
159159

160+
// Post-2544
161+
static HOST_STATE_BUF_NAME_2: &str =
162+
"<task_host_sp_comms::ServerImpl>::claim_static_resources::BUFS";
163+
164+
static PACKRAT_BUF_NAME: &str = "task_packrat::main::BUFS";
165+
166+
// packrat field names
167+
const PACKRAT_LAST_PANIC_PAYLOAD: &str =
168+
"cell.value.host_info.host_panic_payload";
169+
const PACKRAT_LAST_PANIC_STATE: &str = "cell.value.host_info.host_panic_state";
170+
const PACKRAT_BOOT_FAIL_PAYLOAD: &str =
171+
"cell.value.host_info.host_panic_payload";
172+
const PACKRAT_BOOT_FAIL_STATE: &str = "cell.value.host_info.host_panic_state";
173+
160174
/// Mirror type of the internal buf struct in `host_sp_comms`. Must be kept in
161175
/// (partial) sync with that structure (fields that are present need to match,
162176
/// other fields can be ignored).
@@ -229,48 +243,147 @@ fn print_escaped_ascii(mut bytes: &[u8]) {
229243
println!("{buf}");
230244
}
231245

246+
/// Try getting last panic/boot fail from packrat, where it moved to in
247+
/// https://github.com/oxidecomputer/hubris/pull/2518.
248+
fn host_bootinfo_packrat(
249+
hubris: &HubrisArchive,
250+
core: &mut dyn Core,
251+
payload: &str,
252+
state: &str,
253+
) -> Result<Option<Vec<u8>>> {
254+
// If this variable doesn't exist, we're probably on a REALLY old version
255+
// of hubris, but don't return the error here, as it means we'll still want
256+
// to check the host-sp-comms's vars.
257+
let lookup = hubris.lookup_qualified_variable(PACKRAT_BUF_NAME);
258+
let Ok(buf_ty) = lookup else {
259+
return Ok(None);
260+
};
261+
262+
// We do ? the error here, because errors while loading indicate some
263+
// kind of transport error.
264+
let buf: Value = humility::reflect::read_variable(hubris, core, buf_ty)?;
265+
266+
// Again, it's possible the image DOES have the packrat buf, but NOT this
267+
// field (either it is older than #2518, or it is a hostless SP), so treat
268+
// errors here as "no data".
269+
let res_payload: Result<Vec<u8>> = buf.field(payload);
270+
let res_state: Result<Option<Value>> = buf.field(state);
271+
272+
let (Ok(mut payload), Ok(state)) = (res_payload, res_state) else {
273+
return Ok(None);
274+
};
275+
276+
// Cool, cool, we have the fields! Now check if the state is in a place
277+
// where there is something reasonable to extract. If the variables DO
278+
// exist, but DON'T have data, return an empty vec.
279+
let Some(state) = state else {
280+
return Ok(Some(vec![]));
281+
};
282+
283+
let total: u32 = state.field("total_length")?;
284+
payload.truncate(total as usize);
285+
286+
Ok(Some(payload))
287+
}
288+
289+
fn host_boot_fail_spcomms_old(
290+
hubris: &HubrisArchive,
291+
core: &mut dyn Core,
292+
) -> Result<Option<Vec<u8>>> {
293+
read_uqvar(hubris, core, SEPARATE_HOST_BOOT_FAIL_NAME)
294+
}
295+
296+
fn host_boot_fail_spcomms_new(
297+
hubris: &HubrisArchive,
298+
core: &mut dyn Core,
299+
base_buf: &str,
300+
) -> Result<Option<Vec<u8>>> {
301+
let buf = read_qualified_state_buf(hubris, core, base_buf)?;
302+
let maybe_bf = buf.map(|b| b.last_boot_fail);
303+
Ok(maybe_bf)
304+
}
305+
306+
/// Try getting boot fail from packrat, where it moved to in
307+
/// https://github.com/oxidecomputer/hubris/pull/2518.
232308
fn host_boot_fail(hubris: &HubrisArchive, core: &mut dyn Core) -> Result<()> {
233-
// Try old name:
234-
let d = read_uqvar(hubris, core, SEPARATE_HOST_BOOT_FAIL_NAME)?;
235-
if let Some(d) = d {
236-
print_escaped_ascii(&d);
237-
return Ok(());
238-
}
239-
// Try new name
240-
let buf = read_qualified_state_buf(hubris, core, HOST_STATE_BUF_NAME)?
241-
.ok_or_else(|| {
242-
anyhow!(
243-
"Could not find host boot variables under any known name; \
244-
is this a Gimlet image?"
309+
// Work through the different places "boot fail" info could be hiding
310+
let sources: [fn(&HubrisArchive, &mut dyn Core) -> _; _] = [
311+
|h, c| {
312+
host_bootinfo_packrat(
313+
h,
314+
c,
315+
PACKRAT_BOOT_FAIL_PAYLOAD,
316+
PACKRAT_BOOT_FAIL_STATE,
245317
)
246-
})?;
318+
},
319+
host_boot_fail_spcomms_old,
320+
|h, c| host_boot_fail_spcomms_new(h, c, HOST_STATE_BUF_NAME_1),
321+
|h, c| host_boot_fail_spcomms_new(h, c, HOST_STATE_BUF_NAME_2),
322+
];
323+
324+
for source in sources {
325+
if let Some(bootfail) = source(hubris, core)? {
326+
print_escaped_ascii(&bootfail);
327+
return Ok(());
328+
}
329+
}
247330

248-
print_escaped_ascii(&buf.last_boot_fail[..]);
331+
bail!(
332+
"Could not find host boot variables under any known name; is this a \
333+
Gimlet image?"
334+
)
335+
}
249336

250-
Ok(())
337+
/// In host-sp-comms, with the legacy-ish name
338+
fn host_last_panic_spcomms_old(
339+
hubris: &HubrisArchive,
340+
core: &mut dyn Core,
341+
) -> Result<Option<Vec<u8>>> {
342+
read_uqvar(hubris, core, SEPARATE_LAST_HOST_PANIC_NAME)
343+
}
344+
345+
/// In host-sp-comms, with the modern-ish name
346+
fn host_last_panic_spcomms_new(
347+
hubris: &HubrisArchive,
348+
core: &mut dyn Core,
349+
base_buf: &str,
350+
) -> Result<Option<Vec<u8>>> {
351+
// Try new name:
352+
let buf = read_qualified_state_buf(hubris, core, base_buf)?;
353+
let maybe_panic = buf.map(|b| b.last_panic);
354+
Ok(maybe_panic)
251355
}
252356

253357
fn host_last_panic(
254358
hubris: &HubrisArchive,
255359
core: &mut dyn Core,
256360
log: &Logger,
257361
) -> Result<()> {
258-
// Try original name:
259-
let d = read_uqvar(hubris, core, SEPARATE_LAST_HOST_PANIC_NAME)?;
260-
if let Some(d) = d {
261-
return print_panic(d, log);
262-
}
263-
264-
// Try new name:
265-
let buf = read_qualified_state_buf(hubris, core, HOST_STATE_BUF_NAME)?
266-
.ok_or_else(|| {
267-
anyhow!(
268-
"Could not find host boot variables under any known name; \
269-
is this a Gimlet image?"
362+
// Work through the different places "last panic" info could be hiding
363+
let sources: [fn(&HubrisArchive, &mut dyn Core) -> _; _] = [
364+
|h, c| {
365+
host_bootinfo_packrat(
366+
h,
367+
c,
368+
PACKRAT_LAST_PANIC_PAYLOAD,
369+
PACKRAT_LAST_PANIC_STATE,
270370
)
271-
})?;
371+
},
372+
host_last_panic_spcomms_old,
373+
|h, c| host_last_panic_spcomms_new(h, c, HOST_STATE_BUF_NAME_1),
374+
|h, c| host_last_panic_spcomms_new(h, c, HOST_STATE_BUF_NAME_2),
375+
];
376+
377+
for source in sources {
378+
if let Some(panic) = source(hubris, core)? {
379+
return print_panic(panic, log);
380+
}
381+
}
272382

273-
print_panic(buf.last_panic, log)
383+
bail!(
384+
"Could not find host boot variables under any known name; is this a \
385+
Gimlet image?"
386+
)
274387
}
275388

276389
fn print_panic(d: Vec<u8>, log: &Logger) -> Result<()> {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
humility: attached to dump
2-
humility host failed: read of 24964 bytes failed: could not find addr 0x24021ff4 in memory
2+
humility host failed: read of 8264 bytes failed: could not find addr 0x24004380 in memory
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
humility: attached to dump
2-
humility host failed: read of 24964 bytes failed: could not find addr 0x24021c1c in memory
2+
humility host failed: read of 8264 bytes failed: could not find addr 0x24004380 in memory

0 commit comments

Comments
 (0)