Skip to content

Commit eb927ac

Browse files
committed
feat: Add conversion of trapframe to kprobe's pt_regs.
Add custom callback for break exception. Add debug handler for x86_64. Add kprobe support to aarch64 arch and extend break handler parameter. Add debug exception for x86_64 and fix the break exception definition error in aarch64. Signed-off-by: Godones <chenlinfeng25@outlook.com>
1 parent f1359df commit eb927ac

File tree

15 files changed

+326
-25
lines changed

15 files changed

+326
-25
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fp-simd = []
2727
tls = []
2828
uspace = []
2929
arm-el2 = []
30+
kprobe = ["dep:kprobe"]
3031

3132
[dependencies]
3233
axbacktrace = "0.1"
@@ -36,6 +37,7 @@ cfg-if = "1.0"
3637
memory_addr = "0.4"
3738
page_table_entry = "0.5"
3839
static_assertions = "1.1.0"
40+
kprobe = { git = "https://github.com/Starry-OS/kprobe", optional = true }
3941

4042
[target.'cfg(target_arch = "x86_64")'.dependencies]
4143
lazyinit = "0.2"

src/aarch64/context.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ impl fmt::Debug for TrapFrame {
3131
}
3232
}
3333

34+
#[cfg(feature = "kprobe")]
35+
impl From<&TrapFrame> for kprobe::PtRegs {
36+
fn from(tf: &TrapFrame) -> Self {
37+
use core::u64;
38+
39+
use kprobe::PtRegs;
40+
PtRegs {
41+
regs: tf.x,
42+
sp: u64::MAX,
43+
pc: tf.elr,
44+
pstate: tf.spsr,
45+
orig_x0: u64::MAX,
46+
syscallno: -1,
47+
unused2: 0,
48+
}
49+
}
50+
}
51+
52+
#[cfg(feature = "kprobe")]
53+
impl TrapFrame {
54+
/// Update the TrapFrame from kprobe::PtRegs
55+
pub fn update_from_ptregs(&mut self, ptregs: kprobe::PtRegs) {
56+
self.x = ptregs.regs;
57+
self.spsr = ptregs.pstate;
58+
self.elr = ptregs.pc;
59+
}
60+
}
61+
3462
impl TrapFrame {
3563
/// Gets the 0th syscall argument.
3664
pub const fn arg0(&self) -> usize {

src/aarch64/trap.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ pub(super) fn is_valid_page_fault(iss: u64) -> bool {
4141
matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits
4242
}
4343

44+
fn handle_breakpoint(tf: &mut TrapFrame, iss: u64) {
45+
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
46+
if core::hint::likely(handle_trap!(BREAK_HANDLER, tf, iss)) {
47+
return;
48+
}
49+
tf.elr += 4;
50+
}
51+
4452
fn handle_page_fault(tf: &mut TrapFrame, access_flags: PageFaultFlags) {
4553
let vaddr = va!(FAR_EL1.get() as usize);
4654
if handle_trap!(PAGE_FAULT, vaddr, access_flags) {
@@ -99,10 +107,7 @@ fn aarch64_trap_handler(tf: &mut TrapFrame, kind: TrapKind, source: TrapSource)
99107
},
100108
);
101109
}
102-
Some(ESR_EL1::EC::Value::Brk64) => {
103-
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
104-
tf.elr += 4;
105-
}
110+
Some(ESR_EL1::EC::Value::Brk64) => handle_breakpoint(tf, iss),
106111
e => {
107112
let vaddr = va!(FAR_EL1.get() as usize);
108113
panic!(

src/aarch64/uspace.rs

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

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(likely_unlikely)]
12
#![cfg_attr(not(test), no_std)]
23
#![cfg_attr(docsrs, feature(doc_cfg))]
34
#![feature(cold_path)]

src/loongarch64/context.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,8 @@ impl TaskContext {
259259

260260
/// Switches to another task.
261261
///
262-
/// It first saves the current task's context from CPU to this place, and then
263-
/// restores the next task's context from `next_ctx` to CPU.
262+
/// It first saves the current task's context from CPU to this place, and
263+
/// then restores the next task's context from `next_ctx` to CPU.
264264
pub fn switch_to(&mut self, next_ctx: &Self) {
265265
#[cfg(feature = "tls")]
266266
{
@@ -353,3 +353,44 @@ unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task:
353353
ret",
354354
)
355355
}
356+
357+
#[cfg(feature = "kprobe")]
358+
impl From<&TrapFrame> for kprobe::PtRegs {
359+
fn from(tf: &TrapFrame) -> Self {
360+
let regs = [0; 32];
361+
unsafe {
362+
core::ptr::copy_nonoverlapping(
363+
&tf.regs as *const GeneralRegisters as *const usize,
364+
regs.as_ptr() as *mut usize,
365+
32,
366+
);
367+
}
368+
kprobe::PtRegs {
369+
regs,
370+
orig_a0: 0,
371+
csr_era: tf.era,
372+
csr_badvaddr: 0,
373+
csr_crmd: 0,
374+
csr_prmd: tf.prmd,
375+
csr_euen: 0,
376+
csr_ecfg: 0,
377+
csr_estat: 0,
378+
}
379+
}
380+
}
381+
382+
#[cfg(feature = "kprobe")]
383+
impl TrapFrame {
384+
/// Update the TrapFrame from kprobe::PtRegs
385+
pub fn update_from_ptregs(&mut self, ptregs: kprobe::PtRegs) {
386+
unsafe {
387+
core::ptr::copy_nonoverlapping(
388+
ptregs.regs.as_ptr() as *const usize,
389+
&mut self.regs as *mut GeneralRegisters as *mut usize,
390+
32,
391+
);
392+
}
393+
self.era = ptregs.csr_era;
394+
self.prmd = ptregs.csr_prmd;
395+
}
396+
}

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 core::hint::likely(handle_trap!(BREAK_HANDLER, tf, 0)) {
18+
return;
19+
}
20+
tf.era += 4;
1821
}
1922

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

src/riscv/context.rs

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::arch::naked_asm;
2+
23
use memory_addr::VirtAddr;
34
use riscv::register::sstatus::{self, FS};
45

@@ -85,7 +86,8 @@ impl FpState {
8586

8687
/// Handles floating-point state context switching
8788
///
88-
/// Saves the current task's FP state (if needed) and restores the next task's FP state
89+
/// Saves the current task's FP state (if needed) and restores the next
90+
/// task's FP state
8991
pub fn switch_to(&mut self, next_fp_state: &FpState) {
9092
// get the real FP state of the current task
9193
let current_fs = sstatus::read().fs();
@@ -98,9 +100,12 @@ impl FpState {
98100
}
99101
// restore the next task's FP state
100102
match next_fp_state.fs {
101-
FS::Clean => next_fp_state.restore(), // the next task's FP state is clean, we should restore it
102-
FS::Initial => FpState::clear(), // restore the FP state as constant values(all 0)
103-
FS::Off => {} // do nothing
103+
// the next task's FP state is clean, we should restore it
104+
FS::Clean => next_fp_state.restore(),
105+
// restore the FP state as constant values(all 0)
106+
FS::Initial => FpState::clear(),
107+
// do nothing
108+
FS::Off => {}
104109
FS::Dirty => unreachable!("FP state of the next task should not be dirty"),
105110
}
106111
unsafe { sstatus::set_fs(next_fp_state.fs) }; // set the FP state to the next task's FP state
@@ -326,8 +331,8 @@ impl TaskContext {
326331

327332
/// Switches to another task.
328333
///
329-
/// It first saves the current task's context from CPU to this place, and then
330-
/// restores the next task's context from `next_ctx` to CPU.
334+
/// It first saves the current task's context from CPU to this place, and
335+
/// then restores the next task's context from `next_ctx` to CPU.
331336
pub fn switch_to(&mut self, next_ctx: &Self) {
332337
#[cfg(feature = "tls")]
333338
{
@@ -425,3 +430,87 @@ unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task:
425430
ret",
426431
)
427432
}
433+
434+
#[cfg(feature = "kprobe")]
435+
impl From<&TrapFrame> for kprobe::PtRegs {
436+
fn from(tf: &TrapFrame) -> Self {
437+
kprobe::PtRegs {
438+
epc: tf.sepc,
439+
ra: tf.regs.ra,
440+
sp: tf.regs.sp,
441+
gp: tf.regs.gp,
442+
tp: tf.regs.tp,
443+
t0: tf.regs.t0,
444+
t1: tf.regs.t1,
445+
t2: tf.regs.t2,
446+
s0: tf.regs.s0,
447+
s1: tf.regs.s1,
448+
a0: tf.regs.a0,
449+
a1: tf.regs.a1,
450+
a2: tf.regs.a2,
451+
a3: tf.regs.a3,
452+
a4: tf.regs.a4,
453+
a5: tf.regs.a5,
454+
a6: tf.regs.a6,
455+
a7: tf.regs.a7,
456+
s2: tf.regs.s2,
457+
s3: tf.regs.s3,
458+
s4: tf.regs.s4,
459+
s5: tf.regs.s5,
460+
s6: tf.regs.s6,
461+
s7: tf.regs.s7,
462+
s8: tf.regs.s8,
463+
s9: tf.regs.s9,
464+
s10: tf.regs.s10,
465+
s11: tf.regs.s11,
466+
t3: tf.regs.t3,
467+
t4: tf.regs.t4,
468+
t5: tf.regs.t5,
469+
t6: tf.regs.t6,
470+
status: tf.sstatus.bits(),
471+
// todo : other fields
472+
badaddr: 0,
473+
cause: 0,
474+
orig_a0: 0,
475+
}
476+
}
477+
}
478+
479+
impl TrapFrame {
480+
/// Update the TrapFrame from kprobe::PtRegs
481+
pub fn update_from_ptregs(&mut self, ptregs: kprobe::PtRegs) {
482+
self.sepc = ptregs.epc;
483+
self.regs.ra = ptregs.ra;
484+
self.regs.sp = ptregs.sp;
485+
self.regs.gp = ptregs.gp;
486+
self.regs.tp = ptregs.tp;
487+
self.regs.t0 = ptregs.t0;
488+
self.regs.t1 = ptregs.t1;
489+
self.regs.t2 = ptregs.t2;
490+
self.regs.s0 = ptregs.s0;
491+
self.regs.s1 = ptregs.s1;
492+
self.regs.a0 = ptregs.a0;
493+
self.regs.a1 = ptregs.a1;
494+
self.regs.a2 = ptregs.a2;
495+
self.regs.a3 = ptregs.a3;
496+
self.regs.a4 = ptregs.a4;
497+
self.regs.a5 = ptregs.a5;
498+
self.regs.a6 = ptregs.a6;
499+
self.regs.a7 = ptregs.a7;
500+
self.regs.s2 = ptregs.s2;
501+
self.regs.s3 = ptregs.s3;
502+
self.regs.s4 = ptregs.s4;
503+
self.regs.s5 = ptregs.s5;
504+
self.regs.s6 = ptregs.s6;
505+
self.regs.s7 = ptregs.s7;
506+
self.regs.s8 = ptregs.s8;
507+
self.regs.s9 = ptregs.s9;
508+
self.regs.s10 = ptregs.s10;
509+
self.regs.s11 = ptregs.s11;
510+
self.regs.t3 = ptregs.t3;
511+
self.regs.t4 = ptregs.t4;
512+
self.regs.t5 = ptregs.t5;
513+
self.regs.t6 = ptregs.t6;
514+
self.sstatus = sstatus::Sstatus::from_bits(ptregs.status);
515+
}
516+
}

0 commit comments

Comments
 (0)