Skip to content

Fix tracing cow changes#1260

Open
dblnz wants to merge 5 commits intohyperlight-dev:mainfrom
dblnz:fix-tracing-cow-changes
Open

Fix tracing cow changes#1260
dblnz wants to merge 5 commits intohyperlight-dev:mainfrom
dblnz:fix-tracing-cow-changes

Conversation

@dblnz
Copy link
Contributor

@dblnz dblnz commented Feb 25, 2026

Description

This PR fixes #1242.
The guest tracing data received by the host assumes identity mapped addresses, the address needs to be translated to correctly decode the flatbuffers data.

This can be reviewed commit by commit.
The first commit tackles this issue, the other two improve on the spans and usability.

@dblnz dblnz requested a review from danbugs as a code owner February 25, 2026 16:37
@dblnz dblnz added the kind/bugfix For PRs that fix bugs label Feb 25, 2026
@dblnz dblnz force-pushed the fix-tracing-cow-changes branch from 78fb1fe to 6176db1 Compare February 25, 2026 16:46
@danbugs danbugs mentioned this pull request Feb 25, 2026
17 tasks
@ludfjig ludfjig requested a review from Copilot February 25, 2026 18:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes guest→host tracing breakage introduced by CoW by translating the guest-provided trace buffer pointer (GVA) via a page-table walk (using CR3) before decoding the FlatBuffer trace batch. It also refines guest-side spans around initialization/dispatch to improve trace usability and reduce mismatched span warnings.

Changes:

  • Translate trace batch pointers from GVA→GPA on the host (CR3-driven page table walk) before decoding trace FlatBuffers.
  • Update the guest↔host tracing ABI to pass trace batch metadata via r12/r13/r14 and adjust host handling accordingly.
  • Improve guest tracing spans around generic_init and internal_dispatch_function and enable Debug printing of FunctionCall.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/hyperlight_host/src/sandbox/trace/context.rs Switch trace batch extraction to read via GVA translation and new from_regs API.
src/hyperlight_host/src/sandbox/snapshot.rs Expose helpers for resolving GPAs and reading page tables from shared/scratch memory.
src/hyperlight_host/src/mem/mgr.rs Add read_guest_memory_by_gva that walks page tables and reads from shared/scratch backing.
src/hyperlight_host/src/hypervisor/hyperlight_vm.rs Pass CR3 into trace handling and adjust when trace handling is attempted.
src/hyperlight_guest_tracing/src/state.rs Send trace batch pointer/len via r12/r13/r14 in the OUT instruction.
src/hyperlight_guest_bin/src/lib.rs Add a generic_init span and flush/close ordering to avoid host span warnings.
src/hyperlight_guest_bin/src/guest_function/call.rs Add an internal_dispatch_function span and trace log the FunctionCall in debug builds.
src/hyperlight_guest/src/exit.rs Update OUT path to attach trace batch metadata via r12/r13/r14.
src/hyperlight_common/src/vmem.rs Update comment noting virt_to_phys is now used for tracing reads.
src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs Derive Debug for FunctionCall to support tracing output.

Copy link
Contributor

@ludfjig ludfjig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to be but not too familiar with this code. BTW why were the registers changed? Also, should we have tests to make sure this doesn't break in the future again?

@dblnz dblnz force-pushed the fix-tracing-cow-changes branch from 6176db1 to fb1f56a Compare February 26, 2026 16:31
@dblnz
Copy link
Contributor Author

dblnz commented Feb 26, 2026

BTW why were the registers changed?

The registers changed because I wanted to ensure the registers used couldn't be overwritten when returning from a function (currently, we set the registers in preparation for a hlt to execute, and the hlt instruction is written in assembly after the call generic_init or call internal_dispatch_function finishes).
By reading some more info on calling convention, it looks like r12,r13,r14 are preserved registers.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

@dblnz dblnz force-pushed the fix-tracing-cow-changes branch from fb1f56a to bff35d2 Compare February 27, 2026 09:36
@dblnz dblnz requested review from jsturtevant and ludfjig February 27, 2026 10:32
@dblnz dblnz force-pushed the fix-tracing-cow-changes branch from bff35d2 to 18bbbf3 Compare March 2, 2026 07:49
@syntactically
Copy link
Member

At a high level, I think it adds some complexity in the long term to do everything in terms of VAs here, even if it requires fewer changes in the guest immediately to not need to deal with making sure the buffer allocation is contiguous (think like how big kernels do DMA-pinned memory). The specific way that the host code accesses the trace buffers looks to me like it will be fairly slow as well. However, perhaps these are not major concerns if we are going to switch to using the same ring buffer transport as all other asyncio soon. (Side comment: we should definitely still be batching these trace records when we do that---descriptor capacity is limited and these records are tiny individually afaiui.)

BTW why were the registers changed?

The registers changed because I wanted to ensure the registers used couldn't be overwritten when returning from a function (currently, we set the registers in preparation for a hlt to execute, and the hlt instruction is written in assembly after the call generic_init or call internal_dispatch_function finishes). By reading some more info on calling convention, it looks like r12,r13,r14 are preserved registers.

  • Where are we setting the registers and then returning to hlt? Both of the call sites in fa7873d look like they directly do the outb.
  • If we are actually doing that somewhere, this reading of "preserved" is backwards---if you look at the abi it uses the much more illuminating name "callee-save": i.e. if some code calls another function, it should expect by the time of the return that those registers have been restored to whatever they were before, and can do whatever it wants with them. So, not only does using these registers not prevent them being overwritten during the prologue for generic_init, it actually makes it an ABI violation for generic_init not to do that.

@dblnz
Copy link
Contributor Author

dblnz commented Mar 2, 2026

At a high level, I think it adds some complexity in the long term to do everything in terms of VAs here, even if it requires fewer changes in the guest immediately to not need to deal with making sure the buffer allocation is contiguous (think like how big kernels do DMA-pinned memory). The specific way that the host code accesses the trace buffers looks to me like it will be fairly slow as well. However, perhaps these are not major concerns if we are going to switch to using the same ring buffer transport as all other asyncio soon. (Side comment: we should definitely still be batching these trace records when we do that---descriptor capacity is limited and these records are tiny individually afaiui.)

I chose to use VAs because it seemed simpler to access the guest trace buffers that way. My plan is to definitely use the asyncio features once we have them and get rid of the logic handling the buffer info exchanges between the guest and host.

Where are we setting the registers and then returning to hlt? Both of the call sites in fa7873d look like they directly do the outb.

That's correct, we used to also set those registers before hlt to avoid executing an out instruction before it, be we don't do that any more.

If we are actually doing that somewhere, this reading of "preserved" is backwards---if you look at the abi it uses the much more illuminating name "callee-save": i.e. if some code calls another function, it should expect by the time of the return that those registers have been restored to whatever they were before, and can do whatever it wants with them. So, not only does using these registers not prevent them being overwritten during the prologue for generic_init, it actually makes it an ABI violation for generic_init not to do that.

Thanks for clearing this up for me, I got it backwards

dblnz added 5 commits March 2, 2026 17:21
- With the new Copy-on-Write changes, the guest virtual addresses and
  guest physical addresses are no longer identity mapped, so we need a
  way to do this translation when a new guest trace batch arrives from
  the guest

Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
- The max virtual address was calculated based on the vmin (start of
  page), not the actual virtual address provided

Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
- This is currently done on the guest, but not on the host

Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
- For each call to `internal_dispatch_function` now we create a span
  manually because instrumenting the function would be redundant because
  of the call to `new_call` that resets tracing state for each new
  function call
- The same logic is used for `generic_init` to enable it for the
  initialise call

Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
@dblnz dblnz force-pushed the fix-tracing-cow-changes branch 2 times, most recently from a8c31b0 to dadb693 Compare March 2, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bugfix For PRs that fix bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix guest tracing related to CoW changes

5 participants