mod.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. use alloc::sync::Arc;
  2. use core::{
  3. arch::riscv64::sfence_vma_all,
  4. fmt::Debug,
  5. ops::{Deref, DerefMut},
  6. };
  7. use crate::{KprobeBasic, KprobeBuilder, KprobeOps};
  8. const EBREAK_INST: u32 = 0x00100073; // ebreak
  9. const C_EBREAK_INST: u32 = 0x9002; // c.ebreak
  10. const INSN_LENGTH_MASK: u16 = 0x3;
  11. const INSN_LENGTH_32: u16 = 0x3;
  12. #[derive(Debug)]
  13. pub struct Kprobe {
  14. basic: KprobeBasic,
  15. point: Arc<Rv64KprobePoint>,
  16. }
  17. #[derive(Debug)]
  18. enum OpcodeTy {
  19. Inst16(u16),
  20. Inst32(u32),
  21. }
  22. #[derive(Debug)]
  23. pub struct Rv64KprobePoint {
  24. addr: usize,
  25. old_instruction: OpcodeTy,
  26. inst_tmp: [u8; 8],
  27. }
  28. impl Deref for Kprobe {
  29. type Target = KprobeBasic;
  30. fn deref(&self) -> &Self::Target {
  31. &self.basic
  32. }
  33. }
  34. impl DerefMut for Kprobe {
  35. fn deref_mut(&mut self) -> &mut Self::Target {
  36. &mut self.basic
  37. }
  38. }
  39. impl Kprobe {
  40. pub fn probe_point(&self) -> &Arc<Rv64KprobePoint> {
  41. &self.point
  42. }
  43. }
  44. impl Drop for Rv64KprobePoint {
  45. fn drop(&mut self) {
  46. let address = self.addr;
  47. match self.old_instruction {
  48. OpcodeTy::Inst16(inst_16) => unsafe {
  49. core::ptr::write(address as *mut u16, inst_16);
  50. },
  51. OpcodeTy::Inst32(inst_32) => unsafe {
  52. core::ptr::write(address as *mut u32, inst_32);
  53. },
  54. }
  55. unsafe {
  56. sfence_vma_all();
  57. }
  58. log::trace!(
  59. "Kprobe::uninstall: address: {:#x}, old_instruction: {:?}",
  60. address,
  61. self.old_instruction
  62. );
  63. }
  64. }
  65. impl KprobeBuilder {
  66. pub fn install(self) -> (Kprobe, Arc<Rv64KprobePoint>) {
  67. let probe_point = match &self.probe_point {
  68. Some(point) => point.clone(),
  69. None => self.replace_inst(),
  70. };
  71. let kprobe = Kprobe {
  72. basic: KprobeBasic::from(self),
  73. point: probe_point.clone(),
  74. };
  75. (kprobe, probe_point)
  76. }
  77. /// # 安装kprobe
  78. ///
  79. /// 不同的架构下需要保存原指令,然后替换为断点指令
  80. fn replace_inst(&self) -> Arc<Rv64KprobePoint> {
  81. let address = self.symbol_addr + self.offset;
  82. let inst_16 = unsafe { core::ptr::read(address as *const u16) };
  83. // See https://elixir.bootlin.com/linux/v6.10.2/source/arch/riscv/kernel/probes/kprobes.c#L68
  84. let is_inst_16 = if (inst_16 & INSN_LENGTH_MASK) == INSN_LENGTH_32 {
  85. false
  86. } else {
  87. true
  88. };
  89. let mut point = Rv64KprobePoint {
  90. old_instruction: OpcodeTy::Inst16(0),
  91. inst_tmp: [0; 8],
  92. addr: address,
  93. };
  94. let inst_tmp_ptr = point.inst_tmp.as_ptr() as usize;
  95. if is_inst_16 {
  96. point.old_instruction = OpcodeTy::Inst16(inst_16);
  97. unsafe {
  98. core::ptr::write(address as *mut u16, C_EBREAK_INST as u16);
  99. // inst_16 :0-16
  100. // c.ebreak:16-32
  101. core::ptr::write(inst_tmp_ptr as *mut u16, inst_16);
  102. core::ptr::write((inst_tmp_ptr + 2) as *mut u16, C_EBREAK_INST as u16);
  103. }
  104. } else {
  105. let inst_32 = unsafe { core::ptr::read(address as *const u32) };
  106. point.old_instruction = OpcodeTy::Inst32(inst_32);
  107. unsafe {
  108. core::ptr::write(address as *mut u32, EBREAK_INST);
  109. // inst_32 :0-32
  110. // ebreak :32-64
  111. core::ptr::write(inst_tmp_ptr as *mut u32, inst_32);
  112. core::ptr::write((inst_tmp_ptr + 4) as *mut u32, EBREAK_INST);
  113. }
  114. }
  115. unsafe {
  116. sfence_vma_all();
  117. }
  118. log::trace!(
  119. "Kprobe::install: address: {:#x}, func_name: {:?}, opcode: {:x?}",
  120. address,
  121. self.symbol,
  122. point.old_instruction
  123. );
  124. Arc::new(point)
  125. }
  126. }
  127. impl KprobeOps for Rv64KprobePoint {
  128. fn return_address(&self) -> usize {
  129. let address = self.addr;
  130. match self.old_instruction {
  131. OpcodeTy::Inst16(_) => address + 2,
  132. OpcodeTy::Inst32(_) => address + 4,
  133. }
  134. }
  135. fn single_step_address(&self) -> usize {
  136. self.inst_tmp.as_ptr() as usize
  137. }
  138. fn debug_address(&self) -> usize {
  139. match self.old_instruction {
  140. OpcodeTy::Inst16(_) => self.inst_tmp.as_ptr() as usize + 2,
  141. OpcodeTy::Inst32(_) => self.inst_tmp.as_ptr() as usize + 4,
  142. }
  143. }
  144. fn break_address(&self) -> usize {
  145. self.addr
  146. }
  147. }