uhyve
uhyve copied to clipboard
Exit with a non-zero exitcode if the kernel panics.
Uhyve should exit with a non-zero exitcode if the kernel panics. This is important for testing rusty-hermit with uhyve and CI, since I'm not a fan of parsing the output of stdout or stderr to determine if a program failed.
I'm not sure if Uhyve always returns a zero, but at least in the cases I've seen where uhyve shuts down due to a panic of the kernel, the exit code was zero.
This is can easily be implemented, as the signal for the shutdown of the hypervisor is writing an value to a certain COM port. So you can return an arbitrary return code from the application and for example return another value in the panic handler than on regular shutdown.
I've already implemented this for uhyve's little sibling - ehyve. It can be easily backported for uhyve.
Would this be sufficient?
Yes, That would be absolutely sufficient. Thanks for your help :)
Took me embarrasingly long to realize, but this is actually the behaviour that uhyve has by default.
Panicing
#[cfg(target_os = "hermit")]
extern crate hermit_sys;
fn main() {
println!("Hello World!");
panic!("asdf");
}
> cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit
# [...]
> uhyve target/x86_64-unknown-hermit/debug/hermit-new
Hello World!
thread 'main' panicked at 'asdf', src/main.rs:6:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
> echo $?
255
Return Error
#[cfg(target_os = "hermit")]
extern crate hermit_sys;
use std::io::{Error, ErrorKind};
fn main() -> Result<(), std::io::Error> {
println!("Hello World!");
Err(Error::new(ErrorKind::Other, "oh no!"))
}
> uhyve target/x86_64-unknown-hermit/debug/hermit-new
Hello World!
Error: Custom { kind: Other, error: "oh no!" }
> echo $?
1
I'd like to reopen this issue. I checked and the two examples you posted work for me too. However this does not work for all cases. To reproduce do the following:
- Clone rusty-hermit
- Checkout devel branch
- Switch to a new branch at commit 4b74fa4889f60c27eda89c40d3b22598ffc54ff5 (newer commits are not building for me)
- Initialize and update submodules
- Run
cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit
- Run
uhyve -v target/x86_64-unknown-hermit/debug/rusty_demo
- Verify that this works and return code is 0 (no problem here)
-
cd libhermit-rs/src/arch/x86_64
- Comment out lines 411 to 415 so that the we run into the "expect".
- cd back to rusty-hermit
- Run
cargo clean
- Run
cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit
- Run
uhyve -v target/x86_64-unknown-hermit/debug/rusty_demo
- Run
echo $?
. For me this gives 0, even though rusty-hermit crashed.
This also shows an issue that rusty-hermit may have when handling panics, but I should probably create a separate issue for that, since that isn't uhyve related.
Output of step 13
[0][INFO] Welcome to HermitCore-rs 0.3.26
[0][INFO] Kernel starts at 0x200000
[0][INFO] BSS starts at 0x445600
[0][INFO] TLS starts at 0x443828 (size 264 Bytes)
[0][INFO] Total memory size: 64 MB
[0][INFO] A pure Rust application is running on top of HermitCore!
[0][INFO] Heap: size 50 MB, start address 0x600000
[0][INFO] Heap is located at 0x600000 -- 0x3800000 (0 Bytes unmapped)
[0][INFO]
[0][INFO] ===================== PHYSICAL MEMORY FREE LIST ======================
[0][INFO] 0x00000003800000 - 0x00000004000000
[0][INFO] ======================================================================
[0][INFO]
[0][INFO]
[0][INFO] ================== KERNEL VIRTUAL MEMORY FREE LIST ===================
[0][INFO] 0x00000003800000 - 0x00800000000000
[0][INFO] ======================================================================
[0][INFO]
[0][TRACE] __sys_malloc: allocate memory at 0x6000e8 (size 0x408, align 0x8)
[0][ERROR] Page Fault (#PF) Exception: ExceptionStackFrame {
instruction_pointer: 0x38c66b,
code_segment: 0x8,
cpu_flags: 0x10287,
stack_pointer: 0x1ffb90,
stack_segment: 0x10,
}
[0][ERROR] virtual_address = 0x3830000, page fault error = The fault was caused by a non-present page.
The access causing the fault was a read.
The access causing the fault originated when the processor was executing in supervisor mode.
The fault was not caused by reserved bit violation.
The fault was not caused by an instruction fetch.
[0][ERROR] fs = 0x0, gs = 0x447728
[0][ERROR] General Protection (#GP) Exception: ExceptionStackFrame {
[Redacted everything inbetween here since I hit the Character limit]
[0][ERROR] General Protection (#GP) Exception: ExceptionStackFrame {
Dump state of CPU 0
Registers:
----------
kvm_regs { rax: 3026652, rbx: 3026652, rcx: 19, rdx: 3026652, rsi: 19, rdi: 3026652, rsp: 73728, rbp: 0, r8: 19, r9: 1, r10: 0, r11: 0, r12: 19, r13: 73824, r14: 19, r15: 0, rip: 3799712, rflags: 65554 }kvm_sregs { cs: kvm_segment { base: 0, limit: 0, selector: 8, type_: 11, present: 1, dpl: 0, db: 0, s: 1, l: 1, g: 0, avl: 0, unusable: 0, padding: 0 }, ds: kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, es: kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, fs: kvm_segment { base: 0, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, gs: kvm_segment { base: 4486952, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, ss: kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, tr: kvm_segment { base: 6291456, limit: 103, selector: 24, type_: 11, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, ldt: kvm_segment { base: 0, limit: 65535, selector: 0, type_: 2, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }, gdt: kvm_dtable { base: 58720256, limit: 65535, padding: [0, 0, 0] }, idt: kvm_dtable { base: 4482844, limit: 4095, padding: [0, 0, 0] }, cr0: 2147549235, cr2: 6291500, cr3: 65536, cr4: 329312, cr8: 0, efer: 3329, apic_base: 4276095232, interrupt_bitmap: [0, 0, 0, 0] }
Segment registers:
------------------
register selector base limit type p dpl db s l g avl
cs kvm_segment { base: 0, limit: 0, selector: 8, type_: 11, present: 1, dpl: 0, db: 0, s: 1, l: 1, g: 0, avl: 0, unusable: 0, padding: 0 }
ss kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
ds kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
es kvm_segment { base: 0, limit: 0, selector: 16, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
fs kvm_segment { base: 0, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
gs kvm_segment { base: 4486952, limit: 65535, selector: 0, type_: 3, present: 1, dpl: 0, db: 0, s: 1, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
tr kvm_segment { base: 6291456, limit: 103, selector: 24, type_: 11, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
ldt kvm_segment { base: 0, limit: 65535, selector: 0, type_: 2, present: 1, dpl: 0, db: 0, s: 0, l: 0, g: 0, avl: 0, unusable: 0, padding: 0 }
gdt kvm_dtable { base: 58720256, limit: 65535, padding: [0, 0, 0] }
idt kvm_dtable { base: 4482844, limit: 4095, padding: [0, 0, 0] }
APIC:
-----
efer: 0000000000000d01 apic base: 00000000fee00900
Ok, seems that a userspace panic produces a correct return value, but a panic in the kernel code does not.
I'd like to link to the Travis CI build for commit 4a2381ccc192b3d699fd4b54fb007e297bac9e2d. In release mode it seems a race condition occured that caused a Panic due to a BorrowError: [0][!!!PANIC!!!] /home/travis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/cell.rs:798: already mutably borrowed: BorrowError
Given the output I assume that the BorrowError occured in the kernel or demo and not in uhyve.
The thing that makes this related to this isssue is that uhyve doesn't exit after the panic.
I've saved the log output here so it doesn't get lost if someone reruns the build. log.txt
I'm updating this Issue, since apparently it is still relevant.
https://git.rwth-aachen.de/acs/public/hermitcore/libhermit-rs/-/jobs/1378271 shows a CI run where the kernel crashed, but uhyve exited with 0
and the test was marked as passed.