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

Commit

Permalink
add rudimentary backtrace support, still needs to be cleaned up
Browse files Browse the repository at this point in the history
  • Loading branch information
acfoltzer committed Oct 11, 2019
1 parent 5c8bb55 commit ed2f7c2
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lucet-runtime/lucet-runtime-internals/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ edition = "2018"
[dependencies]
lucet-module = { path = "../../lucet-module", version = "0.1.1" }

backtrace = "0.3"
bitflags = "1.0"
bincode = "1.1.4"
byteorder = "1.3"
Expand Down
8 changes: 8 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::module::{self, FunctionHandle, FunctionPointer, Global, GlobalValue,
use crate::region::RegionInternal;
use crate::val::{UntypedRetVal, Val};
use crate::WASM_PAGE_SIZE;
use backtrace::Backtrace;
use libc::{c_void, siginfo_t, uintptr_t};
use lucet_module::InstanceRuntimeData;
use memoffset::offset_of;
Expand Down Expand Up @@ -914,6 +915,7 @@ impl Instance {
mut details,
siginfo,
context,
full_backtrace,
} => {
// Sandbox is no longer runnable. It's unsafe to determine all error details in the signal
// handler, so we fill in extra details here.
Expand All @@ -924,11 +926,15 @@ impl Instance {
.module
.addr_details(details.rip_addr as *const c_void)?;

details.backtrace = Some(self.module.resolve_and_trim(&full_backtrace));
// dbg!(&details.backtrace);

// fill the state back in with the updated details in case fatal handlers need it
self.state = State::Faulted {
details: details.clone(),
siginfo,
context,
full_backtrace,
};

if details.fatal {
Expand Down Expand Up @@ -1109,6 +1115,8 @@ pub struct FaultDetails {
pub rip_addr: uintptr_t,
/// Extra information about the instruction pointer's location, if available.
pub rip_addr_details: Option<module::AddrDetails>,
/// Backtrace of the frames from the guest stack, if available.
pub backtrace: Option<Backtrace>,
}

impl std::fmt::Display for FaultDetails {
Expand Down
3 changes: 3 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/instance/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::instance::{
HOST_CTX,
};
use crate::sysdeps::UContextPtr;
use backtrace::Backtrace;
use lazy_static::lazy_static;
use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV};
use lucet_module::TrapCode;
Expand Down Expand Up @@ -214,9 +215,11 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext
// Details set to `None` here: have to wait until `verify_trap_safety` to
// fill in these details, because access may not be signal safe.
rip_addr_details: None,
backtrace: None,
},
siginfo,
context: ctx.into(),
full_backtrace: Backtrace::new_unresolved(),
};
true
}
Expand Down
2 changes: 2 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/instance/state.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::instance::siginfo_ext::SiginfoExt;
use crate::instance::{FaultDetails, TerminationDetails, YieldedVal};
use crate::sysdeps::UContext;
use backtrace::Backtrace;
use libc::{SIGBUS, SIGSEGV};
use std::any::Any;
use std::ffi::{CStr, CString};
Expand All @@ -26,6 +27,7 @@ pub enum State {
details: FaultDetails,
siginfo: libc::siginfo_t,
context: UContext,
full_backtrace: Backtrace,
},

/// The instance is in the process of terminating.
Expand Down
3 changes: 3 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub use lucet_module::{

use crate::alloc::Limits;
use crate::error::Error;
use backtrace::Backtrace;
use libc::c_void;

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

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

fn resolve_and_trim(&self, full_bt: &Backtrace) -> Backtrace;

fn get_signature(&self, fn_id: FunctionIndex) -> &Signature;

fn function_handle_from_ptr(&self, ptr: FunctionPointer) -> FunctionHandle {
Expand Down
45 changes: 45 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/module/dl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::error::Error;
use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement};
use backtrace::{Backtrace, BacktraceFrame};
use libc::c_void;
use libloading::Library;
use lucet_module::{
Expand Down Expand Up @@ -242,6 +243,50 @@ impl ModuleInternal for DlModule {
fn get_signature(&self, fn_id: FunctionIndex) -> &Signature {
self.module.module_data.get_signature(fn_id)
}

fn resolve_and_trim(&self, full_bt: &Backtrace) -> Backtrace {
let mut bt = full_bt.clone();
bt.resolve();
let trimmed_frames = bt
.frames()
.iter()
.filter(|fr| match self.addr_details(fr.ip()) {
// if we can look up addr details, and it's in module code, keep the frame
Ok(Some(details)) => details.in_module_code,
_ => false,
})
// // skip everything until the entry to the signal handler
// .skip_while(|fr| {
// fr.symbols()
// .iter()
// .find(|sym| {
// sym.name().map_or(false, |sn| {
// let name = format!("{}", sn);
// name.starts_with(
// "lucet_runtime_internals::instance::signals::handle_signal",
// ) && !name.contains("closure")
// })
// })
// .is_none()
// })
// // drop the handle_signal frame
// .skip(1)
// // take all frames between handle_signal and Context::swap
// .take_while(|fr| {
// fr.symbols()
// .iter()
// .find(|sym| {
// sym.name().map_or(false, |sn| {
// format!("{}", sn)
// .starts_with("lucet_runtime_internals::context::Context::swap")
// })
// })
// .is_none()
// })
.cloned()
.collect::<Vec<BacktraceFrame>>();
trimmed_frames.into()
}
}

// TODO: PR to nix or libloading?
Expand Down
9 changes: 9 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/module/mock.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::error::Error;
use crate::module::{AddrDetails, GlobalSpec, HeapSpec, Module, ModuleInternal, TableElement};
use backtrace::Backtrace;
use libc::c_void;
use lucet_module::owned::{
OwnedExportFunction, OwnedFunctionMetadata, OwnedGlobalSpec, OwnedImportFunction,
Expand Down Expand Up @@ -318,6 +319,14 @@ impl ModuleInternal for MockModule {
Ok(None)
}

fn resolve_and_trim(&self, full_bt: &Backtrace) -> Backtrace {
// for a mock module, just resolve since we can't differentiate between hostcall code and
// mock module functions
let mut bt = full_bt.clone();
bt.resolve();
bt
}

fn get_signature(&self, fn_id: FunctionIndex) -> &Signature {
self.module_data.get_signature(fn_id)
}
Expand Down
1 change: 0 additions & 1 deletion lucet-runtime/src/c_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use lucet_runtime_internals::c_api::*;
use lucet_runtime_internals::instance::{
instance_handle_from_raw, instance_handle_to_raw, InstanceInternal,
};
use lucet_runtime_internals::vmctx::VmctxInternal;
use lucet_runtime_internals::WASM_PAGE_SIZE;
use lucet_runtime_internals::{
assert_nonnull, lucet_hostcall_terminate, lucet_hostcalls, with_ffi_arcs,
Expand Down
12 changes: 6 additions & 6 deletions lucetc/src/decls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ impl<'a> ModuleDecls<'a> {
(None, None) => {
// No import or export for this function. It's local, and we have to make up a
// name.
decls.declare_function(
clif_module,
format!("guest_func_{}", ix),
Linkage::Local,
func_index,
)?;
let name = if let Some(Some(name)) = decls.info.function_names.get(func_index) {
format!("guest_func_{}", name)
} else {
format!("guest_func_{}", ix)
};
decls.declare_function(clif_module, name, Linkage::Local, func_index)?;
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion lucetc/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Implements ModuleEnvironment for cranelift-wasm. Code derived from cranelift-wasm/environ/dummy.rs
use crate::error::{LucetcError, LucetcErrorKind};
use crate::pointer::NATIVE_POINTER;
use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap};
use cranelift_codegen::entity::{entity_impl, EntityRef, PrimaryMap, SecondaryMap};
use cranelift_codegen::ir;
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_wasm::{
Expand Down Expand Up @@ -72,6 +72,7 @@ pub struct ModuleInfo<'a> {
pub function_mapping: PrimaryMap<FuncIndex, UniqueFuncIndex>,
/// Function signatures: imported and local
pub functions: PrimaryMap<UniqueFuncIndex, Exportable<'a, SignatureIndex>>,
pub function_names: SecondaryMap<UniqueFuncIndex, Option<&'a str>>,
/// Provided by `declare_table`
pub tables: PrimaryMap<TableIndex, Exportable<'a, Table>>,
/// Provided by `declare_memory`
Expand Down Expand Up @@ -103,6 +104,7 @@ impl<'a> ModuleInfo<'a> {
imported_memories: PrimaryMap::new(),
function_mapping: PrimaryMap::new(),
functions: PrimaryMap::new(),
function_names: SecondaryMap::new(),
tables: PrimaryMap::new(),
memories: PrimaryMap::new(),
globals: PrimaryMap::new(),
Expand Down Expand Up @@ -396,4 +398,13 @@ impl<'a> ModuleEnvironment<'a> for ModuleInfo<'a> {
}
Ok(())
}

fn declare_func_name(&mut self, func_index: FuncIndex, name: &'a str) -> WasmResult<()> {
let unique_func_index = *self
.function_mapping
.get(func_index)
.expect("function indices are valid");
self.function_names[unique_func_index] = Some(name);
Ok(())
}
}

0 comments on commit ed2f7c2

Please sign in to comment.