Răsfoiți Sursa

feat: support tracepoint-based ebpf programs (#1190)

* feat: support tracepoint-based ebpf programs

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* remove licenses

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* feat: Supplement tracepoint related files

fix some warnings
add docs for tracepoint

Signed-off-by: Godones <chenlinfeng25@outlook.com>

---------

Signed-off-by: Godones <chenlinfeng25@outlook.com>
Co-authored-by: longjin <longjin@DragonOS.org>
linfeng 1 zi în urmă
părinte
comite
6b581d4dd8
31 a modificat fișierele cu 1868 adăugiri și 60 ștergeri
  1. 1 0
      docs/kernel/trace/index.rst
  2. 60 0
      docs/kernel/trace/tracepoint.md
  3. 1 0
      kernel/src/bpf/helper/consts.rs
  4. 46 7
      kernel/src/bpf/helper/mod.rs
  5. 23 10
      kernel/src/debug/tracing/mod.rs
  6. 120 3
      kernel/src/debug/tracing/trace_pipe.rs
  7. 2 1
      kernel/src/filesystem/kernfs/callback.rs
  8. 30 0
      kernel/src/filesystem/vfs/syscall/open_utils.rs
  9. 10 2
      kernel/src/perf/mod.rs
  10. 178 0
      kernel/src/perf/tracepoint.rs
  11. 14 2
      kernel/src/perf/util.rs
  12. 12 4
      kernel/src/tracepoint/basic_macro.rs
  13. 5 2
      kernel/src/tracepoint/mod.rs
  14. 44 21
      kernel/src/tracepoint/point.rs
  15. 38 8
      kernel/src/tracepoint/trace_pipe.rs
  16. 9 0
      user/apps/test_tracepoint/.gitignore
  17. 794 0
      user/apps/test_tracepoint/Cargo.lock
  18. 33 0
      user/apps/test_tracepoint/Cargo.toml
  19. 57 0
      user/apps/test_tracepoint/Makefile
  20. 57 0
      user/apps/test_tracepoint/README.md
  21. 16 0
      user/apps/test_tracepoint/mytrace-common/Cargo.toml
  22. 1 0
      user/apps/test_tracepoint/mytrace-common/src/lib.rs
  23. 17 0
      user/apps/test_tracepoint/mytrace-ebpf/Cargo.toml
  24. 17 0
      user/apps/test_tracepoint/mytrace-ebpf/build.rs
  25. 3 0
      user/apps/test_tracepoint/mytrace-ebpf/src/lib.rs
  26. 119 0
      user/apps/test_tracepoint/mytrace-ebpf/src/main.rs
  27. 44 0
      user/apps/test_tracepoint/mytrace/Cargo.toml
  28. 14 0
      user/apps/test_tracepoint/mytrace/build.rs
  29. 62 0
      user/apps/test_tracepoint/mytrace/src/main.rs
  30. 4 0
      user/apps/test_tracepoint/rustfmt.toml
  31. 37 0
      user/dadk/config/test_tracepoint.toml

+ 1 - 0
docs/kernel/trace/index.rst

@@ -9,3 +9,4 @@
 
    eBPF
    kprobe
+   tracepoint

+ 60 - 0
docs/kernel/trace/tracepoint.md

@@ -0,0 +1,60 @@
+# Tracepoints
+
+> 作者: 陈林峰
+>
+> Email: chenlinfeng25@outlook.com
+
+
+## 概述
+Tracepoints 是 Linux 内核提供的一种跟踪机制,允许开发者在内核代码的特定位置插入探测点,以便收集运行时信息。与 kprobes 不同,tracepoints 是预定义的,并且通常用于收集性能数据或调试信息,而不需要修改内核代码。
+
+## 工作流程
+1. **定义 Tracepoint**: 内核开发者在代码中定义 tracepoint,使用宏 `define_event_trace`。
+2. **触发 Tracepoint**: 在代码的其他部分,开发者可以使用 `define_event_trace` 定义的函数来触发已定义的 tracepoint,并传递相关的上下文信息。比如定义的tracepoint名称为`my_tracepoint`,则可以使用 `trace_my_tracepoint()` 来触发它。
+3.  **收集数据**: 当 tracepoint 被触发时,内核会记录相关的数据,这些数据可以通过用户空间工具(如 `trace-cmd` 或 `perf`)进行分析。现在DragonOS中还只能支持查看内核为这些数据创建的文件。
+    1.  读取`/sys/kernel/debug/tracing/trace`文件可以查看tracepoint收集的数据。缓冲区的内容不会被清除。
+    2.  读取`/sys/kernel/debug/tracing/trace_pipe`文件可以查看tracepoint收集的数据。缓冲区的内容会被清除。如果缓冲区没有内容,则会阻塞等待新的数据。
+    3.  读取`/sys/kernel/debug/tracing/events/`目录可以查看所有可用的 tracepoints。
+    4.  读取`/sys/kernel/debug/tracing/events/<event_name>/format`文件可以查看特定 tracepoint 的数据格式。
+    5.  写入`/sys/kernel/debug/tracing/events/<event_name>/enable` 文件可以启用特定的 tracepoint。
+    6.  写入空值到 `/sys/kernel/debug/tracing/trace` 可以清空当前的 trace 数据。
+4. **分析数据**: 用户空间工具可以读取 tracepoint 收集的数据,并生成报告或图表,以帮助开发者理解内核行为。
+
+
+## 接口
+```rust
+define_event_trace!() // 定义一个 tracepoint
+```
+
+```rust
+// example
+define_event_trace!(
+    sys_enter_openat,
+    TP_system(syscalls),
+    TP_PROTO(dfd: i32, path:*const u8, o_flags: u32, mode: u32),
+    TP_STRUCT__entry{
+        dfd: i32,
+        path: u64,
+        o_flags: u32,
+        mode: u32,
+    },
+    TP_fast_assign{
+        dfd: dfd,
+        path: path as u64,
+        o_flags: o_flags,
+        mode: mode,
+    },
+    TP_ident(__entry),
+    TP_printk({
+        format!(
+            "dfd: {}, path: {:#x}, o_flags: {:?}, mode: {:?}",
+            __entry.dfd,
+            __entry.path,
+            __entry.o_flags,
+            __entry.mode
+        )
+    })
+);
+```
+## Tracepoints For eBPF
+在 DragonOS 中,tracepoints 也可以与 eBPF 结合使用,以便在内核中收集更丰富的数据。eBPF 程序可以附加到 tracepoints 上,以便在 tracepoint 被触发时执行自定义的逻辑。

+ 1 - 0
kernel/src/bpf/helper/consts.rs

@@ -10,3 +10,4 @@ pub const HELPER_TRACE_PRINTF: u32 = 6;
 pub const HELPER_MAP_PUSH_ELEM: u32 = 87;
 pub const HELPER_MAP_POP_ELEM: u32 = 88;
 pub const HELPER_MAP_PEEK_ELEM: u32 = 89;
+pub const HELPER_PROBE_READ_USER_STR: u32 = 114;

+ 46 - 7
kernel/src/bpf/helper/mod.rs

@@ -6,6 +6,7 @@ use crate::bpf::map::{BpfCallBackFn, BpfMap};
 use crate::include::bindings::linux_bpf::BPF_F_CURRENT_CPU;
 use crate::libs::lazy_init::Lazy;
 use crate::smp::core::smp_get_processor_id;
+use crate::syscall::user_access::check_and_clone_cstr;
 use crate::time::Instant;
 use alloc::{collections::BTreeMap, sync::Arc};
 use core::ffi::c_void;
@@ -89,12 +90,12 @@ pub fn perf_event_output(
 
 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_probe_read/
 fn raw_bpf_probe_read(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) -> i64 {
-    log::info!(
-        "raw_bpf_probe_read, dst:{:x}, size:{}, unsafe_ptr: {:x}",
-        dst as usize,
-        size,
-        unsafe_ptr as usize
-    );
+    // log::info!(
+    //     "raw_bpf_probe_read, dst:{:x}, size:{}, unsafe_ptr: {:x}",
+    //     dst as usize,
+    //     size,
+    //     unsafe_ptr as usize
+    // );
     let (dst, src) = unsafe {
         let dst = core::slice::from_raw_parts_mut(dst as *mut u8, size as usize);
         let src = core::slice::from_raw_parts(unsafe_ptr as *const u8, size as usize);
@@ -111,7 +112,7 @@ fn raw_bpf_probe_read(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) ->
 /// bytes from kernel space address unsafe_ptr and
 /// store the data in dst.
 pub fn bpf_probe_read(dst: &mut [u8], src: &[u8]) -> Result<()> {
-    log::info!("bpf_probe_read: len: {}", dst.len());
+    // log::info!("bpf_probe_read: len: {}", dst.len());
     dst.copy_from_slice(src);
     Ok(())
 }
@@ -305,6 +306,38 @@ pub fn bpf_ktime_get_ns() -> u64 {
     (Instant::now().total_micros() * 1000) as u64
 }
 
+/// Copy a NULL terminated string from an unsafe user address unsafe_ptr to dst.
+/// The size should include the terminating NULL byte. In case the string length is smaller than size,
+/// the target is not padded with further NULL bytes. If the string length is larger than size,
+/// just size-1 bytes are copied and the last byte is set to NULL.
+///
+/// On success, the strictly positive length of the output string, including the trailing NULL character. On error, a negative value
+///
+/// See https://docs.ebpf.io/linux/helper-function/bpf_probe_read_user_str/
+unsafe fn raw_probe_read_user_str(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) -> i64 {
+    // log::info!(
+    //     "<raw_probe_read_user_str>: dst:{:x}, size:{}, unsafe_ptr: {:x}",
+    //     dst as usize,
+    //     size,
+    //     unsafe_ptr as usize
+    // );
+    let dst = core::slice::from_raw_parts_mut(dst as *mut u8, size as usize);
+    let res = probe_read_user_str(dst, unsafe_ptr as *const u8);
+    match res {
+        Ok(len) => len as i64,
+        Err(e) => e as i64,
+    }
+}
+
+pub fn probe_read_user_str(dst: &mut [u8], src: *const u8) -> Result<usize> {
+    let str = check_and_clone_cstr(src, None).unwrap();
+    let len = str.as_bytes().len();
+    let copy_len = len.min(dst.len() - 1); // Leave space for NULL terminator
+    dst[..copy_len].copy_from_slice(&str.as_bytes()[..copy_len]);
+    dst[copy_len] = 0; // Null-terminate the string
+    Ok(copy_len + 1) // Return length including NULL terminator
+}
+
 pub static BPF_HELPER_FUN_SET: Lazy<BTreeMap<u32, RawBPFHelperFn>> = Lazy::new();
 
 /// Initialize the helper functions.
@@ -341,6 +374,12 @@ pub fn init_helper_functions() {
         map.insert(HELPER_MAP_PUSH_ELEM, define_func!(raw_map_push_elem));
         map.insert(HELPER_MAP_POP_ELEM, define_func!(raw_map_pop_elem));
         map.insert(HELPER_MAP_PEEK_ELEM, define_func!(raw_map_peek_elem));
+
+        // User access helpers
+        map.insert(
+            HELPER_PROBE_READ_USER_STR,
+            define_func!(raw_probe_read_user_str),
+        );
     }
     BPF_HELPER_FUN_SET.init(map);
 }

+ 23 - 10
kernel/src/debug/tracing/mod.rs

@@ -8,11 +8,13 @@ use crate::filesystem::kernfs::KernFSInode;
 use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::PollStatus;
 use crate::libs::spinlock::SpinLock;
-use crate::tracepoint::TracePointInfo;
+use crate::tracepoint::{TraceCmdLineCacheSnapshot, TracePointInfo};
 use alloc::string::ToString;
 use alloc::sync::Arc;
 use system_error::SystemError;
 
+pub use events::tracing_events_manager;
+
 static mut TRACING_ROOT_INODE: Option<Arc<KernFSInode>> = None;
 
 static TRACE_RAW_PIPE: SpinLock<crate::tracepoint::TracePipeRaw> =
@@ -22,6 +24,7 @@ static TRACE_CMDLINE_CACHE: SpinLock<crate::tracepoint::TraceCmdLineCache> =
     SpinLock::new(crate::tracepoint::TraceCmdLineCache::new(128));
 
 pub fn trace_pipe_push_raw_record(record: &[u8]) {
+    // log::debug!("trace_pipe_push_raw_record: {}", record.len());
     TRACE_RAW_PIPE.lock().push_event(record.to_vec());
 }
 
@@ -89,6 +92,13 @@ impl KernInodePrivateData {
             _ => None,
         };
     }
+
+    pub fn trace_saved_cmdlines(&mut self) -> Option<&mut TraceCmdLineCacheSnapshot> {
+        return match self {
+            KernInodePrivateData::TraceSavedCmdlines(cache) => Some(cache),
+            _ => None,
+        };
+    }
 }
 
 /// Initialize the debugfs tracing directory
@@ -108,15 +118,7 @@ pub fn init_debugfs_tracing() -> Result<(), SystemError> {
         Some(&TracingDirCallBack),
     )?;
 
-    // tracing_root.add_file(
-    //     "trace".to_string(),
-    //     ModeType::from_bits_truncate(0o444),
-    //     Some(4096),
-    //     None,
-    //     Some(&trace_pipe::TraceCallBack),
-    // )?;
-
-    tracing_root.add_file_lazy("trace".to_string(), trace_pipe::kernel_inode_provider)?;
+    tracing_root.add_file_lazy("trace".to_string(), trace_pipe::kernel_inode_provider_trace)?;
 
     tracing_root.add_file(
         "trace_pipe".to_string(),
@@ -125,6 +127,17 @@ pub fn init_debugfs_tracing() -> Result<(), SystemError> {
         None,
         Some(&trace_pipe::TracePipeCallBack),
     )?;
+    tracing_root.add_file_lazy(
+        "saved_cmdlines".to_string(),
+        trace_pipe::kernel_inode_provider_saved_cmdlines,
+    )?;
+    tracing_root.add_file(
+        "saved_cmdlines_size".to_string(),
+        ModeType::from_bits_truncate(0o444),
+        None,
+        None,
+        Some(&trace_pipe::SavedCmdlinesSizeCallBack),
+    )?;
 
     events::init_events(events_root)?;
 

+ 120 - 3
kernel/src/debug/tracing/trace_pipe.rs

@@ -6,6 +6,7 @@ use crate::libs::wait_queue::WaitQueue;
 use crate::process::{ProcessFlags, ProcessManager};
 use crate::sched::SchedMode;
 use crate::tracepoint::{TraceEntryParser, TracePipeOps};
+use alloc::string::String;
 use core::fmt::Debug;
 use system_error::SystemError;
 
@@ -73,10 +74,14 @@ impl KernFSCallback for TraceCallBack {
     fn write(
         &self,
         _data: KernCallbackData,
-        _buf: &[u8],
+        buf: &[u8],
         _offset: usize,
     ) -> Result<usize, SystemError> {
-        Err(SystemError::EPERM)
+        if buf.len() == 1 {
+            let mut trace_raw_pipe = super::TRACE_RAW_PIPE.lock();
+            trace_raw_pipe.clear();
+        }
+        Ok(buf.len())
     }
 
     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
@@ -84,7 +89,7 @@ impl KernFSCallback for TraceCallBack {
     }
 }
 
-pub fn kernel_inode_provider() -> KernFSInodeArgs {
+pub fn kernel_inode_provider_trace() -> KernFSInodeArgs {
     KernFSInodeArgs {
         mode: ModeType::from_bits_truncate(0o444),
         callback: Some(&TraceCallBack),
@@ -152,3 +157,115 @@ impl KernFSCallback for TracePipeCallBack {
         Ok(PollStatus::READ)
     }
 }
+
+#[derive(Debug)]
+pub struct SavedCmdlinesSizeCallBack;
+
+impl KernFSCallback for SavedCmdlinesSizeCallBack {
+    fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn read(
+        &self,
+        _data: KernCallbackData,
+        buf: &mut [u8],
+        offset: usize,
+    ) -> Result<usize, SystemError> {
+        let max_record = super::TRACE_CMDLINE_CACHE.lock().max_record();
+        let str = format!("{}\n", max_record);
+        let str_bytes = str.as_bytes();
+        if offset >= str_bytes.len() {
+            return Ok(0); // Offset is beyond the length of the string
+        }
+        let len = buf.len().min(str_bytes.len() - offset);
+        buf[..len].copy_from_slice(&str_bytes[offset..offset + len]);
+        Ok(len)
+    }
+
+    fn write(
+        &self,
+        _data: KernCallbackData,
+        buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        let max_record_str = String::from_utf8_lossy(buf);
+        let max_record: usize = max_record_str
+            .trim()
+            .parse()
+            .map_err(|_| SystemError::EINVAL)?;
+        super::TRACE_CMDLINE_CACHE.lock().set_max_record(max_record);
+        Ok(buf.len())
+    }
+
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+}
+
+pub fn kernel_inode_provider_saved_cmdlines() -> KernFSInodeArgs {
+    KernFSInodeArgs {
+        mode: ModeType::from_bits_truncate(0o444),
+        callback: Some(&SavedCmdlinesSnapshotCallBack),
+        inode_type: KernInodeType::File,
+        size: Some(4096),
+        private_data: None,
+    }
+}
+
+#[derive(Debug)]
+pub struct SavedCmdlinesSnapshotCallBack;
+
+impl KernFSCallback for SavedCmdlinesSnapshotCallBack {
+    fn open(&self, mut data: KernCallbackData) -> Result<(), SystemError> {
+        let pri_data = data.private_data_mut();
+        let snapshot = super::TRACE_CMDLINE_CACHE.lock().snapshot();
+        pri_data.replace(KernInodePrivateData::TraceSavedCmdlines(snapshot));
+        Ok(())
+    }
+
+    fn read(
+        &self,
+        mut data: KernCallbackData,
+        buf: &mut [u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        let pri_data = data.private_data_mut().as_mut().unwrap();
+        let snapshot = pri_data.trace_saved_cmdlines().unwrap();
+
+        let mut copy_len = 0;
+        let mut peek_flag = false;
+        loop {
+            if let Some((pid, cmdline)) = snapshot.peek() {
+                let record_str = format!("{} {}\n", pid, String::from_utf8_lossy(cmdline));
+                if copy_len + record_str.len() > buf.len() {
+                    break;
+                }
+                let len = record_str.len();
+                buf[copy_len..copy_len + len].copy_from_slice(record_str.as_bytes());
+                copy_len += len;
+                peek_flag = true;
+            }
+            if peek_flag {
+                snapshot.pop(); // Remove the record after reading
+                peek_flag = false;
+            } else {
+                break; // No more records to read
+            }
+        }
+        Ok(copy_len)
+    }
+
+    fn write(
+        &self,
+        _data: KernCallbackData,
+        _buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::EPERM)
+    }
+
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+}

+ 2 - 1
kernel/src/filesystem/kernfs/callback.rs

@@ -1,5 +1,5 @@
 use super::KernFSInode;
-use crate::tracepoint::{TracePipeSnapshot, TracePointInfo};
+use crate::tracepoint::{TraceCmdLineCacheSnapshot, TracePipeSnapshot, TracePointInfo};
 use crate::{
     filesystem::{sysfs::SysFSKernPrivateData, vfs::PollStatus},
     libs::spinlock::SpinLockGuard,
@@ -88,6 +88,7 @@ pub enum KernInodePrivateData {
     SysFS(SysFSKernPrivateData),
     DebugFS(Arc<TracePointInfo>),
     TracePipe(TracePipeSnapshot),
+    TraceSavedCmdlines(TraceCmdLineCacheSnapshot),
 }
 
 impl KernInodePrivateData {

+ 30 - 0
kernel/src/filesystem/vfs/syscall/open_utils.rs

@@ -1,6 +1,7 @@
 use system_error::SystemError;
 
 use crate::{
+    define_event_trace,
     filesystem::vfs::{fcntl::AtFlags, file::FileMode, open::do_sys_open, MAX_PATHLEN},
     syscall::user_access::check_and_clone_cstr,
 };
@@ -23,6 +24,7 @@ pub(super) fn do_open(
     mode: u32,
     follow_symlink: bool,
 ) -> Result<usize, SystemError> {
+    trace_sys_enter_openat(AtFlags::AT_FDCWD.bits(), path, o_flags, mode);
     let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?
         .into_string()
         .map_err(|_| SystemError::EINVAL)?;
@@ -37,3 +39,31 @@ pub(super) fn do_open(
         follow_symlink,
     );
 }
+
+define_event_trace!(
+    sys_enter_openat,
+    TP_system(syscalls),
+    TP_PROTO(dfd: i32, path:*const u8, o_flags: u32, mode: u32),
+    TP_STRUCT__entry{
+        dfd: i32,
+        path: u64,
+        o_flags: u32,
+        mode: u32,
+    },
+    TP_fast_assign{
+        dfd: dfd,
+        path: path as u64,
+        o_flags: o_flags,
+        mode: mode,
+    },
+    TP_ident(__entry),
+    TP_printk({
+        format!(
+            "dfd: {}, path: {:#x}, o_flags: {:?}, mode: {:?}",
+            __entry.dfd,
+            __entry.path,
+            __entry.o_flags,
+            __entry.mode
+        )
+    })
+);

+ 10 - 2
kernel/src/perf/mod.rs

@@ -1,5 +1,6 @@
 mod bpf;
 mod kprobe;
+mod tracepoint;
 mod util;
 
 use crate::filesystem::epoll::{event_poll::EventPoll, EPollEventType, EPollItem};
@@ -17,7 +18,7 @@ use crate::libs::spinlock::{SpinLock, SpinLockGuard};
 use crate::mm::fault::{PageFaultHandler, PageFaultMessage};
 use crate::mm::VmFaultReason;
 use crate::perf::bpf::BpfPerfEvent;
-use crate::perf::util::{PerfEventIoc, PerfEventOpenFlags, PerfProbeArgs};
+use crate::perf::util::{PerfEventIoc, PerfEventOpenFlags, PerfProbeArgs, PerfProbeConfig};
 use crate::process::ProcessManager;
 use crate::syscall::user_access::UserBufferReader;
 use crate::syscall::Syscall;
@@ -287,7 +288,10 @@ pub fn perf_event_open(
         }
         perf_type_id::PERF_TYPE_SOFTWARE => {
             // For bpf prog output
-            assert_eq!(args.config, perf_sw_ids::PERF_COUNT_SW_BPF_OUTPUT);
+            assert_eq!(
+                args.config,
+                PerfProbeConfig::PerfSwIds(perf_sw_ids::PERF_COUNT_SW_BPF_OUTPUT)
+            );
             assert_eq!(
                 args.sample_type,
                 Some(perf_event_sample_format::PERF_SAMPLE_RAW)
@@ -295,6 +299,10 @@ pub fn perf_event_open(
             let bpf_event = bpf::perf_event_open_bpf(args);
             Box::new(bpf_event)
         }
+        perf_type_id::PERF_TYPE_TRACEPOINT => {
+            let tracepoint_event = tracepoint::perf_event_open_tracepoint(args)?;
+            Box::new(tracepoint_event)
+        }
         _ => {
             unimplemented!("perf_event_process: unknown type: {:?}", args);
         }

+ 178 - 0
kernel/src/perf/tracepoint.rs

@@ -0,0 +1,178 @@
+use super::Result;
+use crate::bpf::helper::BPF_HELPER_FUN_SET;
+use crate::bpf::prog::BpfProg;
+use crate::filesystem::page_cache::PageCache;
+use crate::libs::casting::DowncastArc;
+use crate::libs::spinlock::SpinLock;
+use crate::perf::util::PerfProbeConfig;
+use crate::tracepoint::{TracePoint, TracePointCallBackFunc};
+use crate::{
+    filesystem::vfs::{file::File, FilePrivateData, FileSystem, IndexNode},
+    libs::spinlock::SpinLockGuard,
+    perf::{util::PerfProbeArgs, PerfEventOps},
+};
+use alloc::boxed::Box;
+use alloc::sync::Arc;
+use alloc::{string::String, vec::Vec};
+use core::any::Any;
+use core::sync::atomic::AtomicUsize;
+use rbpf::EbpfVmRawOwned;
+use system_error::SystemError;
+
+#[derive(Debug)]
+pub struct TracepointPerfEvent {
+    _args: PerfProbeArgs,
+    tp: &'static TracePoint,
+    ebpf_list: SpinLock<Vec<usize>>,
+}
+
+impl TracepointPerfEvent {
+    pub fn new(args: PerfProbeArgs, tp: &'static TracePoint) -> TracepointPerfEvent {
+        TracepointPerfEvent {
+            _args: args,
+            tp,
+            ebpf_list: SpinLock::new(Vec::new()),
+        }
+    }
+}
+
+impl IndexNode for TracepointPerfEvent {
+    fn read_at(
+        &self,
+        _offset: usize,
+        _len: usize,
+        _buf: &mut [u8],
+        _data: SpinLockGuard<FilePrivateData>,
+    ) -> Result<usize> {
+        panic!("read_at not implemented for TracepointPerfEvent");
+    }
+
+    fn write_at(
+        &self,
+        _offset: usize,
+        _len: usize,
+        _buf: &[u8],
+        _data: SpinLockGuard<FilePrivateData>,
+    ) -> Result<usize> {
+        panic!("write_at not implemented for TracepointPerfEvent");
+    }
+
+    fn fs(&self) -> Arc<dyn FileSystem> {
+        panic!("fs not implemented for TracepointPerfEvent");
+    }
+
+    fn as_any_ref(&self) -> &dyn Any {
+        self
+    }
+
+    fn list(&self) -> Result<Vec<String>> {
+        Err(SystemError::ENOSYS)
+    }
+
+    fn page_cache(&self) -> Option<Arc<PageCache>> {
+        None
+    }
+}
+
+pub struct TracePointPerfCallBack {
+    _bpf_prog_file: Arc<BpfProg>,
+    vm: EbpfVmRawOwned,
+}
+
+impl TracePointPerfCallBack {
+    fn new(bpf_prog_file: Arc<BpfProg>, vm: EbpfVmRawOwned) -> Self {
+        Self {
+            _bpf_prog_file: bpf_prog_file,
+            vm,
+        }
+    }
+}
+
+impl TracePointCallBackFunc for TracePointPerfCallBack {
+    fn call(&self, entry: &[u8]) {
+        // ebpf needs a mutable slice
+        let entry =
+            unsafe { core::slice::from_raw_parts_mut(entry.as_ptr() as *mut u8, entry.len()) };
+        let res = self.vm.execute_program(entry);
+        if res.is_err() {
+            log::error!("tracepoint callback error: {:?}", res);
+        }
+    }
+}
+
+impl PerfEventOps for TracepointPerfEvent {
+    fn set_bpf_prog(&self, bpf_prog: Arc<File>) -> Result<()> {
+        static CALLBACK_ID: AtomicUsize = AtomicUsize::new(0);
+
+        let file = bpf_prog
+            .inode()
+            .downcast_arc::<BpfProg>()
+            .ok_or(SystemError::EINVAL)?;
+        let prog_slice = file.insns();
+        let mut vm = EbpfVmRawOwned::new(Some(prog_slice.to_vec())).map_err(|e| {
+            log::error!("create ebpf vm failed: {:?}", e);
+            SystemError::EINVAL
+        })?;
+        vm.register_helper_set(BPF_HELPER_FUN_SET.get())
+            .map_err(|_| SystemError::EINVAL)?;
+
+        // create a callback to execute the ebpf prog
+        let callback = Box::new(TracePointPerfCallBack::new(file, vm));
+        let id = CALLBACK_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
+        self.tp.register_raw_callback(id, callback);
+
+        log::info!(
+            "Registered BPF program for tracepoint: {}:{} with ID: {}",
+            self.tp.system(),
+            self.tp.name(),
+            id
+        );
+        // Store the ID in the ebpf_list for later cleanup
+        self.ebpf_list.lock().push(id);
+        Ok(())
+    }
+
+    fn enable(&self) -> Result<()> {
+        log::info!(
+            "Enabling tracepoint event: {}:{}",
+            self.tp.system(),
+            self.tp.name()
+        );
+        self.tp.enable();
+        Ok(())
+    }
+
+    fn disable(&self) -> Result<()> {
+        self.tp.disable();
+        Ok(())
+    }
+
+    fn readable(&self) -> bool {
+        true
+    }
+}
+
+impl Drop for TracepointPerfEvent {
+    fn drop(&mut self) {
+        // Unregister all callbacks associated with this tracepoint event
+        let mut ebpf_list = self.ebpf_list.lock();
+        for id in ebpf_list.iter() {
+            self.tp.unregister_raw_callback(*id);
+        }
+        ebpf_list.clear();
+    }
+}
+
+/// Creates a new `TracepointPerfEvent` for the given tracepoint ID.
+pub fn perf_event_open_tracepoint(args: PerfProbeArgs) -> Result<TracepointPerfEvent> {
+    let tp_id = match args.config {
+        PerfProbeConfig::Raw(tp_id) => tp_id as u32,
+        _ => {
+            panic!("Invalid PerfProbeConfig for TracepointPerfEvent");
+        }
+    };
+    let tp_manager = crate::debug::tracing::tracing_events_manager();
+    let tp_map = tp_manager.tracepoint_map();
+    let tp = tp_map.get(&tp_id).ok_or(SystemError::ENOENT)?;
+    Ok(TracepointPerfEvent::new(args, tp))
+}

+ 14 - 2
kernel/src/perf/util.rs

@@ -33,7 +33,7 @@ pub enum PerfEventIoc {
 #[allow(unused)]
 /// `perf_event_open` syscall arguments.
 pub struct PerfProbeArgs {
-    pub config: perf_sw_ids,
+    pub config: PerfProbeConfig,
     pub name: String,
     pub offset: u64,
     pub size: u32,
@@ -45,6 +45,12 @@ pub struct PerfProbeArgs {
     pub sample_type: Option<perf_event_sample_format>,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PerfProbeConfig {
+    PerfSwIds(perf_sw_ids),
+    Raw(u64),
+}
+
 impl PerfProbeArgs {
     pub fn try_from(
         attr: &perf_event_attr,
@@ -54,7 +60,13 @@ impl PerfProbeArgs {
         flags: u32,
     ) -> Result<Self, SystemError> {
         let ty = perf_type_id::from_u32(attr.type_).ok_or(SystemError::EINVAL)?;
-        let config = perf_sw_ids::from_u32(attr.config as u32).ok_or(SystemError::EINVAL)?;
+        let config = match ty {
+            perf_type_id::PERF_TYPE_TRACEPOINT => PerfProbeConfig::Raw(attr.config),
+            _ => {
+                let sw_id = perf_sw_ids::from_u32(attr.config as u32).ok_or(SystemError::EINVAL)?;
+                PerfProbeConfig::PerfSwIds(sw_id)
+            }
+        };
         let name = if ty == perf_type_id::PERF_TYPE_MAX {
             let name_ptr = unsafe { attr.__bindgen_anon_3.config1 } as *const u8;
             let name = check_and_clone_cstr(name_ptr, None)?;

+ 12 - 4
kernel/src/tracepoint/basic_macro.rs

@@ -93,12 +93,13 @@ macro_rules! define_event_trace{
             };
 
             #[allow(unused,non_snake_case)]
+            #[allow(clippy::redundant_field_names)]
             pub fn [<trace_default_ $name>](_data:&mut (dyn core::any::Any+Send+Sync), $($arg:$arg_type),* ){
-                #[repr(C)]
+                #[repr(C, packed)]
                 struct Entry {
                     $($entry: $entry_type,)*
                 }
-                #[repr(C)]
+                #[repr(C, packed)]
                 struct FullEntry {
                     common: $crate::tracepoint::TraceEntry,
                     entry: Entry,
@@ -129,18 +130,25 @@ macro_rules! define_event_trace{
                         core::mem::size_of::<FullEntry>(),
                     )
                 };
+
+                let func = |f:&alloc::boxed::Box<dyn $crate::tracepoint::TracePointCallBackFunc>|{
+                    f.call(event_buf);
+                };
+
+                [<__ $name>].raw_callback_list(&func);
+
                 $crate::debug::tracing::trace_cmdline_push(pid as u32);
                 $crate::debug::tracing::trace_pipe_push_raw_record(event_buf);
             }
 
             #[allow(unused,non_snake_case)]
-            pub fn [<trace_fmt_ $name>](buf_ptr: *const u8) -> alloc::string::String {
+            pub fn [<trace_fmt_ $name>](buf: &[u8]) -> alloc::string::String {
                 #[repr(C)]
                 struct Entry {
                     $($entry: $entry_type,)*
                 }
                 let $tp_ident = unsafe {
-                    &*(buf_ptr as *const Entry)
+                    &*(buf.as_ptr() as *const Entry)
                 };
                 let fmt = format!("{}", $fmt_expr);
                 fmt

+ 5 - 2
kernel/src/tracepoint/mod.rs

@@ -15,10 +15,13 @@ use core::{
     ops::{Deref, DerefMut},
     sync::atomic::AtomicUsize,
 };
-pub use point::{CommonTracePointMeta, TraceEntry, TracePoint, TracePointFunc};
+pub use point::{
+    CommonTracePointMeta, TraceEntry, TracePoint, TracePointCallBackFunc, TracePointFunc,
+};
 use system_error::SystemError;
 pub use trace_pipe::{
-    TraceCmdLineCache, TraceEntryParser, TracePipeOps, TracePipeRaw, TracePipeSnapshot,
+    TraceCmdLineCache, TraceCmdLineCacheSnapshot, TraceEntryParser, TracePipeOps, TracePipeRaw,
+    TracePipeSnapshot,
 };
 
 use crate::libs::spinlock::{SpinLock, SpinLockGuard};

+ 44 - 21
kernel/src/tracepoint/point.rs

@@ -1,10 +1,10 @@
 use crate::libs::spinlock::SpinLock;
 use alloc::{boxed::Box, collections::BTreeMap, format, string::String};
-use core::{any::Any, sync::atomic::AtomicU32};
+use core::{any::Any, fmt::Debug, sync::atomic::AtomicU32};
 use static_keys::StaticFalseKey;
 
 #[derive(Debug)]
-#[repr(C)]
+#[repr(C, packed)]
 pub struct TraceEntry {
     pub type_: u16,
     pub flags: u8,
@@ -38,16 +38,13 @@ pub struct TracePoint {
     system: &'static str,
     key: &'static StaticFalseKey,
     id: AtomicU32,
-    inner: SpinLock<TracePointInner>,
-    trace_entry_fmt_func: fn(*const u8) -> String,
+    callback: SpinLock<BTreeMap<usize, TracePointFunc>>,
+    raw_callback: SpinLock<BTreeMap<usize, Box<dyn TracePointCallBackFunc>>>,
+    trace_entry_fmt_func: fn(&[u8]) -> String,
     trace_print_func: fn() -> String,
     flags: u8,
 }
 
-struct TracePointInner {
-    callback: BTreeMap<usize, TracePointFunc>,
-}
-
 impl core::fmt::Debug for TracePoint {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         f.debug_struct("TracePoint")
@@ -72,12 +69,16 @@ pub struct TracePointFunc {
     pub data: Box<dyn Any + Send + Sync>,
 }
 
+pub trait TracePointCallBackFunc: Send + Sync {
+    fn call(&self, entry: &[u8]);
+}
+
 impl TracePoint {
     pub const fn new(
         key: &'static StaticFalseKey,
         name: &'static str,
         system: &'static str,
-        fmt_func: fn(*const u8) -> String,
+        fmt_func: fn(&[u8]) -> String,
         trace_print_func: fn() -> String,
     ) -> Self {
         Self {
@@ -88,9 +89,8 @@ impl TracePoint {
             flags: 0,
             trace_entry_fmt_func: fmt_func,
             trace_print_func,
-            inner: SpinLock::new(TracePointInner {
-                callback: BTreeMap::new(),
-            }),
+            callback: SpinLock::new(BTreeMap::new()),
+            raw_callback: SpinLock::new(BTreeMap::new()),
         }
     }
 
@@ -120,7 +120,7 @@ impl TracePoint {
     }
 
     /// Returns the format function for the tracepoint.
-    pub(crate) fn fmt_func(&self) -> fn(*const u8) -> String {
+    pub(crate) fn fmt_func(&self) -> fn(&[u8]) -> String {
         self.trace_entry_fmt_func
     }
 
@@ -137,27 +137,50 @@ impl TracePoint {
     pub fn register(&self, func: fn(), data: Box<dyn Any + Sync + Send>) {
         let trace_point_func = TracePointFunc { func, data };
         let ptr = func as usize;
-        self.inner
-            .lock()
-            .callback
-            .entry(ptr)
-            .or_insert(trace_point_func);
+        self.callback.lock().entry(ptr).or_insert(trace_point_func);
     }
 
     /// Unregister a callback function from the tracepoint
     pub fn unregister(&self, func: fn()) {
         let func_ptr = func as usize;
-        self.inner.lock().callback.remove(&func_ptr);
+        self.callback.lock().remove(&func_ptr);
     }
 
     /// Iterate over all registered callback functions
     pub fn callback_list(&self, f: &dyn Fn(&TracePointFunc)) {
-        let inner = self.inner.lock();
-        for trace_func in inner.callback.values() {
+        let callback = self.callback.lock();
+        for trace_func in callback.values() {
             f(trace_func);
         }
     }
 
+    /// Register a raw callback function to the tracepoint
+    ///
+    /// This function will be called when default tracepoint fmt function is called.
+    pub fn register_raw_callback(
+        &self,
+        callback_id: usize,
+        callback: Box<dyn TracePointCallBackFunc>,
+    ) {
+        self.raw_callback
+            .lock()
+            .entry(callback_id)
+            .or_insert(callback);
+    }
+
+    /// Unregister a raw callback function from the tracepoint
+    pub fn unregister_raw_callback(&self, callback_id: usize) {
+        self.raw_callback.lock().remove(&callback_id);
+    }
+
+    /// Iterate over all registered raw callback functions
+    pub fn raw_callback_list(&self, f: &dyn Fn(&Box<dyn TracePointCallBackFunc>)) {
+        let raw_callback = self.raw_callback.lock();
+        for callback in raw_callback.values() {
+            f(callback);
+        }
+    }
+
     /// Enable the tracepoint
     pub fn enable(&self) {
         unsafe {

+ 38 - 8
kernel/src/tracepoint/trace_pipe.rs

@@ -29,6 +29,7 @@ impl TracePipeRaw {
     /// Set the maximum number of records to keep in the trace pipe buffer.
     ///
     /// If the current number of records exceeds this limit, the oldest records will be removed.
+    #[allow(unused)]
     pub fn set_max_record(&mut self, max_record: usize) {
         self.max_record = max_record;
         if self.event_buf.len() > max_record {
@@ -44,11 +45,6 @@ impl TracePipeRaw {
         self.event_buf.push(event);
     }
 
-    /// The number of events currently in the trace pipe buffer.
-    pub fn event_count(&self) -> usize {
-        self.event_buf.len()
-    }
-
     /// Clear the trace pipe buffer.
     pub fn clear(&mut self) {
         self.event_buf.clear();
@@ -180,6 +176,38 @@ impl TraceCmdLineCache {
             self.cmdline.truncate(max_len); // Keep only the latest records
         }
     }
+
+    /// Get the maximum number of records in the cache.
+    pub fn max_record(&self) -> usize {
+        self.max_record
+    }
+
+    /// Create a snapshot of the current state of the command line cache.
+    pub fn snapshot(&self) -> TraceCmdLineCacheSnapshot {
+        TraceCmdLineCacheSnapshot::new(self.cmdline.clone())
+    }
+}
+
+#[derive(Debug)]
+pub struct TraceCmdLineCacheSnapshot(Vec<(u32, [u8; 16])>);
+impl TraceCmdLineCacheSnapshot {
+    pub fn new(cmdline: Vec<(u32, [u8; 16])>) -> Self {
+        Self(cmdline)
+    }
+
+    /// Return the first command line entry in the cache.
+    pub fn peek(&self) -> Option<&(u32, [u8; 16])> {
+        self.0.first()
+    }
+
+    /// Remove and return the first command line entry in the cache.
+    pub fn pop(&mut self) -> Option<(u32, [u8; 16])> {
+        if self.0.is_empty() {
+            None
+        } else {
+            Some(self.0.remove(0))
+        }
+    }
 }
 
 pub struct TraceEntryParser;
@@ -196,12 +224,14 @@ impl TraceEntryParser {
         let tracepoint = tracepoint_map.get(&id).expect("TracePoint not found");
         let fmt_func = tracepoint.fmt_func();
         let offset = core::mem::size_of::<TraceEntry>();
-        let str = fmt_func(unsafe { entry.as_ptr().add(offset) });
+        let str = fmt_func(&entry[offset..]);
 
         let time = crate::time::Instant::now().total_micros() * 1000; // Convert to nanoseconds
         let cpu_id = crate::arch::cpu::current_cpu_id().data();
 
-        let pname = cmdline_cache.get(trace_entry.pid as u32).unwrap_or("<...>");
+        // Copy the packed field to a local variable to avoid unaligned reference
+        let pid = trace_entry.pid;
+        let pname = cmdline_cache.get(pid as u32).unwrap_or("<...>");
 
         let secs = time / 1_000_000_000;
         let usec_rem = time % 1_000_000_000 / 1000;
@@ -209,7 +239,7 @@ impl TraceEntryParser {
         format!(
             "{:>16}-{:<7} [{:03}] {} {:5}.{:06}: {}({})\n",
             pname,
-            trace_entry.pid,
+            pid,
             cpu_id,
             trace_entry.trace_print_lat_fmt(),
             secs,

+ 9 - 0
user/apps/test_tracepoint/.gitignore

@@ -0,0 +1,9 @@
+### https://raw.github.com/github/gitignore/master/Rust.gitignore
+
+# Generated by Cargo
+# will have compiled files and executables
+debug/
+target/
+
+# These are backup files generated by rustfmt
+**/*.rs.bk

+ 794 - 0
user/apps/test_tracepoint/Cargo.lock

@@ -0,0 +1,794 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "aya"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d18bc4e506fbb85ab7392ed993a7db4d1a452c71b75a246af4a80ab8c9d2dd50"
+dependencies = [
+ "assert_matches",
+ "aya-obj",
+ "bitflags",
+ "bytes",
+ "libc",
+ "log",
+ "object",
+ "once_cell",
+ "thiserror 1.0.69",
+ "tokio",
+]
+
+[[package]]
+name = "aya-build"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "765c92c523541cbf5e3a94c7a6ff4068a4d9537f98a2eeb136461c0537ded8c1"
+dependencies = [
+ "anyhow",
+ "cargo_metadata",
+]
+
+[[package]]
+name = "aya-ebpf"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8dbaf5409a1a0982e5c9bdc0f499a55fe5ead39fe9c846012053faf0d404f73"
+dependencies = [
+ "aya-ebpf-bindings",
+ "aya-ebpf-cty",
+ "aya-ebpf-macros",
+ "rustversion",
+]
+
+[[package]]
+name = "aya-ebpf-bindings"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "783dc1a82a3d71d83286165381dcc1b1d41643f4b110733d135547527c000a9a"
+dependencies = [
+ "aya-ebpf-cty",
+]
+
+[[package]]
+name = "aya-ebpf-cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cce099aaf3abb89f9a1f8594ffe07fa53738ebc2882fac624d10d9ba31a1b10"
+
+[[package]]
+name = "aya-ebpf-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f47f7b4a75eb5f1d7ba0fb5628d247b1cf20388658899177875dabdda66865"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "aya-log"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b600d806c1d07d3b81ab5f4a2a95fd80f479a0d3f1d68f29064d660865f85f02"
+dependencies = [
+ "aya",
+ "aya-log-common",
+ "bytes",
+ "log",
+ "thiserror 1.0.69",
+ "tokio",
+]
+
+[[package]]
+name = "aya-log-common"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "befef9fe882e63164a2ba0161874e954648a72b0e1c4b361f532d590638c4eec"
+dependencies = [
+ "num_enum",
+]
+
+[[package]]
+name = "aya-log-ebpf"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae348f459df78a79e5cd5e164b6562b927033b97ca3b033605b341a474f44510"
+dependencies = [
+ "aya-ebpf",
+ "aya-log-common",
+ "aya-log-ebpf-macros",
+]
+
+[[package]]
+name = "aya-log-ebpf-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6d8251a75f56077db51892041aa6b77c70ef2723845d7a210979700b2f01bc4"
+dependencies = [
+ "aya-log-common",
+ "aya-log-parser",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "aya-log-parser"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14b102eb5c88c9aa0b49102d3fbcee08ecb0dfa81014f39b373311de7a7032cb"
+dependencies = [
+ "aya-log-common",
+]
+
+[[package]]
+name = "aya-obj"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c51b96c5a8ed8705b40d655273bc4212cbbf38d4e3be2788f36306f154523ec7"
+dependencies = [
+ "bytes",
+ "core-error",
+ "hashbrown",
+ "log",
+ "object",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
+name = "camino"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo-platform"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.12",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "core-error"
+version = "0.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efcdb2972eb64230b4c50646d8498ff73f5128d196a90c7236eec4cbe8619b8f"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "env_filter"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+dependencies = [
+ "env_filter",
+ "log",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "home"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "libc"
+version = "0.2.172"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "mytrace"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "aya",
+ "aya-build",
+ "aya-log",
+ "env_logger",
+ "libc",
+ "log",
+ "mytrace-common",
+ "mytrace-ebpf",
+ "tokio",
+]
+
+[[package]]
+name = "mytrace-common"
+version = "0.1.0"
+dependencies = [
+ "aya",
+]
+
+[[package]]
+name = "mytrace-ebpf"
+version = "0.1.0"
+dependencies = [
+ "aya-ebpf",
+ "aya-log-ebpf",
+ "mytrace-common",
+ "which",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "object"
+version = "0.36.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+dependencies = [
+ "crc32fast",
+ "hashbrown",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "semver"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl 2.0.12",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio"
+version = "1.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
+dependencies = [
+ "backtrace",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "which"
+version = "6.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
+dependencies = [
+ "either",
+ "home",
+ "rustix",
+ "winsafe",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winsafe"
+version = "0.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"

+ 33 - 0
user/apps/test_tracepoint/Cargo.toml

@@ -0,0 +1,33 @@
+[workspace]
+resolver = "2"
+members = [
+    "mytrace",
+    "mytrace-common",
+    "mytrace-ebpf",
+]
+default-members = ["mytrace", "mytrace-common"]
+
+[workspace.package]
+license = "MIT OR Apache-2.0"
+
+[workspace.dependencies]
+aya = { version = "0.13.1", default-features = false }
+aya-build = { version = "0.1.2", default-features = false }
+aya-ebpf = { version = "0.1.1", default-features = false }
+aya-log = { version = "0.2.1", default-features = false }
+aya-log-ebpf = { version = "0.1.1", default-features = false }
+
+anyhow = { version = "1", default-features = false }
+# `std` feature is currently required to build `clap`.
+#
+# See https://github.com/clap-rs/clap/blob/61f5ee5/clap_builder/src/lib.rs#L15.
+clap = { version = "4.5.20", default-features = false, features = ["std"] }
+env_logger = { version = "0.11.5", default-features = false }
+libc = { version = "0.2.159", default-features = false }
+log = { version = "0.4.22", default-features = false }
+tokio = { version = "1.40.0", default-features = false }
+which = { version = "6.0.0", default-features = false }
+
+[profile.release.package.mytrace-ebpf]
+debug = 2
+codegen-units = 1

+ 57 - 0
user/apps/test_tracepoint/Makefile

@@ -0,0 +1,57 @@
+TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu"
+RUSTFLAGS+=""
+
+ifdef DADK_CURRENT_BUILD_DIR
+# 如果是在dadk中编译,那么安装到dadk的安装目录中
+	INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
+else
+# 如果是在本地编译,那么安装到当前目录下的install目录中
+	INSTALL_DIR = ./install
+endif
+
+ifeq ($(ARCH), x86_64)
+	export RUST_TARGET=x86_64-unknown-linux-musl
+else ifeq ($(ARCH), riscv64)
+	export RUST_TARGET=riscv64gc-unknown-linux-gnu
+else 
+# 默认为x86_86,用于本地编译
+	export RUST_TARGET=x86_64-unknown-linux-musl
+endif
+
+run:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
+
+build:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
+
+clean:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
+
+test:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
+
+doc:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
+
+fmt:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
+
+fmt-check:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
+
+run-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
+
+build-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
+
+clean-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
+
+test-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
+
+
+.PHONY: install
+install:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path ./mytrace --no-track --root $(INSTALL_DIR) --force

+ 57 - 0
user/apps/test_tracepoint/README.md

@@ -0,0 +1,57 @@
+# mytrace
+
+## Prerequisites
+
+1. stable rust toolchains: `rustup toolchain install stable`
+1. nightly rust toolchains: `rustup toolchain install nightly --component rust-src`
+1. (if cross-compiling) rustup target: `rustup target add ${ARCH}-unknown-linux-musl`
+1. (if cross-compiling) LLVM: (e.g.) `brew install llvm` (on macOS)
+1. (if cross-compiling) C toolchain: (e.g.) [`brew install filosottile/musl-cross/musl-cross`](https://github.com/FiloSottile/homebrew-musl-cross) (on macOS)
+1. bpf-linker: `cargo install bpf-linker` (`--no-default-features` on macOS)
+
+## Build & Run
+
+Use `cargo build`, `cargo check`, etc. as normal. Run your program with:
+
+```shell
+cargo run --release --config 'target."cfg(all())".runner="sudo -E"'
+```
+
+Cargo build scripts are used to automatically build the eBPF correctly and include it in the
+program.
+
+## Cross-compiling on macOS
+
+Cross compilation should work on both Intel and Apple Silicon Macs.
+
+```shell
+CC=${ARCH}-linux-musl-gcc cargo build --package mytrace --release \
+  --target=${ARCH}-unknown-linux-musl \
+  --config=target.${ARCH}-unknown-linux-musl.linker=\"${ARCH}-linux-musl-gcc\"
+```
+The cross-compiled program `target/${ARCH}-unknown-linux-musl/release/mytrace` can be
+copied to a Linux server or VM and run there.
+
+## License
+
+With the exception of eBPF code, mytrace is distributed under the terms
+of either the [MIT license] or the [Apache License] (version 2.0), at your
+option.
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+
+### eBPF
+
+All eBPF code is distributed under either the terms of the
+[GNU General Public License, Version 2] or the [MIT license], at your
+option.
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this project by you, as defined in the GPL-2 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
+[Apache license]: LICENSE-APACHE
+[MIT license]: LICENSE-MIT
+[GNU General Public License, Version 2]: LICENSE-GPL2

+ 16 - 0
user/apps/test_tracepoint/mytrace-common/Cargo.toml

@@ -0,0 +1,16 @@
+[package]
+name = "mytrace-common"
+version = "0.1.0"
+edition = "2021"
+
+license.workspace = true
+
+[features]
+default = []
+user = ["aya"]
+
+[dependencies]
+aya = { workspace = true, optional = true }
+
+[lib]
+path = "src/lib.rs"

+ 1 - 0
user/apps/test_tracepoint/mytrace-common/src/lib.rs

@@ -0,0 +1 @@
+#![no_std]

+ 17 - 0
user/apps/test_tracepoint/mytrace-ebpf/Cargo.toml

@@ -0,0 +1,17 @@
+[package]
+name = "mytrace-ebpf"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+mytrace-common = { path = "../mytrace-common" }
+
+aya-ebpf = { workspace = true }
+aya-log-ebpf = { workspace = true }
+
+[build-dependencies]
+which = { workspace = true }
+
+[[bin]]
+name = "mytrace"
+path = "src/main.rs"

+ 17 - 0
user/apps/test_tracepoint/mytrace-ebpf/build.rs

@@ -0,0 +1,17 @@
+use which::which;
+
+/// Building this crate has an undeclared dependency on the `bpf-linker` binary. This would be
+/// better expressed by [artifact-dependencies][bindeps] but issues such as
+/// https://github.com/rust-lang/cargo/issues/12385 make their use impractical for the time being.
+///
+/// This file implements an imperfect solution: it causes cargo to rebuild the crate whenever the
+/// mtime of `which bpf-linker` changes. Note that possibility that a new bpf-linker is added to
+/// $PATH ahead of the one used as the cache key still exists. Solving this in the general case
+/// would require rebuild-if-changed-env=PATH *and* rebuild-if-changed={every-directory-in-PATH}
+/// which would likely mean far too much cache invalidation.
+///
+/// [bindeps]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html?highlight=feature#artifact-dependencies
+fn main() {
+    let bpf_linker = which("bpf-linker").unwrap();
+    println!("cargo:rerun-if-changed={}", bpf_linker.to_str().unwrap());
+}

+ 3 - 0
user/apps/test_tracepoint/mytrace-ebpf/src/lib.rs

@@ -0,0 +1,3 @@
+#![no_std]
+
+// This file exists to enable the library target.

+ 119 - 0
user/apps/test_tracepoint/mytrace-ebpf/src/main.rs

@@ -0,0 +1,119 @@
+#![no_std]
+#![no_main]
+
+use aya_ebpf::{
+    helpers::bpf_probe_read_user_str_bytes,
+    macros::{map, tracepoint},
+    maps::PerCpuArray,
+    programs::TracePointContext,
+};
+use aya_log_ebpf::info;
+
+const MAX_PATH: usize = 4096;
+
+#[repr(C)]
+pub struct Buf {
+    pub buf: [u8; MAX_PATH],
+}
+
+#[map]
+pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0); //
+
+#[tracepoint]
+pub fn mytrace(ctx: TracePointContext) -> u32 {
+    match try_mytrace(ctx) {
+        Ok(ret) => ret,
+        Err(ret) => ret,
+    }
+}
+
+fn try_mytrace(ctx: TracePointContext) -> Result<u32, u32> {
+    // info!(&ctx, "tracepoint sys_enter_openat called");
+    match try_aya_tracepoint_echo_open(&ctx) {
+        Ok(_) => Ok(0),
+        Err(e) => {
+            info!(&ctx, "tracepoint sys_enter_openat called, error: {}", e);
+            Err(e as u32)
+        }
+    }
+}
+
+fn try_aya_tracepoint_echo_open(ctx: &TracePointContext) -> Result<u32, i64> {
+    // Load the pointer to the filename. The offset value can be found running:
+    // sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_open/format
+    const FILENAME_OFFSET: usize = 12;
+
+    if let Ok(filename_addr) = unsafe { ctx.read_at::<u64>(FILENAME_OFFSET) } {
+        // get the map-backed buffer that we're going to use as storage for the filename
+        let buf = unsafe {
+            let ptr = BUF.get_ptr_mut(0).ok_or(0)?; //
+
+            &mut *ptr
+        };
+
+        // read the filename
+        let filename = unsafe {
+            core::str::from_utf8_unchecked(bpf_probe_read_user_str_bytes(
+                filename_addr as *const u8,
+                &mut buf.buf,
+            )?)
+        };
+
+        if filename.len() < MAX_PATH {
+            // log the filename
+            info!(
+                ctx,
+                "Kernel tracepoint sys_enter_openat called,  filename :{}", filename
+            );
+        }
+    }
+    Ok(0)
+}
+
+// This function assumes that the maximum length of a file's path can be of 16 bytes. This is meant
+// to be read as an example, only. Refer to the accompanying `tracepoints.md` for its inclusion in the
+// code.
+fn try_aya_tracepoint_echo_open_small_file_path(ctx: &TracePointContext) -> Result<u32, i64> {
+    const MAX_SMALL_PATH: usize = 16;
+    let mut buf: [u8; MAX_SMALL_PATH] = [0; MAX_SMALL_PATH];
+
+    // Load the pointer to the filename. The offset value can be found running:
+    // sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_open/format
+    const FILENAME_OFFSET: usize = 12;
+    if let Ok(filename_addr) = unsafe { ctx.read_at::<u64>(FILENAME_OFFSET) } {
+        // read the filename
+        let filename = unsafe {
+            // Get an UTF-8 String from an array of bytes
+            core::str::from_utf8_unchecked(
+                // Use the address of the kernel's string  //
+
+                // to copy its contents into the array named 'buf'
+                match bpf_probe_read_user_str_bytes(filename_addr as *const u8, &mut buf) {
+                    Ok(_) => &buf,
+                    Err(e) => {
+                        info!(
+                            ctx,
+                            "tracepoint sys_enter_openat called buf_probe failed {}", e
+                        );
+                        return Err(e);
+                    }
+                },
+            )
+        };
+        info!(
+            ctx,
+            "tracepoint sys_enter_openat called, filename  {}", filename
+        );
+    }
+    Ok(0)
+}
+
+#[cfg(not(test))]
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[link_section = "license"]
+#[no_mangle]
+static LICENSE: [u8; 13] = *b"Dual MIT/GPL\0";

+ 44 - 0
user/apps/test_tracepoint/mytrace/Cargo.toml

@@ -0,0 +1,44 @@
+[package]
+name = "mytrace"
+version = "0.1.0"
+edition = "2021"
+
+license.workspace = true
+
+[dependencies]
+mytrace-common = { path = "../mytrace-common", features = ["user"] }
+
+anyhow = { workspace = true, default-features = true }
+aya = { workspace = true }
+aya-log = { workspace = true }
+env_logger = { workspace = true }
+libc = { workspace = true }
+log = { workspace = true }
+tokio = { workspace = true, features = [
+    "macros",
+    "rt",
+    "rt-multi-thread",
+    "net",
+    "signal",
+    "time"
+] }
+[build-dependencies]
+anyhow = { workspace = true }
+aya-build = { workspace = true }
+# TODO(https://github.com/rust-lang/cargo/issues/12375): this should be an artifact dependency, but
+# it's not possible to tell cargo to use `-Z build-std` to build it. We cargo-in-cargo in the build
+# script to build this, but we want to teach cargo about the dependecy so that cache invalidation
+# works properly.
+#
+# Note also that https://github.com/rust-lang/cargo/issues/10593 occurs when `target = ...` is added
+# to an artifact dependency; it seems possible to work around that by setting `resolver = "1"` in
+# Cargo.toml in the workspace root.
+#
+# Finally note that *any* usage of `artifact = ...` in *any* Cargo.toml in the workspace breaks
+# workflows with stable cargo; stable cargo outright refuses to load manifests that use unstable
+# features.
+mytrace-ebpf = { path = "../mytrace-ebpf" }
+
+[[bin]]
+name = "mytrace"
+path = "src/main.rs"

+ 14 - 0
user/apps/test_tracepoint/mytrace/build.rs

@@ -0,0 +1,14 @@
+use anyhow::{anyhow, Context as _};
+use aya_build::cargo_metadata;
+
+fn main() -> anyhow::Result<()> {
+    let cargo_metadata::Metadata { packages, .. } = cargo_metadata::MetadataCommand::new()
+        .no_deps()
+        .exec()
+        .context("MetadataCommand::exec")?;
+    let ebpf_package = packages
+        .into_iter()
+        .find(|cargo_metadata::Package { name, .. }| name == "mytrace-ebpf")
+        .ok_or_else(|| anyhow!("mytrace-ebpf package not found"))?;
+    aya_build::build_ebpf([ebpf_package])
+}

+ 62 - 0
user/apps/test_tracepoint/mytrace/src/main.rs

@@ -0,0 +1,62 @@
+use aya::programs::TracePoint;
+#[rustfmt::skip]
+use log::{debug, warn};
+use tokio::{signal, task::yield_now, time};
+#[tokio::main(flavor = "current_thread")]
+async fn main() -> anyhow::Result<()> {
+    // env_logger::init();
+
+    env_logger::builder()
+        .filter_level(log::LevelFilter::Info)
+        .format_timestamp(None)
+        .init();
+    // Bump the memlock rlimit. This is needed for older kernels that don't use the
+    // new memcg based accounting, see https://lwn.net/Articles/837122/
+    let rlim = libc::rlimit {
+        rlim_cur: libc::RLIM_INFINITY,
+        rlim_max: libc::RLIM_INFINITY,
+    };
+    let ret = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlim) };
+    if ret != 0 {
+        debug!("remove limit on locked memory failed, ret is: {ret}");
+    }
+
+    // This will include your eBPF object file as raw bytes at compile-time and load it at
+    // runtime. This approach is recommended for most real-world use cases. If you would
+    // like to specify the eBPF program at runtime rather than at compile-time, you can
+    // reach for `Bpf::load_file` instead.
+    let mut ebpf = aya::Ebpf::load(aya::include_bytes_aligned!(concat!(
+        env!("OUT_DIR"),
+        "/mytrace"
+    )))?;
+    if let Err(e) = aya_log::EbpfLogger::init(&mut ebpf) {
+        // This can happen if you remove all log statements from your eBPF program.
+        warn!("failed to initialize eBPF logger: {e}");
+    }
+    let program: &mut TracePoint = ebpf.program_mut("mytrace").unwrap().try_into()?;
+    program.load()?;
+    program.attach("syscalls", "sys_enter_openat")?;
+
+    tokio::spawn(async move {
+        let mut now = time::Instant::now();
+        loop {
+            let new_now = time::Instant::now();
+            let duration = new_now.duration_since(now);
+            if duration.as_secs() >= 2 {
+                // open a file to trigger the tracepoint
+                log::info!("Triggering tracepoint by opening /bin");
+                let bin = std::fs::File::open("/bin").unwrap();
+                drop(bin);
+                now = new_now;
+            }
+            yield_now().await;
+        }
+    });
+
+    let ctrl_c = signal::ctrl_c();
+    println!("Waiting for Ctrl-C...");
+    ctrl_c.await?;
+    println!("Exiting...");
+
+    Ok(())
+}

+ 4 - 0
user/apps/test_tracepoint/rustfmt.toml

@@ -0,0 +1,4 @@
+group_imports = "StdExternalCrate"
+imports_granularity = "Crate"
+reorder_imports = true
+unstable_features = true

+ 37 - 0
user/dadk/config/test_tracepoint.toml

@@ -0,0 +1,37 @@
+# 用户程序名称
+name = "test_ebpf_tp"
+# 版本号
+version = "0.1.0"
+# 用户程序描述信息
+description = "to test eBPF"
+# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果
+build-once = false
+#  (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装
+install-once = false
+# 目标架构
+# 可选值:"x86_64", "aarch64", "riscv64"
+target-arch = ["x86_64"]
+# 任务源
+[task-source]
+# 构建类型
+# 可选值:"build-from_source", "install-from-prebuilt"
+type = "build-from-source"
+# 构建来源
+# "build_from_source" 可选值:"git", "local", "archive"
+# "install_from_prebuilt" 可选值:"local", "archive"
+source = "local"
+# 路径或URL
+source-path = "user/apps/test_tracepoint"
+# 构建相关信息
+[build]
+# (可选)构建命令
+build-command = "make install"
+# 安装相关信息
+[install]
+# (可选)安装到DragonOS的路径
+in-dragonos-path = "/"
+# 清除相关信息
+[clean]
+# (可选)清除命令
+clean-command = "make clean"
+