Skip to content

Commit 14845b8

Browse files
committed
Unifies and extends breakpoint and debug trap handling
Signed-off-by: Godones <chenlinfeng25@outlook.com>
1 parent ba55fb9 commit 14845b8

8 files changed

Lines changed: 97 additions & 13 deletions

File tree

src/aarch64/trap.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ fn esr_value() -> u64 {
7070
}
7171
}
7272

73+
fn handle_breakpoint(tf: &mut TrapFrame) {
74+
if handle_trap!(BREAK_HANDLER, tf) {
75+
return;
76+
}
77+
tf.elr += 4;
78+
}
79+
7380
fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
7481
let vaddr = va!(fault_addr());
7582
if handle_trap!(PAGE_FAULT, vaddr, access_flags) {
@@ -162,12 +169,12 @@ fn aarch64_trap_handler(tf: &mut TrapFrame, kind: TrapKind, source: TrapSource)
162169
#[cfg(not(feature = "arm-el2"))]
163170
Some(ESR_EL1::EC::Value::Brk64) => {
164171
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
165-
tf.elr += 4;
172+
handle_breakpoint(tf);
166173
}
167174
#[cfg(feature = "arm-el2")]
168175
Some(ESR_EL2::EC::Value::Brk64) => {
169176
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
170-
tf.elr += 4;
177+
handle_breakpoint(tf);
171178
}
172179
e => {
173180
let vaddr = va!(fault_addr());

src/aarch64/uspace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl ExceptionInfo {
149149
/// Returns a generalized kind of this exception.
150150
pub fn kind(&self) -> ExceptionKind {
151151
match self.esr.read_as_enum(ESR_EL1::EC) {
152-
Some(ESR_EL1::EC::Value::BreakpointLowerEL) => ExceptionKind::Breakpoint,
152+
Some(ESR_EL1::EC::Value::Brk64 | ESR_EL1::EC::Value::Bkpt32) => ExceptionKind::Breakpoint,
153153
Some(ESR_EL1::EC::Value::IllegalExecutionState) => ExceptionKind::IllegalInstruction,
154154
Some(ESR_EL1::EC::Value::PCAlignmentFault)
155155
| Some(ESR_EL1::EC::Value::SPAlignmentFault) => ExceptionKind::Misaligned,

src/loongarch64/trap.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ core::arch::global_asm!(
1212
trapframe_size = const (core::mem::size_of::<TrapFrame>()),
1313
);
1414

15-
fn handle_breakpoint(era: &mut usize) {
16-
debug!("Exception(Breakpoint) @ {era:#x} ");
17-
*era += 4;
15+
fn handle_breakpoint(tf: &mut TrapFrame) {
16+
debug!("Exception(Breakpoint) @ {:#x} ", tf.era);
17+
if handle_trap!(BREAK_HANDLER, tf) {
18+
return;
19+
}
20+
tf.era += 4;
1821
}
1922

2023
fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
@@ -53,7 +56,7 @@ fn loongarch64_trap_handler(tf: &mut TrapFrame) {
5356
| Trap::Exception(Exception::PageNonExecutableFault) => {
5457
handle_page_fault(tf, PageFaultFlags::EXECUTE);
5558
}
56-
Trap::Exception(Exception::Breakpoint) => handle_breakpoint(&mut tf.era),
59+
Trap::Exception(Exception::Breakpoint) => handle_breakpoint(tf),
5760
Trap::Exception(Exception::AddressNotAligned) => unsafe {
5861
tf.emulate_unaligned().unwrap();
5962
},

src/riscv/trap.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ core::arch::global_asm!(
1717
trapframe_size = const core::mem::size_of::<TrapFrame>(),
1818
);
1919

20-
fn handle_breakpoint(sepc: &mut usize) {
21-
debug!("Exception(Breakpoint) @ {sepc:#x} ");
22-
*sepc += 2
20+
fn handle_breakpoint(tf: &mut TrapFrame) {
21+
debug!("Exception(Breakpoint) @ {:#x} ", tf.sepc);
22+
if handle_trap!(BREAK_HANDLER, tf) {
23+
return;
24+
}
25+
tf.sepc += 2;
2326
}
2427

2528
fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
@@ -51,7 +54,7 @@ fn riscv_trap_handler(tf: &mut TrapFrame) {
5154
Trap::Exception(E::InstructionPageFault) => {
5255
handle_page_fault(tf, PageFaultFlags::EXECUTE)
5356
}
54-
Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc),
57+
Trap::Exception(E::Breakpoint) => handle_breakpoint(tf),
5558
Trap::Interrupt(_) => {
5659
handle_trap!(IRQ, scause.bits());
5760
}

src/trap.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,49 @@ pub static IRQ: [fn(usize) -> bool];
1616
#[def_trap_handler]
1717
pub static PAGE_FAULT: [fn(VirtAddr, PageFaultFlags) -> bool];
1818

19+
/// A slice of breakpoint handler functions.
20+
///
21+
/// Each handler is invoked with a mutable reference to the trapped [`TrapFrame`]
22+
/// and must return a boolean indicating whether it has fully handled the trap:
23+
///
24+
/// - `true` means the breakpoint has been handled and control should resume
25+
/// according to the state encoded in the trap frame.
26+
/// - `false` means the breakpoint was not handled and default processing
27+
/// (such as falling back to another mechanism or terminating) should occur.
28+
///
29+
/// When returning `true`, the handler is responsible for updating the saved
30+
/// program counter (or equivalent PC field) in the trap frame as required by
31+
/// the target architecture. In particular, the handler must ensure that,
32+
/// upon resuming from the trap, execution does not immediately re-trigger the
33+
/// same breakpoint instruction or condition, which could otherwise lead to an
34+
/// infinite trap loop. The exact way to advance or modify the PC is
35+
/// architecture-specific and depends on how [`TrapFrame`] encodes the saved
36+
/// context.
37+
#[def_trap_handler]
38+
pub static BREAK_HANDLER: [fn(&mut TrapFrame) -> bool];
39+
40+
/// A slice of debug handler functions.
41+
///
42+
/// On `x86_64`, these handlers are invoked for debug-related traps (for
43+
/// example, hardware breakpoints, single-step traps, or other debug
44+
/// exceptions). The handler receives a mutable reference to the trapped
45+
/// [`TrapFrame`] and returns a boolean with the following meaning:
46+
///
47+
/// - `true` means the debug trap has been fully handled and execution should
48+
/// resume from the state stored in the trap frame.
49+
/// - `false` means the debug trap was not handled and default/secondary
50+
/// processing should take place.
51+
///
52+
/// As with [`BREAK_HANDLER`], when returning `true`, the handler must adjust
53+
/// the saved program counter (or equivalent) in the trap frame if required by
54+
/// the architecture so that resuming execution does not immediately cause the
55+
/// same debug condition to fire again. Callers must take the architecture-
56+
/// specific PC semantics into account when deciding how to advance or modify
57+
/// the PC.
58+
#[cfg(target_arch = "x86_64")]
59+
#[def_trap_handler]
60+
pub static DEBUG_HANDLER: [fn(&mut TrapFrame) -> bool];
61+
1962
#[allow(unused_macros)]
2063
macro_rules! handle_trap {
2164
($trap:ident, $($args:tt)*) => {{

src/uspace_common.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ pub enum ReturnReason {
2121
/// A generalized kind for [`ExceptionInfo`].
2222
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2323
pub enum ExceptionKind {
24+
#[cfg(target_arch = "x86_64")]
25+
/// A debug exception.
26+
Debug,
2427
/// A breakpoint exception.
2528
Breakpoint,
2629
/// An illegal instruction exception.

src/x86_64/trap.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use core::panic;
2+
13
use x86::{controlregs::cr2, irq::*};
24
use x86_64::structures::idt::PageFaultErrorCode;
35

4-
use super::{TrapFrame, gdt};
6+
use super::{gdt, TrapFrame};
57
use crate::trap::PageFaultFlags;
68

79
core::arch::global_asm!(
@@ -38,11 +40,33 @@ fn handle_page_fault(tf: &mut TrapFrame) {
3840
);
3941
}
4042

43+
fn handle_breakpoint(tf: &mut TrapFrame) {
44+
debug!("#BP @ {:#x} ", tf.rip);
45+
if handle_trap!(BREAK_HANDLER, tf) {
46+
return;
47+
}
48+
}
49+
50+
fn handle_debug(tf: &mut TrapFrame) {
51+
debug!("#DB @ {:#x} ", tf.rip);
52+
if handle_trap!(DEBUG_HANDLER, tf) {
53+
return;
54+
}
55+
panic!(
56+
"Unhandled #DB @ {:#x}, error_code={:#x}:\n{:#x?}\n{}",
57+
tf.rip,
58+
tf.error_code,
59+
tf,
60+
tf.backtrace()
61+
);
62+
}
63+
4164
#[unsafe(no_mangle)]
4265
fn x86_trap_handler(tf: &mut TrapFrame) {
4366
match tf.vector as u8 {
4467
PAGE_FAULT_VECTOR => handle_page_fault(tf),
45-
BREAKPOINT_VECTOR => debug!("#BP @ {:#x} ", tf.rip),
68+
BREAKPOINT_VECTOR => handle_breakpoint(tf),
69+
DEBUG_VECTOR => handle_debug(tf),
4670
GENERAL_PROTECTION_FAULT_VECTOR => {
4771
panic!(
4872
"#GP @ {:#x}, error_code={:#x}:\n{:#x?}\n{}",

src/x86_64/uspace.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ impl ExceptionInfo {
140140
/// Returns a generalized kind of this exception.
141141
pub fn kind(&self) -> ExceptionKind {
142142
match ExceptionVector::try_from(self.vector) {
143+
Ok(ExceptionVector::Debug) => ExceptionKind::Debug,
143144
Ok(ExceptionVector::Breakpoint) => ExceptionKind::Breakpoint,
144145
Ok(ExceptionVector::InvalidOpcode) => ExceptionKind::IllegalInstruction,
145146
_ => ExceptionKind::Other,

0 commit comments

Comments
 (0)