[RFC PATCH v2 11/14] selftests/kcov_dataflow: add eight_args_rust test module

Yunseong Kim <[email protected]>
Newsgroups org.kernel.vger.linux-kbuild,dev.linux.lists.llvm,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kernel.vger.rust-for-linux,org.kernel.vger.workflows,org.kvack.linux-mm
Message-ID <[email protected]>
Rust module exercising 1-8 argument functions plus struct pointer.
Verifies register-passed (1-6) and stack-passed (7-8) arguments.

Test:

  make LLVM=1 CC=clang RUSTC=$RUSTC RUST_LIB_SRC=$RUST_LIB_SRC \
    M=tools/testing/selftests/kcov_dataflow/eight_args_rust modules
  vng --user root --exec \
    "python3 tools/testing/selftests/kcov_dataflow/trigger-view.py \
      eight_args_rust -C 8 --ko \
      tools/testing/selftests/kcov_dataflow/eight_args_rust/eight_args_rust.ko"

Result:

  ksys_write(0x0, 0x1)
    fdget_pos(0x4)
    0xffff891481d2bc00 = fdget_pos()
  0x0 = vfs_write()
  vfs_write(0x0, 0x1, 0x0)
  0x0 = _RNvCs3p16QzTwthP_15eight_args_rust13write_handler [eight_args_rust]()
  _RNvCs3p16QzTwthP_15eight_args_rust13write_handler [eight_args_rust](0x0, 0x1, 0x0)
    rdf_func2 [eight_args_rust](0x11, 0x22)
    0x33 = rdf_func2 [eight_args_rust]()
    rdf_func3 [eight_args_rust](0x11, 0x22, 0x33)
    0x66 = rdf_func3 [eight_args_rust]()
    rdf_func4 [eight_args_rust](0x11, 0x22, 0x33, 0x44)
    0xaa = rdf_func4 [eight_args_rust]()
    rdf_func5 [eight_args_rust](0x11, 0x22, 0x33, 0x44, 0x55)
    0xff = rdf_func5 [eight_args_rust]()
    rdf_func6 [eight_args_rust](0x11, 0x22, 0x33, 0x44, 0x55, 0x66)
    0x165 = rdf_func6 [eight_args_rust]()
    rdf_func7 [eight_args_rust](0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77)
    0x1dc = rdf_func7 [eight_args_rust]()
    rdf_func8 [eight_args_rust](0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88)
    0x264 = rdf_func8 [eight_args_rust]()
    rdf_func_struct [eight_args_rust](0xaaaa)
    0x16665 = rdf_func_struct [eight_args_rust]()
  0x1 = _RNvCs3p16QzTwthP_15eight_args_rust13write_handler [eight_args_rust]()
  0x1 = vfs_write()
  0x1 = ksys_write()
  0x1 = __x64_sys_write()
  0x0 = fpregs_assert_state_consistent()
  0xba5748 = __x64_sys_close()
  file_close_fd(0x4)
  0x0 = file_close_fd()
  0x0 = filp_flush()

Cc: Alexander Potapenko <[email protected]>
Assisted-by: Claude:claude-opus-4-6 [kiro-chat]
Link: https://github.com/yskzalloc/kcov-dataflow/actions
Signed-off-by: Yunseong Kim <[email protected]>
---
 tools/testing/selftests/kcov_dataflow/README.rst   |   7 +
 .../kcov_dataflow/eight_args_rust/Makefile         |   3 +
 .../eight_args_rust/eight_args_rust.rs             | 143 +++++++++++++++++++++
 .../selftests/kcov_dataflow/run_eight_args_rust.sh |  35 +++++
 4 files changed, 188 insertions(+)

diff --git a/tools/testing/selftests/kcov_dataflow/README.rst b/tools/testing/selftests/kcov_dataflow/README.rst
index e93b4e573504..61a41f3bd596 100644
--- a/tools/testing/selftests/kcov_dataflow/README.rst
+++ b/tools/testing/selftests/kcov_dataflow/README.rst
@@ -41,3 +41,10 @@ eight_args_c/
 
         make LLVM=1 CC=clang M=tools/testing/selftests/kcov_dataflow/eight_args_c modules
         python3 trigger-view.py eight_args_c
+
+eight_args_rust/
+    Rust equivalent of eight_args_c. Captures arguments at -O2 where
+    drgn/vmcore cannot. Requires CONFIG_RUST::
+
+        make LLVM=1 CC=clang M=tools/testing/selftests/kcov_dataflow/eight_args_rust modules
+        python3 trigger-view.py eight_args_rust
diff --git a/tools/testing/selftests/kcov_dataflow/eight_args_rust/Makefile b/tools/testing/selftests/kcov_dataflow/eight_args_rust/Makefile
new file mode 100644
index 000000000000..c1e9ea2c5622
--- /dev/null
+++ b/tools/testing/selftests/kcov_dataflow/eight_args_rust/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-m := eight_args_rust.o
+KCOV_DATAFLOW_eight_args_rust.o := y
diff --git a/tools/testing/selftests/kcov_dataflow/eight_args_rust/eight_args_rust.rs b/tools/testing/selftests/kcov_dataflow/eight_args_rust/eight_args_rust.rs
new file mode 100644
index 000000000000..3026265cda97
--- /dev/null
+++ b/tools/testing/selftests/kcov_dataflow/eight_args_rust/eight_args_rust.rs
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+//! Verify kcov_dataflow captures 1-8 argument Rust functions at -O2.
+//!
+//! This is the Rust equivalent of eight_args_c. Since rustc elides DWARF
+//! variable locations at -O2, drgn/vmcore cannot observe these arguments.
+//! kcov_dataflow captures them via the post-compilation pipeline.
+//!
+//! Write to /sys/kernel/debug/kcov_dataflow_test/trigger_rust to invoke.
+
+#![allow(missing_docs)]
+
+use kernel::prelude::*;
+use kernel::c_str;
+
+module! {
+    type: EightArgsRust,
+    name: "eight_args_rust",
+    authors: ["kcov-dataflow"],
+    description: "1-8 arg Rust verification for kcov_dataflow",
+    license: "GPL",
+}
+
+#[repr(C)]
+pub struct Pair {
+    pub x: u32,
+    pub y: u32,
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func1(a1: u64) -> u64 { a1 }
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func2(a1: u64, a2: u64) -> u64 { a1 + a2 }
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func3(a1: u64, a2: u64, a3: u64) -> u64 {
+    a1 + a2 + a3
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func4(a1: u64, a2: u64, a3: u64, a4: u64) -> u64 {
+    a1 + a2 + a3 + a4
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func5(a1: u64, a2: u64, a3: u64, a4: u64, a5: u64) -> u64 {
+    a1 + a2 + a3 + a4 + a5
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func6(
+    a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64,
+) -> u64 {
+    a1 + a2 + a3 + a4 + a5 + a6
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func7(
+    a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64, a7: u64,
+) -> u64 {
+    a1 + a2 + a3 + a4 + a5 + a6 + a7
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func8(
+    a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64, a7: u64, a8: u64,
+) -> u64 {
+    a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rdf_func_struct(p: *const Pair) -> u64 {
+    unsafe { (*p).x as u64 + (*p).y as u64 }
+}
+
+unsafe extern "C" fn write_handler(
+    _file: *mut kernel::bindings::file,
+    _buf: *const core::ffi::c_char,
+    count: usize,
+    _ppos: *mut kernel::bindings::loff_t,
+) -> kernel::ffi::c_long {
+    let p = Pair { x: 0xAAAA, y: 0xBBBB };
+
+    let mut sum: u64 = 0;
+    sum = sum.wrapping_add(rdf_func1(0x11));
+    sum = sum.wrapping_add(rdf_func2(0x11, 0x22));
+    sum = sum.wrapping_add(rdf_func3(0x11, 0x22, 0x33));
+    sum = sum.wrapping_add(rdf_func4(0x11, 0x22, 0x33, 0x44));
+    sum = sum.wrapping_add(rdf_func5(0x11, 0x22, 0x33, 0x44, 0x55));
+    sum = sum.wrapping_add(rdf_func6(0x11, 0x22, 0x33, 0x44, 0x55, 0x66));
+    sum = sum.wrapping_add(rdf_func7(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77));
+    sum = sum.wrapping_add(rdf_func8(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88));
+    sum = sum.wrapping_add(rdf_func_struct(&p as *const Pair));
+    core::hint::black_box(sum);
+
+    count as kernel::ffi::c_long
+}
+
+#[repr(transparent)]
+struct SyncFops(kernel::bindings::file_operations);
+unsafe impl Sync for SyncFops {}
+
+static FOPS: SyncFops = SyncFops(kernel::bindings::file_operations {
+    write: Some(unsafe { core::mem::transmute(write_handler as *const ()) }),
+    ..unsafe { core::mem::zeroed() }
+});
+
+struct EightArgsRust {
+    d: *mut kernel::bindings::dentry,
+}
+
+impl kernel::Module for EightArgsRust {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        let d = unsafe {
+            kernel::bindings::debugfs_create_file_unsafe(
+                c_str!("trigger_rust").as_char_ptr(),
+                0o222,
+                core::ptr::null_mut(),
+                core::ptr::null_mut(),
+                &FOPS.0,
+            )
+        };
+        Ok(Self { d })
+    }
+}
+
+impl Drop for EightArgsRust {
+    fn drop(&mut self) {
+        unsafe { kernel::bindings::debugfs_remove(self.d) };
+    }
+}
+
+unsafe impl Send for EightArgsRust {}
+unsafe impl Sync for EightArgsRust {}
diff --git a/tools/testing/selftests/kcov_dataflow/run_eight_args_rust.sh b/tools/testing/selftests/kcov_dataflow/run_eight_args_rust.sh
new file mode 100755
index 000000000000..c5f11866e19d
--- /dev/null
+++ b/tools/testing/selftests/kcov_dataflow/run_eight_args_rust.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Test eight_args_rust module capture via kcov_dataflow
+DIR="$(dirname "$0")"
+KO="$DIR/eight_args_rust/eight_args_rust.ko"
+
+if [ ! -f "$KO" ]; then
+	echo "SKIP: $KO not found"
+	echo "Build: make LLVM=1 CC=clang RUSTC=\$RUSTC M=...eight_args_rust modules""
+	exit 4  # kselftest SKIP
+fi
+
+if [ ! -e /sys/kernel/debug/kcov_dataflow ]; then
+	echo "SKIP: kcov_dataflow not available"
+	exit 4
+fi
+
+OUTPUT=$(python3 "$DIR/trigger-view.py" eight_args_rust --ko "$KO" --raw 2>&1)
+RC=$?
+
+if [ $RC -ne 0 ]; then
+	echo "FAIL: trigger-and-view exited with $RC"
+	echo "$OUTPUT"
+	exit 1
+fi
+
+RECORDS=$(echo "$OUTPUT" | grep -c "^\[ENTRY\]\|^\[RET")
+if [ "$RECORDS" -gt 0 ]; then
+	echo "PASS: captured $RECORDS records from eight_args_rust"
+	exit 0
+else
+	echo "FAIL: no records captured"
+	echo "$OUTPUT"
+	exit 1
+fi

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.