refs: List<NodeRefInfo, { NodeRefInfo::LIST_NODE }>,
}
+use kernel::bindings::rb_node_layout;
+use mem::offset_of;
+pub(crate) const NODE_LAYOUT: rb_node_layout = rb_node_layout {
+ arc_offset: Arc::<Node>::DATA_OFFSET + offset_of!(DTRWrap<Node>, wrapped),
+ debug_id: offset_of!(Node, debug_id),
+ ptr: offset_of!(Node, ptr),
+};
+
#[pin_data]
pub(crate) struct Node {
pub(crate) debug_id: usize,
}
}
+use core::mem::offset_of;
+use kernel::bindings::rb_process_layout;
+pub(crate) const PROCESS_LAYOUT: rb_process_layout = rb_process_layout {
+ arc_offset: Arc::<Process>::DATA_OFFSET,
+ task: offset_of!(Process, task),
+};
+
/// A process using binder.
///
/// Strictly speaking, there can be multiple of these per process. There is one for each binder fd
struct dentry *rust_binderfs_create_proc_file(struct inode *nodp, int pid);
void rust_binderfs_remove_file(struct dentry *dentry);
+/*
+ * The internal data types in the Rust Binder driver are opaque to C, so we use
+ * void pointer typedefs for these types.
+ */
+
+typedef void *rust_binder_transaction;
+typedef void *rust_binder_process;
+typedef void *rust_binder_node;
+
+struct rb_process_layout {
+ size_t arc_offset;
+ size_t task;
+};
+
+struct rb_transaction_layout {
+ size_t debug_id;
+ size_t code;
+ size_t flags;
+ size_t from_thread;
+ size_t to_proc;
+ size_t target_node;
+};
+
+struct rb_node_layout {
+ size_t arc_offset;
+ size_t debug_id;
+ size_t ptr;
+};
+
+struct rust_binder_layout {
+ struct rb_transaction_layout t;
+ struct rb_process_layout p;
+ struct rb_node_layout n;
+};
+
+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);
+}
+
+static inline u32 rust_binder_transaction_code(rust_binder_transaction t)
+{
+ 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);
+}
+
+// Nullable!
+static inline rust_binder_node rust_binder_transaction_target_node(rust_binder_transaction t)
+{
+ void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.target_node);
+
+ if (p)
+ p = p + RUST_BINDER_LAYOUT.n.arc_offset;
+ return NULL;
+}
+
+static inline rust_binder_process rust_binder_transaction_to_proc(rust_binder_transaction t)
+{
+ 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)
+{
+ 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);
+}
+
#endif
TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg)
);
+TRACE_EVENT(rust_binder_transaction,
+ TP_PROTO(bool reply, rust_binder_transaction t, struct task_struct *thread),
+ TP_ARGS(reply, t, thread),
+ TP_STRUCT__entry(
+ __field(int, debug_id)
+ __field(int, target_node)
+ __field(int, to_proc)
+ __field(int, to_thread)
+ __field(int, reply)
+ __field(unsigned int, code)
+ __field(unsigned int, flags)
+ ),
+ TP_fast_assign(
+ rust_binder_process to = rust_binder_transaction_to_proc(t);
+ rust_binder_node target_node = rust_binder_transaction_target_node(t);
+
+ __entry->debug_id = rust_binder_transaction_debug_id(t);
+ __entry->target_node = target_node ? rust_binder_node_debug_id(target_node) : 0;
+ __entry->to_proc = rust_binder_process_task(to)->pid;
+ __entry->to_thread = thread ? thread->pid : 0;
+ __entry->reply = reply;
+ __entry->code = rust_binder_transaction_code(t);
+ __entry->flags = rust_binder_transaction_flags(t);
+ ),
+ TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x",
+ __entry->debug_id, __entry->target_node,
+ __entry->to_proc, __entry->to_thread,
+ __entry->reply, __entry->flags, __entry->code)
+);
+
#endif /* _RUST_BINDER_TRACE_H */
/* This part must be outside protection */
license: "GPL",
}
+use kernel::bindings::rust_binder_layout;
+#[no_mangle]
+static RUST_BINDER_LAYOUT: rust_binder_layout = rust_binder_layout {
+ t: transaction::TRANSACTION_LAYOUT,
+ p: process::PROCESS_LAYOUT,
+ n: node::NODE_LAYOUT,
+};
+
fn next_debug_id() -> usize {
static NEXT_DEBUG_ID: AtomicUsize = AtomicUsize::new(0);
transaction: &DArc<Transaction>,
) -> bool {
if let Ok(transaction) = &reply {
+ crate::trace::trace_transaction(true, transaction, Some(&self.task));
transaction.set_outstanding(&mut self.process.inner.lock());
}
// Copyright (C) 2025 Google LLC.
+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::tracepoint::declare_trace;
declare_trace! {
unsafe fn rust_binder_ioctl(cmd: c_uint, arg: c_ulong);
+ unsafe fn rust_binder_transaction(reply: bool, t: rust_binder_transaction, thread: *mut task_struct);
+}
+
+#[inline]
+fn raw_transaction(t: &Transaction) -> rust_binder_transaction {
+ t as *const Transaction as rust_binder_transaction
}
#[inline]
// SAFETY: Always safe to call.
unsafe { rust_binder_ioctl(cmd, arg as c_ulong) }
}
+
+#[inline]
+pub(crate) fn trace_transaction(reply: bool, t: &Transaction, thread: Option<&Task>) {
+ let thread = match thread {
+ Some(thread) => thread.as_ptr(),
+ None => core::ptr::null_mut(),
+ };
+ // SAFETY: The raw transaction is valid for the duration of this call. The thread pointer is
+ // valid or null.
+ unsafe { rust_binder_transaction(reply, raw_transaction(t), thread) }
+}
BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead,
};
+use core::mem::offset_of;
+use kernel::bindings::rb_transaction_layout;
+pub(crate) const TRANSACTION_LAYOUT: rb_transaction_layout = rb_transaction_layout {
+ debug_id: offset_of!(Transaction, debug_id),
+ code: offset_of!(Transaction, code),
+ flags: offset_of!(Transaction, flags),
+ from_thread: offset_of!(Transaction, from),
+ to_proc: offset_of!(Transaction, to),
+ target_node: offset_of!(Transaction, target_node),
+};
+
#[pin_data(PinnedDrop)]
pub(crate) struct Transaction {
pub(crate) debug_id: usize,
if oneway {
if let Some(target_node) = self.target_node.clone() {
+ crate::trace::trace_transaction(false, &self, None);
if process_inner.is_frozen.is_frozen() {
process_inner.async_recv = true;
if self.flags & TF_UPDATE_TXN != 0 {
}
let res = if let Some(thread) = self.find_target_thread() {
+ crate::trace::trace_transaction(false, &self, Some(&thread.task));
match thread.push_work(self) {
PushWorkRes::Ok => Ok(()),
PushWorkRes::FailedDead(me) => Err((BinderError::new_dead(), me)),
}
} else {
+ crate::trace::trace_transaction(false, &self, None);
process_inner.push_work(self)
};
drop(process_inner);