[PATCH 2/3] rust_binder: add Rust binder tracepoints

Mohamad Alsadhan posted 3 patches 1 month ago
There is a newer version of this series
[PATCH 2/3] rust_binder: add Rust binder tracepoints
Posted by Mohamad Alsadhan 1 month ago
New tracepoints: `{ioctl,read,write}_done`, `wait_for_work`,
`transaction_received`, `transaction_fd_{send,recv}`,
`{alloc,free}_lru_{start,end}`, `alloc_page_{start,end}`,
`unmap_{user,kernel}_{start,end}`, `command` and `return`.

Link: https://github.com/Rust-for-Linux/linux/issues/1226
Suggested-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Mohamad Alsadhan <mo@sdhn.cc>
---
 drivers/android/binder/rust_binder.h        |  28 +++--
 drivers/android/binder/rust_binder_events.h | 172 ++++++++++++++++++++++++++++
 drivers/android/binder/trace.rs             | 111 +++++++++++++++++-
 3 files changed, 299 insertions(+), 12 deletions(-)

diff --git a/drivers/android/binder/rust_binder.h b/drivers/android/binder/rust_binder.h
index d2284726c..b27283fc9 100644
--- a/drivers/android/binder/rust_binder.h
+++ b/drivers/android/binder/rust_binder.h
@@ -59,44 +59,52 @@ extern const struct rust_binder_layout RUST_BINDER_LAYOUT;
 
 static inline size_t rust_binder_transaction_debug_id(rust_binder_transaction t)
 {
-	return *(size_t *) (t + RUST_BINDER_LAYOUT.t.debug_id);
+	return *(size_t *)(t + RUST_BINDER_LAYOUT.t.debug_id);
 }
 
 static inline u32 rust_binder_transaction_code(rust_binder_transaction t)
 {
-	return *(u32 *) (t + RUST_BINDER_LAYOUT.t.code);
+	return *(u32 *)(t + RUST_BINDER_LAYOUT.t.code);
 }
 
 static inline u32 rust_binder_transaction_flags(rust_binder_transaction t)
 {
-	return *(u32 *) (t + RUST_BINDER_LAYOUT.t.flags);
+	return *(u32 *)(t + RUST_BINDER_LAYOUT.t.flags);
 }
 
 // Nullable!
-static inline rust_binder_node rust_binder_transaction_target_node(rust_binder_transaction t)
+static inline rust_binder_node
+rust_binder_transaction_target_node(rust_binder_transaction t)
 {
-	void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.target_node);
+	void *p = *(void **)(t + RUST_BINDER_LAYOUT.t.target_node);
 
 	if (p)
 		p = p + RUST_BINDER_LAYOUT.n.arc_offset;
 	return p;
 }
 
-static inline rust_binder_process rust_binder_transaction_to_proc(rust_binder_transaction t)
+static inline rust_binder_process
+rust_binder_transaction_to_proc(rust_binder_transaction t)
 {
-	void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.to_proc);
+	void *p = *(void **)(t + RUST_BINDER_LAYOUT.t.to_proc);
 
 	return p + RUST_BINDER_LAYOUT.p.arc_offset;
 }
 
-static inline struct task_struct *rust_binder_process_task(rust_binder_process t)
+static inline struct task_struct *
+rust_binder_process_task(rust_binder_process t)
 {
-	return *(struct task_struct **) (t + RUST_BINDER_LAYOUT.p.task);
+	return *(struct task_struct **)(t + RUST_BINDER_LAYOUT.p.task);
 }
 
 static inline size_t rust_binder_node_debug_id(rust_binder_node t)
 {
-	return *(size_t *) (t + RUST_BINDER_LAYOUT.n.debug_id);
+	return *(size_t *)(t + RUST_BINDER_LAYOUT.n.debug_id);
+}
+
+static inline binder_uintptr_t rust_binder_node_ptr(rust_binder_node t)
+{
+	return *(binder_uintptr_t *)(t + RUST_BINDER_LAYOUT.n.ptr);
 }
 
 #endif
diff --git a/drivers/android/binder/rust_binder_events.h b/drivers/android/binder/rust_binder_events.h
index e3adfb931..6725453f5 100644
--- a/drivers/android/binder/rust_binder_events.h
+++ b/drivers/android/binder/rust_binder_events.h
@@ -30,6 +30,45 @@ TRACE_EVENT(binder_ioctl,
 	TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg)
 );
 
+DECLARE_EVENT_CLASS(binder_function_return_class,
+	TP_PROTO(int ret),
+	TP_ARGS(ret),
+	TP_STRUCT__entry(
+		__field(int, ret)
+	),
+	TP_fast_assign(
+		__entry->ret = ret;
+	),
+	TP_printk("ret=%d", __entry->ret)
+);
+
+#define DEFINE_RBINDER_FUNCTION_RETURN_EVENT(name)	\
+DEFINE_EVENT(binder_function_return_class, name,	\
+	TP_PROTO(int ret), \
+	TP_ARGS(ret))
+
+DEFINE_RBINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done);
+DEFINE_RBINDER_FUNCTION_RETURN_EVENT(binder_read_done);
+DEFINE_RBINDER_FUNCTION_RETURN_EVENT(binder_write_done);
+
+TRACE_EVENT(binder_wait_for_work,
+	TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo),
+	TP_ARGS(proc_work, transaction_stack, thread_todo),
+	TP_STRUCT__entry(
+		__field(bool, proc_work)
+		__field(bool, transaction_stack)
+		__field(bool, thread_todo)
+	),
+	TP_fast_assign(
+		__entry->proc_work = proc_work;
+		__entry->transaction_stack = transaction_stack;
+		__entry->thread_todo = thread_todo;
+	),
+	TP_printk("proc_work=%d transaction_stack=%d thread_todo=%d",
+		  __entry->proc_work, __entry->transaction_stack,
+		  __entry->thread_todo)
+);
+
 TRACE_EVENT(binder_transaction,
 	TP_PROTO(bool reply, rust_binder_transaction t, struct task_struct *thread),
 	TP_ARGS(reply, t, thread),
@@ -60,6 +99,139 @@ TRACE_EVENT(binder_transaction,
 		  __entry->reply, __entry->flags, __entry->code)
 );
 
+TRACE_EVENT(binder_transaction_received,
+	TP_PROTO(rust_binder_transaction t),
+	TP_ARGS(t),
+	TP_STRUCT__entry(
+		__field(int, debug_id)
+	),
+	TP_fast_assign(
+		__entry->debug_id = rust_binder_transaction_debug_id(t);
+	),
+	TP_printk("transaction=%d", __entry->debug_id)
+);
+
+TRACE_EVENT(binder_transaction_fd_send,
+	TP_PROTO(int t_debug_id, int fd, size_t offset),
+	TP_ARGS(t_debug_id, fd, offset),
+	TP_STRUCT__entry(
+		__field(int, debug_id)
+		__field(int, fd)
+		__field(size_t, offset)
+	),
+	TP_fast_assign(
+		__entry->debug_id = t_debug_id;
+		__entry->fd = fd;
+		__entry->offset = offset;
+	),
+	TP_printk("transaction=%d src_fd=%d offset=%zu",
+		  __entry->debug_id, __entry->fd, __entry->offset)
+);
+
+TRACE_EVENT(binder_transaction_fd_recv,
+	TP_PROTO(int t_debug_id, int fd, size_t offset),
+	TP_ARGS(t_debug_id, fd, offset),
+	TP_STRUCT__entry(
+		__field(int, debug_id)
+		__field(int, fd)
+		__field(size_t, offset)
+	),
+	TP_fast_assign(
+		__entry->debug_id = t_debug_id;
+		__entry->fd = fd;
+		__entry->offset = offset;
+	),
+	TP_printk("transaction=%d dest_fd=%d offset=%zu",
+		  __entry->debug_id, __entry->fd, __entry->offset)
+);
+
+DECLARE_EVENT_CLASS(binder_lru_page_class,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index),
+	TP_STRUCT__entry(
+		__field(int, proc)
+		__field(size_t, page_index)
+	),
+	TP_fast_assign(
+		__entry->proc = pid;
+		__entry->page_index = page_index;
+	),
+	TP_printk("proc=%d page_index=%zu",
+		  __entry->proc, __entry->page_index)
+);
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end,
+	TP_PROTO(int pid, size_t page_index),
+	TP_ARGS(pid, page_index));
+
+TRACE_EVENT(binder_command,
+	TP_PROTO(uint32_t cmd),
+	TP_ARGS(cmd),
+	TP_STRUCT__entry(
+		__field(uint32_t, cmd)
+	),
+	TP_fast_assign(
+		__entry->cmd = cmd;
+	),
+	TP_printk("cmd=0x%x %s",
+		  __entry->cmd,
+		  _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_command_strings) ?
+			  binder_command_strings[_IOC_NR(__entry->cmd)] :
+			  "unknown")
+);
+
+TRACE_EVENT(binder_return,
+	TP_PROTO(uint32_t cmd),
+	TP_ARGS(cmd),
+	TP_STRUCT__entry(
+		__field(uint32_t, cmd)
+	),
+	TP_fast_assign(
+		__entry->cmd = cmd;
+	),
+	TP_printk("cmd=0x%x %s",
+		  __entry->cmd,
+		  _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_return_strings) ?
+			  binder_return_strings[_IOC_NR(__entry->cmd)] :
+			  "unknown")
+);
+
 #endif /* _RUST_BINDER_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/android/binder/trace.rs b/drivers/android/binder/trace.rs
index d54b18ab7..e270d08a5 100644
--- a/drivers/android/binder/trace.rs
+++ b/drivers/android/binder/trace.rs
@@ -5,13 +5,33 @@
 use crate::transaction::Transaction;
 
 use kernel::bindings::{rust_binder_transaction, task_struct};
-use kernel::ffi::{c_uint, c_ulong};
-use kernel::task::Task;
+use kernel::error::Result;
+use kernel::ffi::{c_int, c_uint, c_ulong};
+use kernel::task::{Pid, Task};
 use kernel::tracepoint::declare_trace;
 
 declare_trace! {
     unsafe fn binder_ioctl(cmd: c_uint, arg: c_ulong);
+    unsafe fn binder_ioctl_done(ret: c_int);
+    unsafe fn binder_read_done(ret: c_int);
+    unsafe fn binder_write_done(ret: c_int);
+    unsafe fn binder_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool);
     unsafe fn binder_transaction(reply: bool, t: rust_binder_transaction, thread: *mut task_struct);
+    unsafe fn binder_transaction_received(t: rust_binder_transaction);
+    unsafe fn binder_transaction_fd_send(t_debug_id: c_int, fd: c_int, offset: usize);
+    unsafe fn binder_transaction_fd_recv(t_debug_id: c_int, fd: c_int, offset: usize);
+    unsafe fn binder_alloc_lru_start(pid: c_int, page_index: usize);
+    unsafe fn binder_alloc_lru_end(pid: c_int, page_index: usize);
+    unsafe fn binder_free_lru_start(pid: c_int, page_index: usize);
+    unsafe fn binder_free_lru_end(pid: c_int, page_index: usize);
+    unsafe fn binder_alloc_page_start(pid: c_int, page_index: usize);
+    unsafe fn binder_alloc_page_end(pid: c_int, page_index: usize);
+    unsafe fn binder_unmap_user_start(pid: c_int, page_index: usize);
+    unsafe fn binder_unmap_user_end(pid: c_int, page_index: usize);
+    unsafe fn binder_unmap_kernel_start(pid: c_int, page_index: usize);
+    unsafe fn binder_unmap_kernel_end(pid: c_int, page_index: usize);
+    unsafe fn binder_command(cmd: u32);
+    unsafe fn binder_return(ret: u32);
 }
 
 #[inline]
@@ -19,12 +39,44 @@ fn raw_transaction(t: &Transaction) -> rust_binder_transaction {
     t as *const Transaction as rust_binder_transaction
 }
 
+#[inline]
+fn to_errno(ret: Result) -> i32 {
+    match ret {
+        Ok(()) => 0,
+        Err(err) => err.to_errno(),
+    }
+}
+
 #[inline]
 pub(crate) fn trace_ioctl(cmd: u32, arg: usize) {
     // SAFETY: Always safe to call.
     unsafe { binder_ioctl(cmd, arg as c_ulong) }
 }
 
+#[inline]
+pub(crate) fn trace_ioctl_done(ret: Result) {
+    // SAFETY: Always safe to call.
+    unsafe { binder_ioctl_done(to_errno(ret)) }
+}
+#[inline]
+pub(crate) fn trace_read_done(ret: Result) {
+    // SAFETY: Always safe to call.
+    unsafe { binder_read_done(to_errno(ret)) }
+}
+#[inline]
+pub(crate) fn trace_write_done(ret: Result) {
+    // SAFETY: Always safe to call.
+    unsafe { binder_write_done(to_errno(ret)) }
+}
+
+#[inline]
+pub(crate) fn trace_wait_for_work(proc_work: bool, transaction_stack: bool, thread_todo: bool) {
+    // SAFETY: Always safe to call.
+    unsafe { binder_wait_for_work(proc_work, transaction_stack, thread_todo) }
+}
+
+
+
 #[inline]
 pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) {
     let thread = match thread {
@@ -35,3 +87,58 @@ pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Ta
     // valid or null.
     unsafe { binder_transaction(reply, raw_transaction(t), thread) }
 }
+
+#[inline]
+pub(crate) fn trace_transaction_received(t: &Transaction) {
+    // SAFETY: The raw transaction is valid for the duration of this call.
+    unsafe { binder_transaction_received(raw_transaction(t)) }
+}
+
+#[inline]
+pub(crate) fn trace_transaction_fd_send(t_debug_id: usize, fd: u32, offset: usize) {
+    // SAFETY: This function is always safe to call.
+    unsafe { binder_transaction_fd_send(t_debug_id as c_int, fd as c_int, offset) }
+}
+#[inline]
+pub(crate) fn trace_transaction_fd_recv(t_debug_id: usize, fd: u32, offset: usize) {
+    // SAFETY: This function is always safe to call.
+    unsafe { binder_transaction_fd_recv(t_debug_id as c_int, fd as c_int, offset) }
+}
+
+macro_rules! define_wrapper_lru_page_class {
+    ($($name:ident),* $(,)?) => {
+        $(
+            kernel::macros::paste! {
+                #[inline]
+                pub(crate) fn [<trace_ $name>](pid: Pid, page_index: usize) {
+                    // SAFETY: Always safe to call.
+                    unsafe { [<binder_ $name>](pid as c_int, page_index) }
+                }
+            }
+        )*
+    };
+}
+
+define_wrapper_lru_page_class!(
+    alloc_lru_start,
+    alloc_lru_end,
+    free_lru_start,
+    free_lru_end,
+    alloc_page_start,
+    alloc_page_end,
+    unmap_user_start,
+    unmap_user_end,
+    unmap_kernel_start,
+    unmap_kernel_end,
+);
+
+#[inline]
+pub(crate) fn trace_command(cmd: u32) {
+    // SAFETY: This function is always safe to call.
+    unsafe { binder_command(cmd) }
+}
+#[inline]
+pub(crate) fn trace_return(ret: u32) {
+    // SAFETY: This function is always safe to call.
+    unsafe { binder_return(ret) }
+}

-- 
2.52.0
Re: [PATCH 2/3] rust_binder: add Rust binder tracepoints
Posted by kernel test robot 1 month ago
Hi Mohamad,

kernel test robot noticed the following build errors:

[auto build test ERROR on 11439c4635edd669ae435eec308f4ab8a0804808]

url:    https://github.com/intel-lab-lkp/linux/commits/Mohamad-Alsadhan/rust_binder-remove-rust_-prefix-from-tracepoints/20260307-134539
base:   11439c4635edd669ae435eec308f4ab8a0804808
patch link:    https://lore.kernel.org/r/20260307-rust-binder-trace-v1-2-5e03283c6e53%40sdhn.cc
patch subject: [PATCH 2/3] rust_binder: add Rust binder tracepoints
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260307/202603071232.kB8K6o91-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260307/202603071232.kB8K6o91-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603071232.kB8K6o91-lkp@intel.com/

All errors (new ones prefixed by >>):

   PATH=/opt/cross/clang-20/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
   INFO PATH=/opt/cross/rustc-1.88.0-bindgen-0.72.1/cargo/bin:/opt/cross/clang-20/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
   /usr/bin/timeout -k 100 12h /usr/bin/make KCFLAGS=\ -fno-crash-diagnostics\ -Wno-error=return-type\ -Wreturn-type\ -funsigned-char\ -Wundef\ -falign-functions=64 W=1 --keep-going LLVM=1 -j32 -C source O=/kbuild/obj/consumer/x86_64-rhel-9.4-rust ARCH=x86_64 SHELL=/bin/bash rustfmtcheck 
   make: Entering directory '/kbuild/src/consumer'
   make[1]: Entering directory '/kbuild/obj/consumer/x86_64-rhel-9.4-rust'
>> Diff in drivers/android/binder/trace.rs:75:
        unsafe { binder_wait_for_work(proc_work, transaction_stack, thread_todo) }
    }
    
   -
   -
    #[inline]
    pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) {
        let thread = match thread {
>> Diff in drivers/android/binder/trace.rs:75:
        unsafe { binder_wait_for_work(proc_work, transaction_stack, thread_todo) }
    }
    
   -
   -
    #[inline]
    pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) {
        let thread = match thread {
   make[2]: *** [Makefile:1912: rustfmt] Error 123
   make[2]: Target 'rustfmtcheck' not remade because of errors.
   make[1]: Leaving directory '/kbuild/obj/consumer/x86_64-rhel-9.4-rust'
   make[1]: *** [Makefile:248: __sub-make] Error 2
   make[1]: Target 'rustfmtcheck' not remade because of errors.
   make: *** [Makefile:248: __sub-make] Error 2
   make: Target 'rustfmtcheck' not remade because of errors.
   make: Leaving directory '/kbuild/src/consumer'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 2/3] rust_binder: add Rust binder tracepoints
Posted by Miguel Ojeda 1 month ago
On Sat, Mar 7, 2026 at 6:42 AM Mohamad Alsadhan <mo@sdhn.cc> wrote:
>
>  static inline size_t rust_binder_transaction_debug_id(rust_binder_transaction t)
>  {
> -       return *(size_t *) (t + RUST_BINDER_LAYOUT.t.debug_id);
> +       return *(size_t *)(t + RUST_BINDER_LAYOUT.t.debug_id);
>  }

The kernel test robot just reported the Rust side wasn't formatted,
but this seems to be a C formatter at work. Spurious changes?

Thanks!

Cheers,
Miguel