Skip to content

Commit 72554b4

Browse files
committed
Embed a backtrace into Error in debug build
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
1 parent 1af7b98 commit 72554b4

File tree

6 files changed

+119
-11
lines changed

6 files changed

+119
-11
lines changed

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.

kernel/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ hashbrown = { version = "0.11.2", features = ["nightly"] }
2121
log = "0.4"
2222
crossbeam = { version = "0.8.1", default-features = false, features = ["alloc"] }
2323
smoltcp = { version = "0.7.5", default-features = false, features = ["alloc", "proto-ipv4", "socket", "socket-raw", "socket-udp", "socket-tcp", "proto-dhcpv4", "ethernet"] }
24+
cfg-if = "1"

kernel/arch/x64/address.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ pub struct UserVAddr(u64);
153153
impl UserVAddr {
154154
pub const fn new(addr: usize) -> Result<Option<UserVAddr>> {
155155
if (addr as u64) >= KERNEL_BASE_ADDR {
156-
return Err(Error::with_message(Errno::EFAULT, "invalid user pointer"));
156+
return Err(Error::with_message_const(
157+
Errno::EFAULT,
158+
"invalid user pointer",
159+
));
157160
}
158161

159162
if addr == 0 {
@@ -165,11 +168,17 @@ impl UserVAddr {
165168

166169
pub const fn new_nonnull(addr: usize) -> Result<UserVAddr> {
167170
if (addr as u64) >= KERNEL_BASE_ADDR {
168-
return Err(Error::with_message(Errno::EFAULT, "invalid user pointer"));
171+
return Err(Error::with_message_const(
172+
Errno::EFAULT,
173+
"invalid user pointer",
174+
));
169175
}
170176

171177
if addr == 0 {
172-
return Err(Error::with_message(Errno::EFAULT, "null user pointer"));
178+
return Err(Error::with_message_const(
179+
Errno::EFAULT,
180+
"null user pointer",
181+
));
173182
}
174183

175184
Ok(UserVAddr(addr as u64))
@@ -204,8 +213,14 @@ impl UserVAddr {
204213
pub fn access_ok(self, len: usize) -> Result<()> {
205214
match self.value().checked_add(len) {
206215
Some(end) if end <= KERNEL_BASE_ADDR as usize => Ok(()),
207-
Some(_end) => Err(Error::with_message(Errno::EFAULT, "invalid user pointer")),
208-
None => Err(Error::with_message(Errno::EFAULT, "overflow in access_ok")),
216+
Some(_end) => Err(Error::with_message_const(
217+
Errno::EFAULT,
218+
"invalid user pointer",
219+
)),
220+
None => Err(Error::with_message_const(
221+
Errno::EFAULT,
222+
"overflow in access_ok",
223+
)),
209224
}
210225
}
211226

kernel/arch/x64/backtrace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ impl Backtrace {
1919
}
2020
}
2121

22-
pub fn traverse<F>(self, callback: F)
22+
pub fn traverse<F>(self, mut callback: F)
2323
where
24-
F: Fn(usize, VAddr),
24+
F: FnMut(usize, VAddr),
2525
{
2626
let mut frame = self.frame;
2727
for i in 0..BACKTRACE_MAX {

kernel/printk.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
use alloc::boxed::Box;
2+
use arrayvec::ArrayVec;
13
use kerla_utils::ring_buffer::RingBuffer;
24

35
use crate::arch::SpinLock;
46
use crate::arch::{print_str, printchar, Backtrace, VAddr};
57
use crate::lang_items::PANICKED;
68
use core::mem::size_of;
7-
use core::slice;
89
use core::str;
910
use core::sync::atomic::Ordering;
11+
use core::{fmt, slice};
1012
pub struct Printer;
1113

1214
pub const KERNEL_LOG_BUF_SIZE: usize = 8192;
@@ -238,3 +240,45 @@ pub fn backtrace() {
238240
}
239241
});
240242
}
243+
244+
pub struct CapturedBacktraceFrame {
245+
pub vaddr: VAddr,
246+
pub offset: usize,
247+
pub symbol_name: &'static str,
248+
}
249+
250+
pub struct CapturedBacktrace {
251+
pub trace: Box<ArrayVec<CapturedBacktraceFrame, 8>>,
252+
}
253+
254+
/// Returns a saved backtrace.
255+
pub fn capture_backtrace() -> CapturedBacktrace {
256+
let mut trace = Box::new(ArrayVec::new());
257+
Backtrace::current_frame().traverse(|_, vaddr| {
258+
if let Some(symbol) = resolve_symbol(vaddr) {
259+
let _ = trace.try_push(CapturedBacktraceFrame {
260+
vaddr,
261+
symbol_name: symbol.name,
262+
offset: vaddr.value() - symbol.addr.value(),
263+
});
264+
}
265+
});
266+
CapturedBacktrace { trace }
267+
}
268+
269+
impl fmt::Debug for CapturedBacktrace {
270+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271+
for (i, frame) in self.trace.iter().enumerate() {
272+
let _ = write!(
273+
f,
274+
" #{}: {} {}()+0x{:x}\n",
275+
i + 1,
276+
frame.vaddr,
277+
frame.symbol_name,
278+
frame.offset
279+
);
280+
}
281+
282+
Ok(())
283+
}
284+
}

kernel/result.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use core::fmt;
22

3+
use cfg_if::cfg_if;
4+
5+
use crate::printk::{capture_backtrace, CapturedBacktrace};
6+
37
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
48
#[repr(i32)]
59
#[allow(unused)]
@@ -63,20 +67,35 @@ enum ErrorMessage {
6367
pub struct Error {
6468
errno: Errno,
6569
message: Option<ErrorMessage>,
70+
#[cfg(debug_assertions)]
71+
backtrace: Option<CapturedBacktrace>,
6672
}
6773

6874
impl Error {
6975
pub fn new(errno: Errno) -> Error {
7076
Error {
7177
errno,
7278
message: None,
79+
#[cfg(debug_assertions)]
80+
backtrace: Some(capture_backtrace()),
81+
}
82+
}
83+
84+
pub fn with_message(errno: Errno, message: &'static str) -> Error {
85+
Error {
86+
errno,
87+
message: Some(ErrorMessage::StaticStr(message)),
88+
#[cfg(debug_assertions)]
89+
backtrace: Some(capture_backtrace()),
7390
}
7491
}
7592

76-
pub const fn with_message(errno: Errno, message: &'static str) -> Error {
93+
pub const fn with_message_const(errno: Errno, message: &'static str) -> Error {
7794
Error {
7895
errno,
7996
message: Some(ErrorMessage::StaticStr(message)),
97+
#[cfg(debug_assertions)]
98+
backtrace: None,
8099
}
81100
}
82101

@@ -90,11 +109,39 @@ impl fmt::Debug for Error {
90109
if let Some(message) = self.message.as_ref() {
91110
match message {
92111
ErrorMessage::StaticStr(message) => {
93-
write!(f, "[{:?}] {}", self.errno, message)
112+
cfg_if! {
113+
if #[cfg(debug_assertions)] {
114+
if let Some(ref trace) = self.backtrace {
115+
write!(
116+
f,
117+
"[{:?}] {}\n This error originates from:\n{:?}",
118+
self.errno, message, trace
119+
)
120+
} else {
121+
write!(f, "[{:?}] {}", self.errno, message)
122+
}
123+
} else {
124+
write!(f, "[{:?}] {}", self.errno, message)
125+
}
126+
}
94127
}
95128
}
96129
} else {
97-
write!(f, "{:?}", self.errno)
130+
cfg_if! {
131+
if #[cfg(debug_assertions)] {
132+
if let Some(ref trace) = self.backtrace {
133+
write!(
134+
f,
135+
"{:?}: This error originates from:\n{:?}",
136+
self.errno, trace
137+
)
138+
} else {
139+
write!(f, "{:?}", self.errno)
140+
}
141+
} else {
142+
write!(f, "{:?}", self.errno)
143+
}
144+
}
98145
}
99146
}
100147
}

0 commit comments

Comments
 (0)