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
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
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
© 2016 - 2026 Red Hat, Inc.