Skip to content

Commit

Permalink
Embed a backtrace into Error in debug build
Browse files Browse the repository at this point in the history
It helps where an error is constructed:

[   0.585] [7:curl] syscall: close(ffffffffffffffff, 0, 0, 0, 0, 0)
[   0.585] WARN: close: error: EBADF: This error originates from:
    #1: ffff800000184219  kerla::printk::capture_backtrace()+0x79
    #2: ffff8000001dbb13  kerla::result::Error::new()+0x23
    #3: ffff8000001dc0e7  <kerla::result::Error as c...la::result::Errno>>::from()+0x17
    #4: ffff800000211177  <T as core::convert::Into<U>>::into()+0x17
    #5: ffff8000001fcb55  kerla::fs::opened_file::OpenedFileTable::close()+0xa5
    #6: ffff80000010b124  kerla::syscalls::close::<i...yscallHandler>::sys_close()+0xa4
    #7: ffff80000011bf62  kerla::syscalls::SyscallHandler::do_dispatch()+0x4e62
    #8: ffff8000001168fc  kerla::syscalls::SyscallHandler::dispatch()+0x1ac
  • Loading branch information
nuta committed Nov 4, 2021
1 parent 1af7b98 commit 72554b4
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 11 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 kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ hashbrown = { version = "0.11.2", features = ["nightly"] }
log = "0.4"
crossbeam = { version = "0.8.1", default-features = false, features = ["alloc"] }
smoltcp = { version = "0.7.5", default-features = false, features = ["alloc", "proto-ipv4", "socket", "socket-raw", "socket-udp", "socket-tcp", "proto-dhcpv4", "ethernet"] }
cfg-if = "1"
25 changes: 20 additions & 5 deletions kernel/arch/x64/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ pub struct UserVAddr(u64);
impl UserVAddr {
pub const fn new(addr: usize) -> Result<Option<UserVAddr>> {
if (addr as u64) >= KERNEL_BASE_ADDR {
return Err(Error::with_message(Errno::EFAULT, "invalid user pointer"));
return Err(Error::with_message_const(
Errno::EFAULT,
"invalid user pointer",
));
}

if addr == 0 {
Expand All @@ -165,11 +168,17 @@ impl UserVAddr {

pub const fn new_nonnull(addr: usize) -> Result<UserVAddr> {
if (addr as u64) >= KERNEL_BASE_ADDR {
return Err(Error::with_message(Errno::EFAULT, "invalid user pointer"));
return Err(Error::with_message_const(
Errno::EFAULT,
"invalid user pointer",
));
}

if addr == 0 {
return Err(Error::with_message(Errno::EFAULT, "null user pointer"));
return Err(Error::with_message_const(
Errno::EFAULT,
"null user pointer",
));
}

Ok(UserVAddr(addr as u64))
Expand Down Expand Up @@ -204,8 +213,14 @@ impl UserVAddr {
pub fn access_ok(self, len: usize) -> Result<()> {
match self.value().checked_add(len) {
Some(end) if end <= KERNEL_BASE_ADDR as usize => Ok(()),
Some(_end) => Err(Error::with_message(Errno::EFAULT, "invalid user pointer")),
None => Err(Error::with_message(Errno::EFAULT, "overflow in access_ok")),
Some(_end) => Err(Error::with_message_const(
Errno::EFAULT,
"invalid user pointer",
)),
None => Err(Error::with_message_const(
Errno::EFAULT,
"overflow in access_ok",
)),
}
}

Expand Down
4 changes: 2 additions & 2 deletions kernel/arch/x64/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ impl Backtrace {
}
}

pub fn traverse<F>(self, callback: F)
pub fn traverse<F>(self, mut callback: F)
where
F: Fn(usize, VAddr),
F: FnMut(usize, VAddr),
{
let mut frame = self.frame;
for i in 0..BACKTRACE_MAX {
Expand Down
46 changes: 45 additions & 1 deletion kernel/printk.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use alloc::boxed::Box;
use arrayvec::ArrayVec;
use kerla_utils::ring_buffer::RingBuffer;

use crate::arch::SpinLock;
use crate::arch::{print_str, printchar, Backtrace, VAddr};
use crate::lang_items::PANICKED;
use core::mem::size_of;
use core::slice;
use core::str;
use core::sync::atomic::Ordering;
use core::{fmt, slice};
pub struct Printer;

pub const KERNEL_LOG_BUF_SIZE: usize = 8192;
Expand Down Expand Up @@ -238,3 +240,45 @@ pub fn backtrace() {
}
});
}

pub struct CapturedBacktraceFrame {
pub vaddr: VAddr,
pub offset: usize,
pub symbol_name: &'static str,
}

pub struct CapturedBacktrace {
pub trace: Box<ArrayVec<CapturedBacktraceFrame, 8>>,
}

/// Returns a saved backtrace.
pub fn capture_backtrace() -> CapturedBacktrace {
let mut trace = Box::new(ArrayVec::new());
Backtrace::current_frame().traverse(|_, vaddr| {
if let Some(symbol) = resolve_symbol(vaddr) {
let _ = trace.try_push(CapturedBacktraceFrame {
vaddr,
symbol_name: symbol.name,
offset: vaddr.value() - symbol.addr.value(),
});
}
});
CapturedBacktrace { trace }
}

impl fmt::Debug for CapturedBacktrace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, frame) in self.trace.iter().enumerate() {
let _ = write!(
f,
" #{}: {} {}()+0x{:x}\n",
i + 1,
frame.vaddr,
frame.symbol_name,
frame.offset
);
}

Ok(())
}
}
53 changes: 50 additions & 3 deletions kernel/result.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use core::fmt;

use cfg_if::cfg_if;

use crate::printk::{capture_backtrace, CapturedBacktrace};

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(i32)]
#[allow(unused)]
Expand Down Expand Up @@ -63,20 +67,35 @@ enum ErrorMessage {
pub struct Error {
errno: Errno,
message: Option<ErrorMessage>,
#[cfg(debug_assertions)]
backtrace: Option<CapturedBacktrace>,
}

impl Error {
pub fn new(errno: Errno) -> Error {
Error {
errno,
message: None,
#[cfg(debug_assertions)]
backtrace: Some(capture_backtrace()),
}
}

pub fn with_message(errno: Errno, message: &'static str) -> Error {
Error {
errno,
message: Some(ErrorMessage::StaticStr(message)),
#[cfg(debug_assertions)]
backtrace: Some(capture_backtrace()),
}
}

pub const fn with_message(errno: Errno, message: &'static str) -> Error {
pub const fn with_message_const(errno: Errno, message: &'static str) -> Error {
Error {
errno,
message: Some(ErrorMessage::StaticStr(message)),
#[cfg(debug_assertions)]
backtrace: None,
}
}

Expand All @@ -90,11 +109,39 @@ impl fmt::Debug for Error {
if let Some(message) = self.message.as_ref() {
match message {
ErrorMessage::StaticStr(message) => {
write!(f, "[{:?}] {}", self.errno, message)
cfg_if! {
if #[cfg(debug_assertions)] {
if let Some(ref trace) = self.backtrace {
write!(
f,
"[{:?}] {}\n This error originates from:\n{:?}",
self.errno, message, trace
)
} else {
write!(f, "[{:?}] {}", self.errno, message)
}
} else {
write!(f, "[{:?}] {}", self.errno, message)
}
}
}
}
} else {
write!(f, "{:?}", self.errno)
cfg_if! {
if #[cfg(debug_assertions)] {
if let Some(ref trace) = self.backtrace {
write!(
f,
"{:?}: This error originates from:\n{:?}",
self.errno, trace
)
} else {
write!(f, "{:?}", self.errno)
}
} else {
write!(f, "{:?}", self.errno)
}
}
}
}
}
Expand Down

0 comments on commit 72554b4

Please sign in to comment.