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.dam...@lse.epita.fr> Reviewed-by: Gabriel Laskar <gabr...@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 ------------------------------------------------------------------------------ What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic patterns at an interface-level. Reveals which users, apps, and protocols are consuming the most bandwidth. Provides multi-vendor support for NetFlow, J-Flow, sFlow and other flows. Make informed decisions using capacity planning reports. https://ad.doubleclick.net/ddm/clk/305295220;132659582;e _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel