Skip to content

Commit de6e1f1

Browse files
committed
Persist guest ELF entry point for crashdump AT_ENTRY
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent bf07797 commit de6e1f1

5 files changed

Lines changed: 51 additions & 4 deletions

File tree

src/hyperlight_host/src/mem/mgr.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ pub(crate) struct SandboxMemoryManager<S: SharedMemory> {
143143
/// The next action to perform when this sandbox resumes:
144144
/// `Initialise` before the guest has run, `Call` afterwards.
145145
pub(crate) next_action: NextAction,
146+
/// Guest virtual address of the guest binary's ELF entry point,
147+
/// preserved across the `Initialise` -> `Call` transition so it
148+
/// can fill `AT_ENTRY` in guest core dumps. 0 if unknown.
149+
pub(crate) original_entrypoint: u64,
146150
/// Buffer for accumulating guest abort messages
147151
pub(crate) abort_buffer: Vec<u8>,
148152
/// Generation counter: how many snapshots have been taken from
@@ -283,6 +287,7 @@ where
283287
shared_mem,
284288
scratch_mem,
285289
next_action,
290+
original_entrypoint: 0,
286291
abort_buffer: Vec::new(),
287292
snapshot_count: 0,
288293
}
@@ -315,6 +320,7 @@ where
315320
rsp_gva,
316321
sregs,
317322
next_action,
323+
self.original_entrypoint,
318324
self.snapshot_count,
319325
host_functions,
320326
)
@@ -328,6 +334,7 @@ impl SandboxMemoryManager<ExclusiveSharedMemory> {
328334
let scratch_mem = ExclusiveSharedMemory::new(s.layout().get_scratch_size())?;
329335
let next_action = s.next_action();
330336
let mut mgr = Self::new(layout, shared_mem, scratch_mem, next_action);
337+
mgr.original_entrypoint = s.original_entrypoint();
331338
// Inherit the snapshot's generation number for the same
332339
// reason `restore_snapshot` does: the guest-visible counter
333340
// reflects "which snapshot is the sandbox currently a clone
@@ -359,6 +366,7 @@ impl SandboxMemoryManager<ExclusiveSharedMemory> {
359366
scratch_mem: hscratch,
360367
layout: self.layout,
361368
next_action: self.next_action,
369+
original_entrypoint: self.original_entrypoint,
362370
abort_buffer: self.abort_buffer,
363371
snapshot_count: self.snapshot_count,
364372
};
@@ -367,6 +375,7 @@ impl SandboxMemoryManager<ExclusiveSharedMemory> {
367375
scratch_mem: gscratch,
368376
layout: self.layout,
369377
next_action: self.next_action,
378+
original_entrypoint: self.original_entrypoint,
370379
abort_buffer: Vec::new(), // Guest doesn't need abort buffer
371380
snapshot_count: self.snapshot_count,
372381
};

src/hyperlight_host/src/sandbox/snapshot/file/config.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ pub(super) struct OciSnapshotConfig {
177177
pub(super) stack_top_gva: u64,
178178
/// Guest virtual address the loader resumes the paused call at.
179179
pub(super) entrypoint_addr: u64,
180+
/// Guest virtual address of the ELF entry point
181+
/// (`load_addr + e_entry - base_va`), preserved across the
182+
/// Initialise->Call transition. Fills `AT_ENTRY` in core dumps so
183+
/// gdb resolves PIE symbols. Optional: snapshots written before
184+
/// this field existed deserialize to `0`, which core-dump code
185+
/// treats as unknown.
186+
#[serde(default)]
187+
pub(super) original_entrypoint_addr: u64,
180188
/// Special registers captured from the paused vCPU, restored
181189
/// verbatim when resuming the call.
182190
pub(super) sregs: CommonSpecialRegisters,
@@ -675,6 +683,7 @@ mod tests {
675683
cpu_vendor: CpuVendor::current(),
676684
stack_top_gva: 0x2000,
677685
entrypoint_addr: SandboxMemoryLayout::BASE_ADDRESS as u64,
686+
original_entrypoint_addr: 0,
678687
sregs: distinct_sregs(),
679688
layout: MemoryLayout {
680689
input_data_size: 0,
@@ -746,6 +755,7 @@ mod schema_pin {
746755
"cpu_vendor": "intel",
747756
"stack_top_gva": 3735928559,
748757
"entrypoint_addr": 8192,
758+
"original_entrypoint_addr": 0,
749759
"sregs": {
750760
"cs": {
751761
"base": 1,
@@ -921,6 +931,7 @@ mod schema_pin {
921931
"cpu_vendor": "intel",
922932
"stack_top_gva": 3735928559,
923933
"entrypoint_addr": 8192,
934+
"original_entrypoint_addr": 0,
924935
"sregs": {
925936
"tcr_el1": 1,
926937
"mair_el1": 2,

src/hyperlight_host/src/sandbox/snapshot/file/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ impl Snapshot {
584584
cpu_vendor: CpuVendor::current(),
585585
stack_top_gva: self.stack_top_gva,
586586
entrypoint_addr,
587+
original_entrypoint_addr: self.original_entrypoint,
587588
sregs: *sregs,
588589
layout: MemoryLayout {
589590
input_data_size: l.input_data_size(),
@@ -872,6 +873,7 @@ impl Snapshot {
872873
stack_top_gva: cfg.stack_top_gva,
873874
sregs: Some(cfg.sregs),
874875
next_action,
876+
original_entrypoint: cfg.original_entrypoint_addr,
875877
snapshot_generation,
876878
host_functions,
877879
})

src/hyperlight_host/src/sandbox/snapshot/mod.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ pub struct Snapshot {
9595
/// The next action that should be performed on this snapshot
9696
next_action: NextAction,
9797

98+
/// Guest virtual address of the guest binary's ELF entry point
99+
/// (`load_addr + e_entry - base_va`). Unlike `next_action`, which
100+
/// transitions to `Call(dispatch_addr)` once the guest has run,
101+
/// this preserves the original entry across that transition. Used
102+
/// to fill `AT_ENTRY` in guest core dumps so a debugger can
103+
/// compute the PIE load bias. 0 if unknown (e.g. an older
104+
/// on-disk snapshot that predates this field).
105+
original_entrypoint: u64,
106+
98107
/// The generation number assigned to this snapshot when it was
99108
/// taken — i.e. "this is the Nth snapshot taken from the sandbox's
100109
/// execution path from init to here". Propagated into the
@@ -375,13 +384,16 @@ impl Snapshot {
375384
- hyperlight_common::layout::SCRATCH_TOP_EXN_STACK_OFFSET
376385
+ 1;
377386

387+
let entrypoint_gva = load_addr + entrypoint_va - base_va;
388+
378389
Ok(Self {
379390
memory: ReadonlySharedMemory::from_bytes(&memory, layout.snapshot_size())?,
380391
layout,
381392
load_info,
382393
stack_top_gva: exn_stack_top_gva,
383394
sregs: None,
384-
next_action: NextAction::Initialise(load_addr + entrypoint_va - base_va),
395+
next_action: NextAction::Initialise(entrypoint_gva),
396+
original_entrypoint: entrypoint_gva,
385397
snapshot_generation: 0,
386398
host_functions: HostFunctionDetails {
387399
host_functions: None,
@@ -408,6 +420,7 @@ impl Snapshot {
408420
stack_top_gva: u64,
409421
sregs: CommonSpecialRegisters,
410422
next_action: NextAction,
423+
original_entrypoint: u64,
411424
snapshot_generation: u64,
412425
host_functions: HostFunctionDetails,
413426
) -> Result<Self> {
@@ -561,6 +574,7 @@ impl Snapshot {
561574
stack_top_gva,
562575
sregs: Some(sregs),
563576
next_action,
577+
original_entrypoint,
564578
snapshot_generation,
565579
host_functions,
566580
})
@@ -607,6 +621,13 @@ impl Snapshot {
607621
self.next_action
608622
}
609623

624+
/// Guest virtual address of the guest binary's ELF entry point,
625+
/// preserved across the `Initialise` -> `Call` transition. Used
626+
/// to fill `AT_ENTRY` in guest core dumps. 0 if unknown.
627+
pub(crate) fn original_entrypoint(&self) -> u64 {
628+
self.original_entrypoint
629+
}
630+
610631
/// Validate that `provided` is a superset of the host functions
611632
/// recorded in this snapshot: every function that was registered
612633
/// at snapshot time must also be present in `provided` with a
@@ -762,6 +783,7 @@ mod tests {
762783
0,
763784
default_sregs(),
764785
super::NextAction::None,
786+
0,
765787
1,
766788
HostFunctionDetails::default(),
767789
)
@@ -779,6 +801,7 @@ mod tests {
779801
0,
780802
default_sregs(),
781803
super::NextAction::None,
804+
0,
782805
2,
783806
HostFunctionDetails::default(),
784807
)

src/hyperlight_host/src/sandbox/uninitialized_evolve.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,14 @@ pub(crate) fn set_up_hypervisor_partition(
153153
// Store the original entry point address in the runtime config for core dumps.
154154
// This is needed because `next_action` transitions from `Initialise(addr)` to
155155
// `Call(dispatch_addr)` after guest initialisation, losing the original value
156-
// that GDB needs to compute the PIE binary's load offset.
156+
// that GDB needs to compute the PIE binary's load offset. The manager carries
157+
// it across that transition (and across snapshot save/restore), so it is
158+
// correct for both the evolve path and `MultiUseSandbox::from_snapshot`.
157159
#[cfg(crashdump)]
158160
let rt_cfg = {
159161
let mut rt_cfg = rt_cfg;
160-
if let crate::sandbox::snapshot::NextAction::Initialise(addr) = mgr.next_action {
161-
rt_cfg.entry_point = Some(addr);
162+
if mgr.original_entrypoint != 0 {
163+
rt_cfg.entry_point = Some(mgr.original_entrypoint);
162164
}
163165
rt_cfg
164166
};

0 commit comments

Comments
 (0)