mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 10:03:23 +00:00
feat(ebpf):[WIP] add eBPF support (#948)
* feat(kprobe): Add basic kprobe support for x86_64 * feat: add ebpf support (#912) - 实现bpf()一部分命令,包括几种基本map,相关的helper函数 - 实现部分perf相关的数据结构 - 暂时为文件实现简单mmap - 实现一个使用kprobe统计syscall 调用次数的ebpf程序 对eBPF支持程度(基本): - 简单的eBPF程序(没有指定特殊的Map) - 使用内核已经实现的Map的eBPF程序 - 可以和kprobe配合使用 - 内核Map相关的接口定义已经实现,添加新的Map较为简单 不支持的功能: - 区分不同的eBPF程序类型(Network/Cgroup)并限定可调用的helper函数集 - 与内核其它跟踪机制配合(tracepoint) - 其它helper和Map todo - [ ] 修改mmap,需要讨论,因为这个和块缓存层相关 - [x] 添加文档 - [x] 修复可能的错误 - [x] 增加rbpf版本信息 * feat: add /sys/devices/system/cpu/possible file * feat: add /sys/devices/system/cpu/online
This commit is contained in:
11
kernel/crates/kprobe/Cargo.toml
Normal file
11
kernel/crates/kprobe/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "kprobe"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.21"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
yaxpeax-x86 = { version = "2", default-features = false, features = ["fmt"] }
|
||||
yaxpeax-arch = { version = "0", default-features = false }
|
112
kernel/crates/kprobe/src/arch/loongarch64/mod.rs
Normal file
112
kernel/crates/kprobe/src/arch/loongarch64/mod.rs
Normal file
@ -0,0 +1,112 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::{KprobeBasic, KprobeBuilder, KprobeOps};
|
||||
|
||||
const BRK_KPROBE_BP: u64 = 10;
|
||||
const BRK_KPROBE_SSTEPBP: u64 = 11;
|
||||
const EBREAK_INST: u32 = 0x002a0000;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Kprobe {
|
||||
basic: KprobeBasic,
|
||||
point: Arc<LA64KprobePoint>,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct LA64KprobePoint {
|
||||
addr: usize,
|
||||
inst_tmp: [u8; 8],
|
||||
}
|
||||
|
||||
impl Deref for Kprobe {
|
||||
type Target = KprobeBasic;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.basic
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Kprobe {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.basic
|
||||
}
|
||||
}
|
||||
|
||||
impl Kprobe {
|
||||
pub fn probe_point(&self) -> &Arc<LA64KprobePoint> {
|
||||
&self.point
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LA64KprobePoint {
|
||||
fn drop(&mut self) {
|
||||
let address = self.addr;
|
||||
let inst_tmp_ptr = self.inst_tmp.as_ptr() as usize;
|
||||
let inst_32 = unsafe { core::ptr::read(inst_tmp_ptr as *const u32) };
|
||||
unsafe {
|
||||
core::ptr::write(address as *mut u32, inst_32);
|
||||
}
|
||||
log::trace!(
|
||||
"Kprobe::uninstall: address: {:#x}, old_instruction: {:?}",
|
||||
address,
|
||||
inst_32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeBuilder {
|
||||
pub fn install(self) -> (Kprobe, Arc<LA64KprobePoint>) {
|
||||
let probe_point = match &self.probe_point {
|
||||
Some(point) => point.clone(),
|
||||
None => self.replace_inst(),
|
||||
};
|
||||
let kprobe = Kprobe {
|
||||
basic: KprobeBasic::from(self),
|
||||
point: probe_point.clone(),
|
||||
};
|
||||
(kprobe, probe_point)
|
||||
}
|
||||
/// # 安装kprobe
|
||||
///
|
||||
/// 不同的架构下需要保存原指令,然后替换为断点指令
|
||||
fn replace_inst(&self) -> Arc<LA64KprobePoint> {
|
||||
let address = self.symbol_addr + self.offset;
|
||||
let point = LA64KprobePoint {
|
||||
addr: address,
|
||||
inst_tmp: [0u8; 8],
|
||||
};
|
||||
let inst_tmp_ptr = point.inst_tmp.as_ptr() as usize;
|
||||
let inst_32 = unsafe { core::ptr::read(address as *const u32) };
|
||||
unsafe {
|
||||
core::ptr::write(address as *mut u32, EBREAK_INST);
|
||||
// inst_32 :0-32
|
||||
// ebreak :32-64
|
||||
core::ptr::write(inst_tmp_ptr as *mut u32, inst_32);
|
||||
core::ptr::write((inst_tmp_ptr + 4) as *mut u32, EBREAK_INST);
|
||||
}
|
||||
log::trace!(
|
||||
"Kprobe::install: address: {:#x}, func_name: {:?}, opcode: {:x?}",
|
||||
address,
|
||||
self.symbol,
|
||||
inst_32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeOps for LA64KprobePoint {
|
||||
fn return_address(&self) -> usize {
|
||||
self.addr + 4
|
||||
}
|
||||
|
||||
fn single_step_address(&self) -> usize {
|
||||
self.inst_tmp.as_ptr() as usize
|
||||
}
|
||||
|
||||
fn debug_address(&self) -> usize {
|
||||
self.inst_tmp.as_ptr() as usize + 4
|
||||
}
|
||||
|
||||
fn break_address(&self) -> usize {
|
||||
self.addr
|
||||
}
|
||||
}
|
211
kernel/crates/kprobe/src/arch/mod.rs
Normal file
211
kernel/crates/kprobe/src/arch/mod.rs
Normal file
@ -0,0 +1,211 @@
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
||||
#[cfg(target_arch = "loongarch64")]
|
||||
mod loongarch64;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
mod rv64;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod x86;
|
||||
|
||||
#[cfg(target_arch = "loongarch64")]
|
||||
pub use loongarch64::*;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub use rv64::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86::*;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub type KprobePoint = X86KprobePoint;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub type KprobePoint = Rv64KprobePoint;
|
||||
#[cfg(target_arch = "loongarch64")]
|
||||
pub type KprobePoint = LA64KprobePoint;
|
||||
|
||||
pub trait ProbeArgs: Send {
|
||||
/// 用于使用者转换到特定架构下的TrapFrame
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
/// 返回导致break异常的地址
|
||||
fn break_address(&self) -> usize;
|
||||
/// 返回导致单步执行异常的地址
|
||||
fn debug_address(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait KprobeOps: Send {
|
||||
/// # 返回探测点的下一条指令地址
|
||||
///
|
||||
/// 执行流需要回到正常的路径中,在执行完探测点的指令后,需要返回到下一条指令
|
||||
fn return_address(&self) -> usize;
|
||||
/// # 返回单步执行的指令地址
|
||||
///
|
||||
/// 通常探测点的处的原指令被保存在一个数组当中。根据架构的不同, 在保存的指令后面,可能会填充必要的指令。
|
||||
/// 例如x86架构下支持单步执行的特性, 而其它架构下通常没有,因此我们使用break异常来进行模拟,所以会填充
|
||||
/// 一条断点指令。
|
||||
fn single_step_address(&self) -> usize;
|
||||
/// # 返回单步执行指令触发异常的地址
|
||||
///
|
||||
/// 其值等于`single_step_address`的值加上探测点指令的长度
|
||||
fn debug_address(&self) -> usize;
|
||||
/// # 返回设置break断点的地址
|
||||
///
|
||||
/// 其值与探测点地址相等
|
||||
fn break_address(&self) -> usize;
|
||||
}
|
||||
|
||||
struct ProbeHandler {
|
||||
func: fn(&dyn ProbeArgs),
|
||||
}
|
||||
|
||||
impl ProbeHandler {
|
||||
pub fn new(func: fn(&dyn ProbeArgs)) -> Self {
|
||||
ProbeHandler { func }
|
||||
}
|
||||
/// 调用探测点处理函数
|
||||
pub fn call(&self, trap_frame: &dyn ProbeArgs) {
|
||||
(self.func)(trap_frame);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KprobeBuilder {
|
||||
symbol: Option<String>,
|
||||
symbol_addr: usize,
|
||||
offset: usize,
|
||||
pre_handler: ProbeHandler,
|
||||
post_handler: ProbeHandler,
|
||||
fault_handler: Option<ProbeHandler>,
|
||||
event_callback: Option<Box<dyn CallBackFunc>>,
|
||||
probe_point: Option<Arc<KprobePoint>>,
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
pub trait EventCallback: Send {
|
||||
fn call(&self, trap_frame: &dyn ProbeArgs);
|
||||
}
|
||||
|
||||
impl KprobeBuilder {
|
||||
pub fn new(
|
||||
symbol: Option<String>,
|
||||
symbol_addr: usize,
|
||||
offset: usize,
|
||||
pre_handler: fn(&dyn ProbeArgs),
|
||||
post_handler: fn(&dyn ProbeArgs),
|
||||
enable: bool,
|
||||
) -> Self {
|
||||
KprobeBuilder {
|
||||
symbol,
|
||||
symbol_addr,
|
||||
offset,
|
||||
pre_handler: ProbeHandler::new(pre_handler),
|
||||
post_handler: ProbeHandler::new(post_handler),
|
||||
event_callback: None,
|
||||
fault_handler: None,
|
||||
probe_point: None,
|
||||
enable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_fault_handler(mut self, func: fn(&dyn ProbeArgs)) -> Self {
|
||||
self.fault_handler = Some(ProbeHandler::new(func));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_probe_point(mut self, point: Arc<KprobePoint>) -> Self {
|
||||
self.probe_point = Some(point);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_event_callback(mut self, event_callback: Box<dyn CallBackFunc>) -> Self {
|
||||
self.event_callback = Some(event_callback);
|
||||
self
|
||||
}
|
||||
|
||||
/// 获取探测点的地址
|
||||
///
|
||||
/// 探测点的地址 == break指令的地址
|
||||
pub fn probe_addr(&self) -> usize {
|
||||
self.symbol_addr + self.offset
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KprobeBasic {
|
||||
symbol: Option<String>,
|
||||
symbol_addr: usize,
|
||||
offset: usize,
|
||||
pre_handler: ProbeHandler,
|
||||
post_handler: ProbeHandler,
|
||||
fault_handler: ProbeHandler,
|
||||
event_callback: Option<Box<dyn CallBackFunc>>,
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
pub trait CallBackFunc: Send + Sync {
|
||||
fn call(&self, trap_frame: &dyn ProbeArgs);
|
||||
}
|
||||
|
||||
impl Debug for KprobeBasic {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Kprobe")
|
||||
.field("symbol", &self.symbol)
|
||||
.field("symbol_addr", &self.symbol_addr)
|
||||
.field("offset", &self.offset)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeBasic {
|
||||
pub fn call_pre_handler(&self, trap_frame: &dyn ProbeArgs) {
|
||||
self.pre_handler.call(trap_frame);
|
||||
}
|
||||
|
||||
pub fn call_post_handler(&self, trap_frame: &dyn ProbeArgs) {
|
||||
self.post_handler.call(trap_frame);
|
||||
}
|
||||
|
||||
pub fn call_fault_handler(&self, trap_frame: &dyn ProbeArgs) {
|
||||
self.fault_handler.call(trap_frame);
|
||||
}
|
||||
|
||||
pub fn call_event_callback(&self, trap_frame: &dyn ProbeArgs) {
|
||||
if let Some(ref call_back) = self.event_callback {
|
||||
call_back.call(trap_frame);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_event_callback(&mut self, callback: Box<dyn CallBackFunc>) {
|
||||
self.event_callback = Some(callback);
|
||||
}
|
||||
|
||||
pub fn disable(&mut self) {
|
||||
self.enable = false;
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
self.enable = true;
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.enable
|
||||
}
|
||||
/// 返回探测点的函数名称
|
||||
pub fn symbol(&self) -> Option<&str> {
|
||||
self.symbol.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KprobeBuilder> for KprobeBasic {
|
||||
fn from(value: KprobeBuilder) -> Self {
|
||||
let fault_handler = value.fault_handler.unwrap_or(ProbeHandler::new(|_| {}));
|
||||
KprobeBasic {
|
||||
symbol: value.symbol,
|
||||
symbol_addr: value.symbol_addr,
|
||||
offset: value.offset,
|
||||
pre_handler: value.pre_handler,
|
||||
post_handler: value.post_handler,
|
||||
event_callback: value.event_callback,
|
||||
fault_handler,
|
||||
enable: value.enable,
|
||||
}
|
||||
}
|
||||
}
|
157
kernel/crates/kprobe/src/arch/rv64/mod.rs
Normal file
157
kernel/crates/kprobe/src/arch/rv64/mod.rs
Normal file
@ -0,0 +1,157 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::{
|
||||
arch::riscv64::sfence_vma_all,
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use crate::{KprobeBasic, KprobeBuilder, KprobeOps};
|
||||
const EBREAK_INST: u32 = 0x00100073; // ebreak
|
||||
const C_EBREAK_INST: u32 = 0x9002; // c.ebreak
|
||||
const INSN_LENGTH_MASK: u16 = 0x3;
|
||||
const INSN_LENGTH_32: u16 = 0x3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Kprobe {
|
||||
basic: KprobeBasic,
|
||||
point: Arc<Rv64KprobePoint>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OpcodeTy {
|
||||
Inst16(u16),
|
||||
Inst32(u32),
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct Rv64KprobePoint {
|
||||
addr: usize,
|
||||
old_instruction: OpcodeTy,
|
||||
inst_tmp: [u8; 8],
|
||||
}
|
||||
|
||||
impl Deref for Kprobe {
|
||||
type Target = KprobeBasic;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.basic
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Kprobe {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.basic
|
||||
}
|
||||
}
|
||||
|
||||
impl Kprobe {
|
||||
pub fn probe_point(&self) -> &Arc<Rv64KprobePoint> {
|
||||
&self.point
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Rv64KprobePoint {
|
||||
fn drop(&mut self) {
|
||||
let address = self.addr;
|
||||
match self.old_instruction {
|
||||
OpcodeTy::Inst16(inst_16) => unsafe {
|
||||
core::ptr::write(address as *mut u16, inst_16);
|
||||
},
|
||||
OpcodeTy::Inst32(inst_32) => unsafe {
|
||||
core::ptr::write(address as *mut u32, inst_32);
|
||||
},
|
||||
}
|
||||
unsafe {
|
||||
sfence_vma_all();
|
||||
}
|
||||
log::trace!(
|
||||
"Kprobe::uninstall: address: {:#x}, old_instruction: {:?}",
|
||||
address,
|
||||
self.old_instruction
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeBuilder {
|
||||
pub fn install(self) -> (Kprobe, Arc<Rv64KprobePoint>) {
|
||||
let probe_point = match &self.probe_point {
|
||||
Some(point) => point.clone(),
|
||||
None => self.replace_inst(),
|
||||
};
|
||||
let kprobe = Kprobe {
|
||||
basic: KprobeBasic::from(self),
|
||||
point: probe_point.clone(),
|
||||
};
|
||||
(kprobe, probe_point)
|
||||
}
|
||||
/// # 安装kprobe
|
||||
///
|
||||
/// 不同的架构下需要保存原指令,然后替换为断点指令
|
||||
fn replace_inst(&self) -> Arc<Rv64KprobePoint> {
|
||||
let address = self.symbol_addr + self.offset;
|
||||
let inst_16 = unsafe { core::ptr::read(address as *const u16) };
|
||||
// See https://elixir.bootlin.com/linux/v6.10.2/source/arch/riscv/kernel/probes/kprobes.c#L68
|
||||
let is_inst_16 = if (inst_16 & INSN_LENGTH_MASK) == INSN_LENGTH_32 {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
let mut point = Rv64KprobePoint {
|
||||
old_instruction: OpcodeTy::Inst16(0),
|
||||
inst_tmp: [0; 8],
|
||||
addr: address,
|
||||
};
|
||||
let inst_tmp_ptr = point.inst_tmp.as_ptr() as usize;
|
||||
if is_inst_16 {
|
||||
point.old_instruction = OpcodeTy::Inst16(inst_16);
|
||||
unsafe {
|
||||
core::ptr::write(address as *mut u16, C_EBREAK_INST as u16);
|
||||
// inst_16 :0-16
|
||||
// c.ebreak:16-32
|
||||
core::ptr::write(inst_tmp_ptr as *mut u16, inst_16);
|
||||
core::ptr::write((inst_tmp_ptr + 2) as *mut u16, C_EBREAK_INST as u16);
|
||||
}
|
||||
} else {
|
||||
let inst_32 = unsafe { core::ptr::read(address as *const u32) };
|
||||
point.old_instruction = OpcodeTy::Inst32(inst_32);
|
||||
unsafe {
|
||||
core::ptr::write(address as *mut u32, EBREAK_INST);
|
||||
// inst_32 :0-32
|
||||
// ebreak :32-64
|
||||
core::ptr::write(inst_tmp_ptr as *mut u32, inst_32);
|
||||
core::ptr::write((inst_tmp_ptr + 4) as *mut u32, EBREAK_INST);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
sfence_vma_all();
|
||||
}
|
||||
log::trace!(
|
||||
"Kprobe::install: address: {:#x}, func_name: {:?}, opcode: {:x?}",
|
||||
address,
|
||||
self.symbol,
|
||||
point.old_instruction
|
||||
);
|
||||
Arc::new(point)
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeOps for Rv64KprobePoint {
|
||||
fn return_address(&self) -> usize {
|
||||
let address = self.addr;
|
||||
match self.old_instruction {
|
||||
OpcodeTy::Inst16(_) => address + 2,
|
||||
OpcodeTy::Inst32(_) => address + 4,
|
||||
}
|
||||
}
|
||||
fn single_step_address(&self) -> usize {
|
||||
self.inst_tmp.as_ptr() as usize
|
||||
}
|
||||
fn debug_address(&self) -> usize {
|
||||
match self.old_instruction {
|
||||
OpcodeTy::Inst16(_) => self.inst_tmp.as_ptr() as usize + 2,
|
||||
OpcodeTy::Inst32(_) => self.inst_tmp.as_ptr() as usize + 4,
|
||||
}
|
||||
}
|
||||
fn break_address(&self) -> usize {
|
||||
self.addr
|
||||
}
|
||||
}
|
135
kernel/crates/kprobe/src/arch/x86/mod.rs
Normal file
135
kernel/crates/kprobe/src/arch/x86/mod.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use crate::{KprobeBasic, KprobeBuilder, KprobeOps};
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use yaxpeax_arch::LengthedInstruction;
|
||||
|
||||
const EBREAK_INST: u8 = 0xcc; // x86_64: 0xcc
|
||||
const MAX_INSTRUCTION_SIZE: usize = 15; // x86_64 max instruction length
|
||||
|
||||
pub struct Kprobe {
|
||||
basic: KprobeBasic,
|
||||
point: Arc<X86KprobePoint>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct X86KprobePoint {
|
||||
addr: usize,
|
||||
old_instruction: [u8; MAX_INSTRUCTION_SIZE],
|
||||
old_instruction_len: usize,
|
||||
}
|
||||
|
||||
impl Drop for X86KprobePoint {
|
||||
fn drop(&mut self) {
|
||||
let address = self.addr;
|
||||
unsafe {
|
||||
core::ptr::copy(
|
||||
self.old_instruction.as_ptr(),
|
||||
address as *mut u8,
|
||||
self.old_instruction_len,
|
||||
);
|
||||
core::arch::x86_64::_mm_mfence();
|
||||
}
|
||||
let decoder = yaxpeax_x86::amd64::InstDecoder::default();
|
||||
let inst = decoder.decode_slice(&self.old_instruction).unwrap();
|
||||
log::trace!(
|
||||
"Kprobe::uninstall: address: {:#x}, old_instruction: {:?}",
|
||||
address,
|
||||
inst.to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Kprobe {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Kprobe")
|
||||
.field("basic", &self.basic)
|
||||
.field("point", &self.point)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Kprobe {
|
||||
type Target = KprobeBasic;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.basic
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Kprobe {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.basic
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeBuilder {
|
||||
pub fn install(self) -> (Kprobe, Arc<X86KprobePoint>) {
|
||||
let probe_point = match &self.probe_point {
|
||||
Some(point) => point.clone(),
|
||||
None => self.replace_inst(),
|
||||
};
|
||||
let kprobe = Kprobe {
|
||||
basic: KprobeBasic::from(self),
|
||||
point: probe_point.clone(),
|
||||
};
|
||||
(kprobe, probe_point)
|
||||
}
|
||||
/// # 安装kprobe
|
||||
///
|
||||
/// 不同的架构下需要保存原指令,然后替换为断点指令
|
||||
fn replace_inst(&self) -> Arc<X86KprobePoint> {
|
||||
let address = self.symbol_addr + self.offset;
|
||||
let mut inst_tmp = [0u8; MAX_INSTRUCTION_SIZE];
|
||||
unsafe {
|
||||
core::ptr::copy(
|
||||
address as *const u8,
|
||||
inst_tmp.as_mut_ptr(),
|
||||
MAX_INSTRUCTION_SIZE,
|
||||
);
|
||||
}
|
||||
let decoder = yaxpeax_x86::amd64::InstDecoder::default();
|
||||
let inst = decoder.decode_slice(&inst_tmp).unwrap();
|
||||
let len = inst.len().to_const();
|
||||
log::trace!("inst: {:?}, len: {:?}", inst.to_string(), len);
|
||||
let point = Arc::new(X86KprobePoint {
|
||||
addr: address,
|
||||
old_instruction: inst_tmp,
|
||||
old_instruction_len: len as usize,
|
||||
});
|
||||
unsafe {
|
||||
core::ptr::write_volatile(address as *mut u8, EBREAK_INST);
|
||||
core::arch::x86_64::_mm_mfence();
|
||||
}
|
||||
log::trace!(
|
||||
"Kprobe::install: address: {:#x}, func_name: {:?}",
|
||||
address,
|
||||
self.symbol
|
||||
);
|
||||
point
|
||||
}
|
||||
}
|
||||
|
||||
impl Kprobe {
|
||||
pub fn probe_point(&self) -> &Arc<X86KprobePoint> {
|
||||
&self.point
|
||||
}
|
||||
}
|
||||
|
||||
impl KprobeOps for X86KprobePoint {
|
||||
fn return_address(&self) -> usize {
|
||||
self.addr + self.old_instruction_len
|
||||
}
|
||||
fn single_step_address(&self) -> usize {
|
||||
self.old_instruction.as_ptr() as usize
|
||||
}
|
||||
fn debug_address(&self) -> usize {
|
||||
self.old_instruction.as_ptr() as usize + self.old_instruction_len
|
||||
}
|
||||
fn break_address(&self) -> usize {
|
||||
self.addr
|
||||
}
|
||||
}
|
7
kernel/crates/kprobe/src/lib.rs
Normal file
7
kernel/crates/kprobe/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
||||
mod arch;
|
||||
|
||||
pub use arch::*;
|
Reference in New Issue
Block a user