Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Commit d09c213

Browse files
acfoltzeriximeow
authored andcommitted
add rudimentary backtrace support, still needs to be cleaned up
1 parent 23c9721 commit d09c213

10 files changed

Lines changed: 82 additions & 8 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lucet-runtime/lucet-runtime-internals/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ edition = "2018"
1313
lucet-module = { path = "../../lucet-module", version = "0.5.0" }
1414
lucet-runtime-macros = { path = "../lucet-runtime-macros", version = "0.5.0" }
1515

16+
backtrace = "0.3"
1617
bitflags = "1.0"
1718
bincode = "1.1.4"
1819
byteorder = "1.3"

lucet-runtime/lucet-runtime-internals/src/c_api.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ pub mod lucet_result {
295295
.map(|CTerminationDetails { details }| *details)
296296
.unwrap_or(ptr::null_mut()),
297297
},
298+
TerminationDetails::ForcedUnwind => lucet_terminated {
299+
reason: lucet_terminated_reason::ForcedUnwind,
300+
provided: std::ptr::null_mut(),
301+
},
298302
TerminationDetails::Remote => lucet_terminated {
299303
reason: lucet_terminated_reason::Remote,
300304
provided: std::ptr::null_mut(),
@@ -352,6 +356,7 @@ pub mod lucet_result {
352356
YieldTypeMismatch,
353357
BorrowError,
354358
Provided,
359+
ForcedUnwind,
355360
Remote,
356361
}
357362

lucet-runtime/lucet-runtime-internals/src/instance.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::module::{self, FunctionHandle, FunctionPointer, Global, GlobalValue,
1515
use crate::region::RegionInternal;
1616
use crate::val::{UntypedRetVal, Val};
1717
use crate::WASM_PAGE_SIZE;
18+
use backtrace::Backtrace;
1819
use libc::{c_void, pthread_self, siginfo_t, uintptr_t};
1920
use lucet_module::InstanceRuntimeData;
2021
use memoffset::offset_of;
@@ -984,6 +985,7 @@ impl Instance {
984985
mut details,
985986
siginfo,
986987
context,
988+
full_backtrace,
987989
} => {
988990
// Sandbox is no longer runnable. It's unsafe to determine all error details in the signal
989991
// handler, so we fill in extra details here.
@@ -994,11 +996,15 @@ impl Instance {
994996
.module
995997
.addr_details(details.rip_addr as *const c_void)?;
996998

999+
details.backtrace = Some(self.module.resolve_and_trim(&full_backtrace));
1000+
// dbg!(&details.backtrace);
1001+
9971002
// fill the state back in with the updated details in case fatal handlers need it
9981003
self.state = State::Faulted {
9991004
details: details.clone(),
10001005
siginfo,
10011006
context,
1007+
full_backtrace,
10021008
};
10031009

10041010
if details.fatal {
@@ -1180,6 +1186,8 @@ pub struct FaultDetails {
11801186
pub rip_addr: uintptr_t,
11811187
/// Extra information about the instruction pointer's location, if available.
11821188
pub rip_addr_details: Option<module::AddrDetails>,
1189+
/// Backtrace of the frames from the guest stack, if available.
1190+
pub backtrace: Option<Backtrace>,
11831191
}
11841192

11851193
impl std::fmt::Display for FaultDetails {
@@ -1240,6 +1248,8 @@ pub enum TerminationDetails {
12401248
BorrowError(&'static str),
12411249
/// Calls to `lucet_hostcall_terminate` provide a payload for use by the embedder.
12421250
Provided(Box<dyn Any + 'static>),
1251+
/// Returned when the stack is forced to unwind on instance reset or drop.
1252+
ForcedUnwind,
12431253
Remote,
12441254
}
12451255

@@ -1291,6 +1301,7 @@ impl std::fmt::Debug for TerminationDetails {
12911301
TerminationDetails::YieldTypeMismatch => write!(f, "YieldTypeMismatch"),
12921302
TerminationDetails::Provided(_) => write!(f, "Provided(Any)"),
12931303
TerminationDetails::Remote => write!(f, "Remote"),
1304+
TerminationDetails::ForcedUnwind => write!(f, "ForcedUnwind"),
12941305
}
12951306
}
12961307
}

lucet-runtime/lucet-runtime-internals/src/instance/internals.rs

Whitespace-only changes.

lucet-runtime/lucet-runtime-internals/src/instance/signals.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::instance::{
55
HOST_CTX,
66
};
77
use crate::sysdeps::UContextPtr;
8+
use backtrace::Backtrace;
89
use lazy_static::lazy_static;
910
use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV};
1011
use lucet_module::TrapCode;
@@ -90,7 +91,7 @@ impl Instance {
9091
Ok(res) => res,
9192
Err(e) => match e.downcast::<TerminationDetails>() {
9293
Ok(details) => {
93-
self.state = State::Terminated { details: *details };
94+
self.state = State::Terminating { details: *details };
9495
Ok(())
9596
}
9697
Err(e) => {
@@ -196,7 +197,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext
196197
let trapcode = inst.module.lookup_trapcode(rip);
197198

198199
let behavior = (inst.signal_handler)(inst, &trapcode, signum, siginfo_ptr, ucontext_ptr);
199-
match behavior {
200+
let switch_to_host = match behavior {
200201
SignalBehavior::Continue => {
201202
// return to the guest context without making any modifications to the instance
202203
false
@@ -245,9 +246,11 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext
245246
// Details set to `None` here: have to wait until `verify_trap_safety` to
246247
// fill in these details, because access may not be signal safe.
247248
rip_addr_details: None,
249+
backtrace: None,
248250
},
249251
siginfo,
250252
context: ctx.into(),
253+
full_backtrace: Backtrace::new_unresolved(),
251254
};
252255
};
253256

@@ -259,12 +262,6 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext
259262
if switch_to_host {
260263
// we must disable termination so no KillSwitch may fire in host code.
261264
inst.kill_state.disable_termination();
262-
263-
// use the ucontext to fill in the fields of the guest context; we can't use
264-
// `Context::swap()` here because then we'd swap back to the signal handler instead of
265-
// the point in the guest that caused the fault
266-
ctx.save_to_context(&mut inst.ctx);
267-
inst.ctx.stop_addr = Some(rip as u64);
268265
}
269266

270267
switch_to_host

lucet-runtime/lucet-runtime-internals/src/instance/state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::instance::siginfo_ext::SiginfoExt;
22
use crate::instance::{FaultDetails, TerminationDetails, YieldedVal};
33
use crate::sysdeps::UContext;
4+
use backtrace::Backtrace;
45
use libc::{SIGBUS, SIGSEGV};
56
use std::any::Any;
67
use std::ffi::{CStr, CString};
@@ -26,6 +27,7 @@ pub enum State {
2627
details: FaultDetails,
2728
siginfo: libc::siginfo_t,
2829
context: UContext,
30+
full_backtrace: Backtrace,
2931
},
3032

3133
/// The instance is in the process of terminating.

lucet-runtime/lucet-runtime-internals/src/module.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub use lucet_module::{
1111

1212
use crate::alloc::Limits;
1313
use crate::error::Error;
14+
use backtrace::Backtrace;
1415
use libc::c_void;
1516

1617
/// Details about a program address.
@@ -64,6 +65,8 @@ pub trait ModuleInternal: Send + Sync {
6465

6566
fn addr_details(&self, addr: *const c_void) -> Result<Option<AddrDetails>, Error>;
6667

68+
fn resolve_and_trim(&self, full_bt: &Backtrace) -> Backtrace;
69+
6770
fn get_signature(&self, fn_id: FunctionIndex) -> &Signature;
6871

6972
fn function_handle_from_ptr(&self, ptr: FunctionPointer) -> FunctionHandle {

lucet-runtime/lucet-runtime-internals/src/module/dl.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::error::Error;
22
use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement};
3+
use backtrace::{Backtrace, BacktraceFrame};
34
use libc::c_void;
45
use libloading::Library;
56
use lucet_module::{
@@ -303,6 +304,50 @@ impl ModuleInternal for DlModule {
303304
fn get_signature(&self, fn_id: FunctionIndex) -> &Signature {
304305
self.module.module_data.get_signature(fn_id)
305306
}
307+
308+
fn resolve_and_trim(&self, full_bt: &Backtrace) -> Backtrace {
309+
let mut bt = full_bt.clone();
310+
bt.resolve();
311+
let trimmed_frames = bt
312+
.frames()
313+
.iter()
314+
.filter(|fr| match self.addr_details(fr.ip()) {
315+
// if we can look up addr details, and it's in module code, keep the frame
316+
Ok(Some(details)) => details.in_module_code,
317+
_ => false,
318+
})
319+
// // skip everything until the entry to the signal handler
320+
// .skip_while(|fr| {
321+
// fr.symbols()
322+
// .iter()
323+
// .find(|sym| {
324+
// sym.name().map_or(false, |sn| {
325+
// let name = format!("{}", sn);
326+
// name.starts_with(
327+
// "lucet_runtime_internals::instance::signals::handle_signal",
328+
// ) && !name.contains("closure")
329+
// })
330+
// })
331+
// .is_none()
332+
// })
333+
// // drop the handle_signal frame
334+
// .skip(1)
335+
// // take all frames between handle_signal and Context::swap
336+
// .take_while(|fr| {
337+
// fr.symbols()
338+
// .iter()
339+
// .find(|sym| {
340+
// sym.name().map_or(false, |sn| {
341+
// format!("{}", sn)
342+
// .starts_with("lucet_runtime_internals::context::Context::swap")
343+
// })
344+
// })
345+
// .is_none()
346+
// })
347+
.cloned()
348+
.collect::<Vec<BacktraceFrame>>();
349+
trimmed_frames.into()
350+
}
306351
}
307352

308353
// TODO: PR to nix or libloading?

lucet-runtime/lucet-runtime-internals/src/module/mock.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::error::Error;
22
use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement};
3+
use backtrace::Backtrace;
34
use libc::c_void;
45
use lucet_module::owned::{
56
OwnedExportFunction, OwnedFunctionMetadata, OwnedGlobalSpec, OwnedImportFunction,
@@ -319,6 +320,14 @@ impl ModuleInternal for MockModule {
319320
Ok(None)
320321
}
321322

323+
fn resolve_and_trim(&self, full_bt: &Backtrace) -> Backtrace {
324+
// for a mock module, just resolve since we can't differentiate between hostcall code and
325+
// mock module functions
326+
let mut bt = full_bt.clone();
327+
bt.resolve();
328+
bt
329+
}
330+
322331
fn get_signature(&self, fn_id: FunctionIndex) -> &Signature {
323332
self.module_data.get_signature(fn_id)
324333
}

0 commit comments

Comments
 (0)