mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-21 14:23:39 +00:00
* 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
158 lines
4.4 KiB
Rust
158 lines
4.4 KiB
Rust
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
|
|
}
|
|
}
|