[PATCH 1/3] Add decoding for binder ioctls

Antoine Damhet antoine.damhet at lse.epita.fr
Sat May 28 20:40:26 UTC 2016


This patch introduce decoding for binder ioctls including the command
and return protocol from BINDER_WRITE_READ.

* binder.c: New file.
* xlat/binder_driver_commands.in: New file.
* xlat/binder_driver_returns.in: New file.
* Makefile.am (strace_SOURCES): Add binder.c.
* ioctl.c (ioctl_decode): Call binder_ioctl for 'b' ioctl commands.
* defs.h (binder_ioctl): New prototype.
* configure.ac: Check binder header.

Signed-off-by: Antoine Damhet <antoine.damhet at lse.epita.fr>
Reviewed-by: Gabriel Laskar <gabriel at lse.epita.fr>
---
The underlaying structures of BINDER_WRITE_READ are just printed for now.
I tested on aosp 6.0.1_r17 (x86_64) with BinderDemo (in the external
folder). The expected output with "strace -v -e ioctl binder" should be:
ioctl(4, BINDER_VERSION, {protocol_version=8}) = 0
ioctl(4, BINDER_SET_MAX_THREADS, [15])  = 0
ioctl(4, BINDER_WRITE_READ, {write_size=68, write_consumed=0, write_buffer=[[BC_TRANSACTION, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0GNP_\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"]], read_size=256, read_consumed=0} => {write_size=68, write_consumed=68, read_size=256, read_consumed=76, read_buffer=[BR_NOOP, BR_TRANSACTION_COMPLETE, [BR_REPLY, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\350\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0P \f\263j\177\0\0P \f\263j\177\0\0"]]}) = 0
ioctl(4, BINDER_WRITE_READ, {write_size=96, write_consumed=0, write_buffer=[[BC_FREE_BUFFER, "P \f\263j\177\0\0"], [BC_INCREFS, "\0\0\0\0"], [BC_ACQUIRE, "\0\0\0\0"], [BC_TRANSACTION, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0l\0\0\0\0\0\0\0\10\0\0\0\0\0\0\0\240\2606\263j\177\0\0@\0215\263j\177\0\0"]], read_size=256, read_consumed=0} => {write_size=96, write_consumed=96, read_size=256, read_consumed=116, read_buffer=[BR_NOOP, [BR_INCREFS, " \0215\263j\177\0\0(\3014\263j\177\0\0"], [BR_ACQUIRE, " \0215\263j\177\0\0(\3014\263j\177\0\0"], BR_TRANSACTION_COMPLETE, [BR_REPLY, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\350\3\0\0\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0P \f\263j\177\0\0X \f\263j\177\0\0"]]}) = 0
ioctl(4, BINDER_WRITE_READ, {write_size=56, write_consumed=0, write_buffer=[[BC_INCREFS_DONE, " \0215\263j\177\0\0(\3014\263j\177\0\0"], [BC_ACQUIRE_DONE, " \0215\263j\177\0\0(\3014\263j\177\0\0"], [BC_FREE_BUFFER, "P \f\263j\177\0\0"], BC_ENTER_LOOPER], read_size=256, read_consumed=0}
 Makefile.am                    |   1 +
 binder.c                       | 211 +++++++++++++++++++++++++++++++++++++++++
 configure.ac                   |   2 +
 defs.h                         |   1 +
 ioctl.c                        |   4 +
 xlat/binder_driver_commands.in |  21 ++++
 xlat/binder_driver_returns.in  |  22 +++++
 7 files changed, 262 insertions(+)
 create mode 100644 binder.c
 create mode 100644 xlat/binder_driver_commands.in
 create mode 100644 xlat/binder_driver_returns.in

diff --git a/Makefile.am b/Makefile.am
index 052cb21..ba850cc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -78,6 +78,7 @@ strace_SOURCES =	\
 	affinity.c	\
 	aio.c		\
 	alpha.c		\
+	binder.c	\
 	bjm.c		\
 	block.c		\
 	bpf.c		\
diff --git a/binder.c b/binder.c
new file mode 100644
index 0000000..8781374
--- /dev/null
+++ b/binder.c
@@ -0,0 +1,211 @@
+#include "defs.h"
+
+#if defined(HAVE_LINUX_ANDROID_BINDER_H) || defined(__ANDROID__)
+
+#include <linux/ioctl.h>
+
+#if SIZEOF_LONG == 4
+# define BINDER_IPC_32BIT
+#endif
+#ifdef HAVE_LINUX_ANDROID_BINDER_H
+# include <linux/android/binder.h>
+#else
+# include <linux/binder.h>
+#endif
+
+#include "xlat/binder_driver_commands.h"
+#include "xlat/binder_driver_returns.h"
+
+static int
+decode_binder_returns(struct tcb *tcp, struct binder_write_read *wr)
+{
+	if (wr->read_consumed < sizeof(uint32_t)) {
+		tprints("[]");
+		return 0;
+	}
+
+	if (abbrev(tcp)) {
+		tprints("[...]");
+		return 0;
+	}
+
+	char *buffer = malloc(wr->read_consumed);
+	if (!buffer)
+		return 1;
+
+	if (umoven(tcp, wr->read_buffer, wr->read_consumed, buffer)) {
+		free(buffer);
+		return 1;
+	}
+
+	size_t pos = 0;
+	uint32_t type;
+	tprints("[");
+
+	goto print_one_read_buffer;
+	while (pos + sizeof(uint32_t) <= wr->read_consumed) {
+		tprints(", ");
+
+print_one_read_buffer:
+		type = *(uint32_t *)(buffer + pos);
+		if (_IOC_SIZE(type) > 0) {
+			tprints("[");
+			printxval(binder_driver_returns, type, "BR_???");
+			tprints(", ");
+			print_quoted_string(buffer + pos + sizeof(type),
+					_IOC_SIZE(type), 0);
+			tprints("]");
+		} else
+			printxval(binder_driver_returns, type, "BR_???");
+		pos += sizeof(uint32_t) + _IOC_SIZE(type);
+	}
+
+	tprints("]");
+	free(buffer);
+	return 0;
+}
+
+static int
+decode_binder_commands(struct tcb *tcp, struct binder_write_read *wr)
+{
+	if (wr->write_size < sizeof(uint32_t)) {
+		tprints("[]");
+		return 0;
+	}
+
+	if (abbrev(tcp)) {
+		tprints("[...]");
+		return 0;
+	}
+
+	char *buffer = malloc(wr->write_size);
+	if (!buffer)
+		return 1;
+
+	if (umoven(tcp, wr->write_buffer, wr->write_size, buffer)) {
+		free(buffer);
+		return 1;
+	}
+
+	size_t pos = wr->write_consumed;
+	uint32_t type;
+	tprints("[");
+
+	goto print_one_write_buffer;
+	while (pos + sizeof(uint32_t) <= wr->write_size) {
+		tprints(", ");
+
+print_one_write_buffer:
+		type = *(uint32_t *)(buffer + pos);
+		if (_IOC_SIZE(type) > 0) {
+			tprints("[");
+			printxval(binder_driver_commands, type, "BC_???");
+			tprints(", ");
+			print_quoted_string(buffer + pos + sizeof(type),
+					_IOC_SIZE(type), 0);
+			tprints("]");
+		} else
+			printxval(binder_driver_commands, type, "BC_???");
+		pos += sizeof(uint32_t) + _IOC_SIZE(type);
+	}
+
+	tprints("]");
+	free(buffer);
+	return 0;
+}
+
+static int
+decode_binder_write_read(struct tcb *tcp, const long addr)
+{
+	struct binder_write_read wr;
+
+	if (entering(tcp)) {
+		tprints(", ");
+		if (umove_or_printaddr(tcp, addr, &wr))
+			return RVAL_DECODED | 1;
+
+		tprintf("{write_size=%" PRIu64 ", write_consumed=%" PRIu64
+				", write_buffer=",
+				(uint64_t)wr.write_size,
+				(uint64_t)wr.write_consumed);
+		if (decode_binder_commands(tcp, &wr))
+			return RVAL_DECODED | 1;
+
+		tprintf(", read_size=%" PRIu64 ", read_consumed=%" PRIu64 "}",
+				(uint64_t)wr.read_size,
+				(uint64_t)wr.read_consumed);
+		return 0;
+	}
+
+	if (syserror(tcp))
+		return RVAL_DECODED | 1;
+
+	if (umove(tcp, addr, &wr))
+		return RVAL_DECODED | 1;
+
+	tprints(" => ");
+
+	tprintf("{write_size=%" PRIu64 ", write_consumed=%" PRIu64
+			", read_size=%" PRIu64 ", read_consumed=%" PRIu64
+			", read_buffer=",
+			(uint64_t)wr.write_size,
+			(uint64_t)wr.write_consumed,
+			(uint64_t)wr.read_size,
+			(uint64_t)wr.read_consumed);
+	if (decode_binder_returns(tcp, &wr))
+		return RVAL_DECODED | 1;
+
+	tprints("}");
+	return RVAL_DECODED | 1;
+}
+
+int
+decode_binder_version(struct tcb *tcp, long addr)
+{
+	struct binder_version version;
+
+	tprints(", ");
+	if (umove_or_printaddr(tcp, addr, &version))
+		return RVAL_DECODED | 1;
+
+	tprintf("{protocol_version=%" PRId32 "}", version.protocol_version);
+	return RVAL_DECODED | 1;
+}
+
+int
+binder_ioctl(struct tcb *tcp, const unsigned int code, long arg)
+{
+	if (!verbose(tcp))
+		return RVAL_DECODED;
+
+	if (code == BINDER_WRITE_READ)
+		return decode_binder_write_read(tcp, arg);
+
+	if (entering(tcp)) {
+		switch (code) {
+		case BINDER_SET_IDLE_TIMEOUT:
+			tprints(", ");
+			printnum_int64(tcp, arg, "%lld");
+			return RVAL_DECODED | 1;
+		case BINDER_SET_MAX_THREADS:
+			tprints(", ");
+			printnum_int(tcp, arg, "%u");
+			return RVAL_DECODED | 1;
+		case BINDER_SET_IDLE_PRIORITY:
+		case BINDER_SET_CONTEXT_MGR:
+		case BINDER_THREAD_EXIT:
+			tprints(", ");
+			printnum_int(tcp, arg, "%d");
+			return RVAL_DECODED | 1;
+		default:
+			break;
+		}
+	} else {
+		if (code == BINDER_VERSION)
+			return decode_binder_version(tcp, arg);
+	}
+
+	return 0;
+}
+
+#endif /* !(HAVE_LINUX_ANDROID_BINDER_H || __ANDROID__) */
diff --git a/configure.ac b/configure.ac
index 7dfa1d1..535b835 100644
--- a/configure.ac
+++ b/configure.ac
@@ -430,6 +430,8 @@ AC_CHECK_HEADERS([linux/bpf.h], [
 	fi
 ])
 
+AC_CHECK_HEADERS([linux/android/binder.h],,, [#include <sys/types.h>])
+
 AC_CHECK_TYPES([struct statfs], [
 	AC_CHECK_MEMBERS([struct statfs.f_frsize],,, [#include <linux/types.h>
 #include <asm/statfs.h>])
diff --git a/defs.h b/defs.h
index b2a7f4d..92c6e55 100644
--- a/defs.h
+++ b/defs.h
@@ -663,6 +663,7 @@ extern void print_struct_statfs64(struct tcb *tcp, long, unsigned long);
 extern int file_ioctl(struct tcb *, const unsigned int, long);
 extern int fs_x_ioctl(struct tcb *, const unsigned int, long);
 extern int hdio_ioctl(struct tcb *, const unsigned int, long);
+extern int binder_ioctl(struct tcb *, const unsigned int, long);
 extern int loop_ioctl(struct tcb *, const unsigned int, long);
 extern int mtd_ioctl(struct tcb *, const unsigned int, long);
 extern int ptp_ioctl(struct tcb *, const unsigned int, long);
diff --git a/ioctl.c b/ioctl.c
index e4b20d9..54aa9a7 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -282,6 +282,10 @@ ioctl_decode(struct tcb *tcp)
 	case 0x94:
 		return btrfs_ioctl(tcp, code, arg);
 #endif
+#if defined(HAVE_LINUX_ANDROID_BINDER_H) || defined(__ANDROID__)
+	case 'b':
+		return binder_ioctl(tcp, code, arg);
+#endif
 	default:
 		break;
 	}
diff --git a/xlat/binder_driver_commands.in b/xlat/binder_driver_commands.in
new file mode 100644
index 0000000..9652ae3
--- /dev/null
+++ b/xlat/binder_driver_commands.in
@@ -0,0 +1,21 @@
+/*
+ * These values are defined as an enum in linux/android/binder.h and must be
+ * defined here because xlat is unable to fetch them.
+ */
+BC_TRANSACTION _IOW('c', 0, struct binder_transaction_data)
+BC_REPLY _IOW('c', 1, struct binder_transaction_data)
+BC_ACQUIRE_RESULT _IOW('c', 2, __s32)
+BC_FREE_BUFFER _IOW('c', 3, binder_uintptr_t)
+BC_INCREFS _IOW('c', 4, __u32)
+BC_ACQUIRE _IOW('c', 5, __u32)
+BC_RELEASE _IOW('c', 6, __u32)
+BC_DECREFS _IOW('c', 7, __u32)
+BC_INCREFS_DONE _IOW('c', 8, struct binder_ptr_cookie)
+BC_ACQUIRE_DONE _IOW('c', 9, struct binder_ptr_cookie)
+BC_ATTEMPT_ACQUIRE _IOW('c', 10, struct binder_pri_desc)
+BC_REGISTER_LOOPER _IO('c', 11)
+BC_ENTER_LOOPER _IO('c', 12)
+BC_EXIT_LOOPER _IO('c', 13)
+BC_REQUEST_DEATH_NOTIFICATION _IOW('c', 14, struct binder_handle_cookie)
+BC_CLEAR_DEATH_NOTIFICATION _IOW('c', 15, struct binder_handle_cookie)
+BC_DEAD_BINDER_DONE _IOW('c', 16, binder_uintptr_t)
diff --git a/xlat/binder_driver_returns.in b/xlat/binder_driver_returns.in
new file mode 100644
index 0000000..cd06a80
--- /dev/null
+++ b/xlat/binder_driver_returns.in
@@ -0,0 +1,22 @@
+/*
+ * These values are defined as an enum in linux/android/binder.h and must be
+ * defined here because xlat is unable to fetch them.
+ */
+BR_ERROR _IOR('r', 0, __s32)
+BR_OK _IO('r', 1)
+BR_TRANSACTION _IOR('r', 2, struct binder_transaction_data)
+BR_REPLY _IOR('r', 3, struct binder_transaction_data)
+BR_ACQUIRE_RESULT _IOR('r', 4, __s32)
+BR_DEAD_REPLY _IO('r', 5)
+BR_TRANSACTION_COMPLETE _IO('r', 6)
+BR_INCREFS _IOR('r', 7, struct binder_ptr_cookie)
+BR_ACQUIRE _IOR('r', 8, struct binder_ptr_cookie)
+BR_RELEASE _IOR('r', 9, struct binder_ptr_cookie)
+BR_DECREFS _IOR('r', 10, struct binder_ptr_cookie)
+BR_ATTEMPT_ACQUIRE _IOR('r', 11, struct binder_pri_ptr_cookie)
+BR_NOOP _IO('r', 12)
+BR_SPAWN_LOOPER _IO('r', 13)
+BR_FINISHED _IO('r', 14)
+BR_DEAD_BINDER _IOR('r', 15, binder_uintptr_t)
+BR_CLEAR_DEATH_NOTIFICATION_DONE _IOR('r', 16, binder_uintptr_t)
+BR_FAILED_REPLY _IO('r', 17)
-- 
2.8.3





More information about the Strace-devel mailing list