[PATCH v2 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 v2 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        |   5 +
 drivers/android/binder/rust_binder_events.h | 172 ++++++++++++++++++++++++++++
 drivers/android/binder/trace.rs             | 109 +++++++++++++++++-
 3 files changed, 284 insertions(+), 2 deletions(-)

diff --git a/drivers/android/binder/rust_binder.h b/drivers/android/binder/rust_binder.h
index d2284726c..3936b9d0b 100644
--- a/drivers/android/binder/rust_binder.h
+++ b/drivers/android/binder/rust_binder.h
@@ -99,4 +99,9 @@ static inline size_t rust_binder_node_debug_id(rust_binder_node t)
 	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..8bfe7f882 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,42 @@ 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 +85,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