Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5249f488 authored by Arve Hjønnevåg's avatar Arve Hjønnevåg Committed by Greg Kroah-Hartman
Browse files

binder: Use seq_file for debug interface.

parent 3537cdaa
Loading
Loading
Loading
Loading
+201 −374
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/proc_fs.h>
#include <linux/rbtree.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
@@ -48,8 +49,22 @@ static struct binder_node *binder_context_mgr_node;
static uid_t binder_context_mgr_uid = -1;
static int binder_last_id;

static int binder_read_proc_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data);
#define BINDER_DEBUG_ENTRY(name) \
static int binder_##name##_open(struct inode *inode, struct file *file) \
{ \
	return single_open(file, binder_##name##_show, PDE(inode)->data); \
} \
\
static const struct file_operations binder_##name##_fops = { \
	.owner = THIS_MODULE, \
	.open = binder_##name##_open, \
	.read = seq_read, \
	.llseek = seq_lseek, \
	.release = single_release, \
}

static int binder_proc_show(struct seq_file *m, void *unused);
BINDER_DEBUG_ENTRY(proc);

/* This is only defined in include/asm-arm/sizes.h */
#ifndef SZ_1K
@@ -2880,9 +2895,9 @@ static int binder_open(struct inode *nodp, struct file *filp)
		char strbuf[11];
		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		remove_proc_entry(strbuf, binder_proc_dir_entry_proc);
		create_proc_read_entry(strbuf, S_IRUGO,
		proc_create_data(strbuf, S_IRUGO,
				 binder_proc_dir_entry_proc,
				       binder_read_proc_proc, proc);
				 &binder_proc_fops, proc);
	}

	return 0;
@@ -3105,47 +3120,39 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
	mutex_unlock(&binder_deferred_lock);
}

static char *print_binder_transaction(char *buf, char *end, const char *prefix,
static void print_binder_transaction(struct seq_file *m, const char *prefix,
				     struct binder_transaction *t)
{
	buf += snprintf(buf, end - buf,
			"%s %d: %p from %d:%d to %d:%d code %x "
			"flags %x pri %ld r%d",
	seq_printf(m,
		   "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
		   prefix, t->debug_id, t,
		   t->from ? t->from->proc->pid : 0,
		   t->from ? t->from->pid : 0,
		   t->to_proc ? t->to_proc->pid : 0,
		   t->to_thread ? t->to_thread->pid : 0,
		   t->code, t->flags, t->priority, t->need_reply);
	if (buf >= end)
		return buf;
	if (t->buffer == NULL) {
		buf += snprintf(buf, end - buf, " buffer free\n");
		return buf;
		seq_puts(m, " buffer free\n");
		return;
	}
	if (t->buffer->target_node) {
		buf += snprintf(buf, end - buf, " node %d",
	if (t->buffer->target_node)
		seq_printf(m, " node %d",
			   t->buffer->target_node->debug_id);
		if (buf >= end)
			return buf;
	}
	buf += snprintf(buf, end - buf, " size %zd:%zd data %p\n",
	seq_printf(m, " size %zd:%zd data %p\n",
		   t->buffer->data_size, t->buffer->offsets_size,
		   t->buffer->data);
	return buf;
}

static char *print_binder_buffer(char *buf, char *end, const char *prefix,
static void print_binder_buffer(struct seq_file *m, const char *prefix,
				struct binder_buffer *buffer)
{
	buf += snprintf(buf, end - buf, "%s %d: %p size %zd:%zd %s\n",
	seq_printf(m, "%s %d: %p size %zd:%zd %s\n",
		   prefix, buffer->debug_id, buffer->data,
		   buffer->data_size, buffer->offsets_size,
		   buffer->transaction ? "active" : "delivered");
	return buf;
}

static char *print_binder_work(char *buf, char *end, const char *prefix,
static void print_binder_work(struct seq_file *m, const char *prefix,
			      const char *transaction_prefix,
			      struct binder_work *w)
{
@@ -3155,79 +3162,65 @@ static char *print_binder_work(char *buf, char *end, const char *prefix,
	switch (w->type) {
	case BINDER_WORK_TRANSACTION:
		t = container_of(w, struct binder_transaction, work);
		buf = print_binder_transaction(buf, end, transaction_prefix, t);
		print_binder_transaction(m, transaction_prefix, t);
		break;
	case BINDER_WORK_TRANSACTION_COMPLETE:
		buf += snprintf(buf, end - buf,
				"%stransaction complete\n", prefix);
		seq_printf(m, "%stransaction complete\n", prefix);
		break;
	case BINDER_WORK_NODE:
		node = container_of(w, struct binder_node, work);
		buf += snprintf(buf, end - buf, "%snode work %d: u%p c%p\n",
				prefix, node->debug_id, node->ptr,
				node->cookie);
		seq_printf(m, "%snode work %d: u%p c%p\n",
			   prefix, node->debug_id, node->ptr, node->cookie);
		break;
	case BINDER_WORK_DEAD_BINDER:
		buf += snprintf(buf, end - buf, "%shas dead binder\n", prefix);
		seq_printf(m, "%shas dead binder\n", prefix);
		break;
	case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
		buf += snprintf(buf, end - buf,
				"%shas cleared dead binder\n", prefix);
		seq_printf(m, "%shas cleared dead binder\n", prefix);
		break;
	case BINDER_WORK_CLEAR_DEATH_NOTIFICATION:
		buf += snprintf(buf, end - buf,
				"%shas cleared death notification\n", prefix);
		seq_printf(m, "%shas cleared death notification\n", prefix);
		break;
	default:
		buf += snprintf(buf, end - buf, "%sunknown work: type %d\n",
				prefix, w->type);
		seq_printf(m, "%sunknown work: type %d\n", prefix, w->type);
		break;
	}
	return buf;
}

static char *print_binder_thread(char *buf, char *end,
static void print_binder_thread(struct seq_file *m,
				struct binder_thread *thread,
				int print_always)
{
	struct binder_transaction *t;
	struct binder_work *w;
	char *start_buf = buf;
	char *header_buf;
	size_t start_pos = m->count;
	size_t header_pos;

	buf += snprintf(buf, end - buf, "  thread %d: l %02x\n",
			thread->pid, thread->looper);
	header_buf = buf;
	seq_printf(m, "  thread %d: l %02x\n", thread->pid, thread->looper);
	header_pos = m->count;
	t = thread->transaction_stack;
	while (t) {
		if (buf >= end)
			break;
		if (t->from == thread) {
			buf = print_binder_transaction(buf, end,
			print_binder_transaction(m,
						 "    outgoing transaction", t);
			t = t->from_parent;
		} else if (t->to_thread == thread) {
			buf = print_binder_transaction(buf, end,
			print_binder_transaction(m,
						 "    incoming transaction", t);
			t = t->to_parent;
		} else {
			buf = print_binder_transaction(buf, end,
						"    bad transaction", t);
			print_binder_transaction(m, "    bad transaction", t);
			t = NULL;
		}
	}
	list_for_each_entry(w, &thread->todo, entry) {
		if (buf >= end)
			break;
		buf = print_binder_work(buf, end, "    ",
					"    pending transaction", w);
		print_binder_work(m, "    ", "    pending transaction", w);
	}
	if (!print_always && buf == header_buf)
		buf = start_buf;
	return buf;
	if (!print_always && m->count == header_pos)
		m->count = start_pos;
}

static char *print_binder_node(char *buf, char *end, struct binder_node *node)
static void print_binder_node(struct seq_file *m, struct binder_node *node)
{
	struct binder_ref *ref;
	struct hlist_node *pos;
@@ -3238,100 +3231,67 @@ static char *print_binder_node(char *buf, char *end, struct binder_node *node)
	hlist_for_each_entry(ref, pos, &node->refs, node_entry)
		count++;

	buf += snprintf(buf, end - buf,
			"  node %d: u%p c%p hs %d hw %d ls %d lw %d "
			"is %d iw %d",
	seq_printf(m, "  node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d",
		   node->debug_id, node->ptr, node->cookie,
		   node->has_strong_ref, node->has_weak_ref,
		   node->local_strong_refs, node->local_weak_refs,
		   node->internal_strong_refs, count);
	if (buf >= end)
		return buf;
	if (count) {
		buf += snprintf(buf, end - buf, " proc");
		if (buf >= end)
			return buf;
		hlist_for_each_entry(ref, pos, &node->refs, node_entry) {
			buf += snprintf(buf, end - buf, " %d", ref->proc->pid);
			if (buf >= end)
				return buf;
		}
		seq_puts(m, " proc");
		hlist_for_each_entry(ref, pos, &node->refs, node_entry)
			seq_printf(m, " %d", ref->proc->pid);
	}
	buf += snprintf(buf, end - buf, "\n");
	list_for_each_entry(w, &node->async_todo, entry) {
		if (buf >= end)
			break;
		buf = print_binder_work(buf, end, "    ",
	seq_puts(m, "\n");
	list_for_each_entry(w, &node->async_todo, entry)
		print_binder_work(m, "    ",
				  "    pending async transaction", w);
}
	return buf;
}

static char *print_binder_ref(char *buf, char *end, struct binder_ref *ref)
static void print_binder_ref(struct seq_file *m, struct binder_ref *ref)
{
	buf += snprintf(buf, end - buf,
			"  ref %d: desc %d %snode %d s %d w %d d %p\n",
			ref->debug_id, ref->desc,
			ref->node->proc ? "" : "dead ", ref->node->debug_id,
			ref->strong, ref->weak, ref->death);
	return buf;
	seq_printf(m, "  ref %d: desc %d %snode %d s %d w %d d %p\n",
		   ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ",
		   ref->node->debug_id, ref->strong, ref->weak, ref->death);
}

static char *print_binder_proc(char *buf, char *end,
static void print_binder_proc(struct seq_file *m,
			      struct binder_proc *proc, int print_all)
{
	struct binder_work *w;
	struct rb_node *n;
	char *start_buf = buf;
	char *header_buf;
	size_t start_pos = m->count;
	size_t header_pos;

	buf += snprintf(buf, end - buf, "proc %d\n", proc->pid);
	header_buf = buf;
	seq_printf(m, "proc %d\n", proc->pid);
	header_pos = m->count;

	for (n = rb_first(&proc->threads);
	     n != NULL && buf < end;
	     n = rb_next(n))
		buf = print_binder_thread(buf, end,
					  rb_entry(n, struct binder_thread,
	for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
		print_binder_thread(m, rb_entry(n, struct binder_thread,
						rb_node), print_all);
	for (n = rb_first(&proc->nodes);
	     n != NULL && buf < end;
	     n = rb_next(n)) {
	for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) {
		struct binder_node *node = rb_entry(n, struct binder_node,
						    rb_node);
		if (print_all || node->has_async_transaction)
			buf = print_binder_node(buf, end, node);
			print_binder_node(m, node);
	}
	if (print_all) {
		for (n = rb_first(&proc->refs_by_desc);
		     n != NULL && buf < end;
		     n != NULL;
		     n = rb_next(n))
			buf = print_binder_ref(buf, end,
					       rb_entry(n, struct binder_ref,
			print_binder_ref(m, rb_entry(n, struct binder_ref,
						     rb_node_desc));
	}
	for (n = rb_first(&proc->allocated_buffers);
	     n != NULL && buf < end;
	     n = rb_next(n))
		buf = print_binder_buffer(buf, end, "  buffer",
					  rb_entry(n, struct binder_buffer,
						   rb_node));
	list_for_each_entry(w, &proc->todo, entry) {
		if (buf >= end)
			break;
		buf = print_binder_work(buf, end, "  ",
					"  pending transaction", w);
	}
	for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n))
		print_binder_buffer(m, "  buffer",
				    rb_entry(n, struct binder_buffer, rb_node));
	list_for_each_entry(w, &proc->todo, entry)
		print_binder_work(m, "  ", "  pending transaction", w);
	list_for_each_entry(w, &proc->delivered_death, entry) {
		if (buf >= end)
			break;
		buf += snprintf(buf, end - buf,
				"  has delivered dead binder\n");
		seq_puts(m, "  has delivered dead binder\n");
		break;
	}
	if (!print_all && buf == header_buf)
		buf = start_buf;
	return buf;
	if (!print_all && m->count == header_pos)
		m->count = start_pos;
}

static const char *binder_return_strings[] = {
@@ -3385,7 +3345,7 @@ static const char *binder_objstat_strings[] = {
	"transaction_complete"
};

static char *print_binder_stats(char *buf, char *end, const char *prefix,
static void print_binder_stats(struct seq_file *m, const char *prefix,
			       struct binder_stats *stats)
{
	int i;
@@ -3394,21 +3354,16 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix,
		     ARRAY_SIZE(binder_command_strings));
	for (i = 0; i < ARRAY_SIZE(stats->bc); i++) {
		if (stats->bc[i])
			buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix,
					binder_command_strings[i],
					stats->bc[i]);
		if (buf >= end)
			return buf;
			seq_printf(m, "%s%s: %d\n", prefix,
				   binder_command_strings[i], stats->bc[i]);
	}

	BUILD_BUG_ON(ARRAY_SIZE(stats->br) !=
		     ARRAY_SIZE(binder_return_strings));
	for (i = 0; i < ARRAY_SIZE(stats->br); i++) {
		if (stats->br[i])
			buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix,
			seq_printf(m, "%s%s: %d\n", prefix,
				   binder_return_strings[i], stats->br[i]);
		if (buf >= end)
			return buf;
	}

	BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) !=
@@ -3417,47 +3372,34 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix,
		     ARRAY_SIZE(stats->obj_deleted));
	for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) {
		if (stats->obj_created[i] || stats->obj_deleted[i])
			buf += snprintf(buf, end - buf,
					"%s%s: active %d total %d\n", prefix,
			seq_printf(m, "%s%s: active %d total %d\n", prefix,
				binder_objstat_strings[i],
					stats->obj_created[i] -
						stats->obj_deleted[i],
				stats->obj_created[i] - stats->obj_deleted[i],
				stats->obj_created[i]);
		if (buf >= end)
			return buf;
	}
	return buf;
}

static char *print_binder_proc_stats(char *buf, char *end,
static void print_binder_proc_stats(struct seq_file *m,
				    struct binder_proc *proc)
{
	struct binder_work *w;
	struct rb_node *n;
	int count, strong, weak;

	buf += snprintf(buf, end - buf, "proc %d\n", proc->pid);
	if (buf >= end)
		return buf;
	seq_printf(m, "proc %d\n", proc->pid);
	count = 0;
	for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
		count++;
	buf += snprintf(buf, end - buf, "  threads: %d\n", count);
	if (buf >= end)
		return buf;
	buf += snprintf(buf, end - buf, "  requested threads: %d+%d/%d\n"
	seq_printf(m, "  threads: %d\n", count);
	seq_printf(m, "  requested threads: %d+%d/%d\n"
			"  ready threads %d\n"
			"  free async space %zd\n", proc->requested_threads,
			proc->requested_threads_started, proc->max_threads,
			proc->ready_threads, proc->free_async_space);
	if (buf >= end)
		return buf;
	count = 0;
	for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n))
		count++;
	buf += snprintf(buf, end - buf, "  nodes: %d\n", count);
	if (buf >= end)
		return buf;
	seq_printf(m, "  nodes: %d\n", count);
	count = 0;
	strong = 0;
	weak = 0;
@@ -3468,17 +3410,12 @@ static char *print_binder_proc_stats(char *buf, char *end,
		strong += ref->strong;
		weak += ref->weak;
	}
	buf += snprintf(buf, end - buf, "  refs: %d s %d w %d\n",
			count, strong, weak);
	if (buf >= end)
		return buf;
	seq_printf(m, "  refs: %d s %d w %d\n", count, strong, weak);

	count = 0;
	for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n))
		count++;
	buf += snprintf(buf, end - buf, "  buffers: %d\n", count);
	if (buf >= end)
		return buf;
	seq_printf(m, "  buffers: %d\n", count);

	count = 0;
	list_for_each_entry(w, &proc->todo, entry) {
@@ -3490,222 +3427,110 @@ static char *print_binder_proc_stats(char *buf, char *end,
			break;
		}
	}
	buf += snprintf(buf, end - buf, "  pending transactions: %d\n", count);
	if (buf >= end)
		return buf;

	buf = print_binder_stats(buf, end, "  ", &proc->stats);
	seq_printf(m, "  pending transactions: %d\n", count);

	return buf;
	print_binder_stats(m, "  ", &proc->stats);
}


static int binder_read_proc_state(char *page, char **start, off_t off,
				  int count, int *eof, void *data)
static int binder_state_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc;
	struct hlist_node *pos;
	struct binder_node *node;
	int len = 0;
	char *buf = page;
	char *end = page + PAGE_SIZE;
	int do_lock = !binder_debug_no_lock;

	if (off)
		return 0;

	if (do_lock)
		mutex_lock(&binder_lock);

	buf += snprintf(buf, end - buf, "binder state:\n");
	seq_puts(m, "binder state:\n");

	if (!hlist_empty(&binder_dead_nodes))
		buf += snprintf(buf, end - buf, "dead nodes:\n");
	hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) {
		if (buf >= end)
			break;
		buf = print_binder_node(buf, end, node);
	}
		seq_puts(m, "dead nodes:\n");
	hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node)
		print_binder_node(m, node);

	hlist_for_each_entry(proc, pos, &binder_procs, proc_node) {
		if (buf >= end)
			break;
		buf = print_binder_proc(buf, end, proc, 1);
	}
	hlist_for_each_entry(proc, pos, &binder_procs, proc_node)
		print_binder_proc(m, proc, 1);
	if (do_lock)
		mutex_unlock(&binder_lock);
	if (buf > page + PAGE_SIZE)
		buf = page + PAGE_SIZE;

	*start = page + off;

	len = buf - page;
	if (len > off)
		len -= off;
	else
		len = 0;

	return len < count ? len  : count;
	return 0;
}

static int binder_read_proc_stats(char *page, char **start, off_t off,
				  int count, int *eof, void *data)
static int binder_stats_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc;
	struct hlist_node *pos;
	int len = 0;
	char *p = page;
	int do_lock = !binder_debug_no_lock;

	if (off)
		return 0;

	if (do_lock)
		mutex_lock(&binder_lock);

	p += snprintf(p, PAGE_SIZE, "binder stats:\n");
	seq_puts(m, "binder stats:\n");

	p = print_binder_stats(p, page + PAGE_SIZE, "", &binder_stats);
	print_binder_stats(m, "", &binder_stats);

	hlist_for_each_entry(proc, pos, &binder_procs, proc_node) {
		if (p >= page + PAGE_SIZE)
			break;
		p = print_binder_proc_stats(p, page + PAGE_SIZE, proc);
	}
	hlist_for_each_entry(proc, pos, &binder_procs, proc_node)
		print_binder_proc_stats(m, proc);
	if (do_lock)
		mutex_unlock(&binder_lock);
	if (p > page + PAGE_SIZE)
		p = page + PAGE_SIZE;

	*start = page + off;

	len = p - page;
	if (len > off)
		len -= off;
	else
		len = 0;

	return len < count ? len  : count;
	return 0;
}

static int binder_read_proc_transactions(char *page, char **start, off_t off,
					 int count, int *eof, void *data)
static int binder_transactions_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc;
	struct hlist_node *pos;
	int len = 0;
	char *buf = page;
	char *end = page + PAGE_SIZE;
	int do_lock = !binder_debug_no_lock;

	if (off)
		return 0;

	if (do_lock)
		mutex_lock(&binder_lock);

	buf += snprintf(buf, end - buf, "binder transactions:\n");
	hlist_for_each_entry(proc, pos, &binder_procs, proc_node) {
		if (buf >= end)
			break;
		buf = print_binder_proc(buf, end, proc, 0);
	}
	seq_puts(m, "binder transactions:\n");
	hlist_for_each_entry(proc, pos, &binder_procs, proc_node)
		print_binder_proc(m, proc, 0);
	if (do_lock)
		mutex_unlock(&binder_lock);
	if (buf > page + PAGE_SIZE)
		buf = page + PAGE_SIZE;

	*start = page + off;

	len = buf - page;
	if (len > off)
		len -= off;
	else
		len = 0;

	return len < count ? len  : count;
	return 0;
}

static int binder_read_proc_proc(char *page, char **start, off_t off,
				 int count, int *eof, void *data)
static int binder_proc_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc = data;
	int len = 0;
	char *p = page;
	struct binder_proc *proc = m->private;
	int do_lock = !binder_debug_no_lock;

	if (off)
		return 0;

	if (do_lock)
		mutex_lock(&binder_lock);
	p += snprintf(p, PAGE_SIZE, "binder proc state:\n");
	p = print_binder_proc(p, page + PAGE_SIZE, proc, 1);
	seq_puts(m, "binder proc state:\n");
	print_binder_proc(m, proc, 1);
	if (do_lock)
		mutex_unlock(&binder_lock);

	if (p > page + PAGE_SIZE)
		p = page + PAGE_SIZE;
	*start = page + off;

	len = p - page;
	if (len > off)
		len -= off;
	else
		len = 0;

	return len < count ? len  : count;
	return 0;
}

static char *print_binder_transaction_log_entry(char *buf, char *end,
static void print_binder_transaction_log_entry(struct seq_file *m,
					struct binder_transaction_log_entry *e)
{
	buf += snprintf(buf, end - buf,
			"%d: %s from %d:%d to %d:%d node %d handle %d "
			"size %d:%d\n",
	seq_printf(m,
		   "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n",
		   e->debug_id, (e->call_type == 2) ? "reply" :
		   ((e->call_type == 1) ? "async" : "call "), e->from_proc,
		   e->from_thread, e->to_proc, e->to_thread, e->to_node,
		   e->target_handle, e->data_size, e->offsets_size);
	return buf;
}

static int binder_read_proc_transaction_log(
	char *page, char **start, off_t off, int count, int *eof, void *data)
static int binder_transaction_log_show(struct seq_file *m, void *unused)
{
	struct binder_transaction_log *log = data;
	int len = 0;
	struct binder_transaction_log *log = m->private;
	int i;
	char *buf = page;
	char *end = page + PAGE_SIZE;

	if (off)
		return 0;

	if (log->full) {
		for (i = log->next; i < ARRAY_SIZE(log->entry); i++) {
			if (buf >= end)
				break;
			buf = print_binder_transaction_log_entry(buf, end,
								&log->entry[i]);
		}
	}
	for (i = 0; i < log->next; i++) {
		if (buf >= end)
			break;
		buf = print_binder_transaction_log_entry(buf, end,
							 &log->entry[i]);
		for (i = log->next; i < ARRAY_SIZE(log->entry); i++)
			print_binder_transaction_log_entry(m, &log->entry[i]);
	}

	*start = page + off;

	len = buf - page;
	if (len > off)
		len -= off;
	else
		len = 0;

	return len < count ? len  : count;
	for (i = 0; i < log->next; i++)
		print_binder_transaction_log_entry(m, &log->entry[i]);
	return 0;
}

static const struct file_operations binder_fops = {
@@ -3724,6 +3549,11 @@ static struct miscdevice binder_miscdev = {
	.fops = &binder_fops
};

BINDER_DEBUG_ENTRY(state);
BINDER_DEBUG_ENTRY(stats);
BINDER_DEBUG_ENTRY(transactions);
BINDER_DEBUG_ENTRY(transaction_log);

static int __init binder_init(void)
{
	int ret;
@@ -3734,30 +3564,27 @@ static int __init binder_init(void)
						binder_proc_dir_entry_root);
	ret = misc_register(&binder_miscdev);
	if (binder_proc_dir_entry_root) {
		create_proc_read_entry("state",
		proc_create("state",
			    S_IRUGO,
			    binder_proc_dir_entry_root,
				       binder_read_proc_state,
				       NULL);
		create_proc_read_entry("stats",
			    &binder_state_fops);
		proc_create("stats",
			    S_IRUGO,
			    binder_proc_dir_entry_root,
				       binder_read_proc_stats,
				       NULL);
		create_proc_read_entry("transactions",
			    &binder_stats_fops);
		proc_create("transactions",
			    S_IRUGO,
			    binder_proc_dir_entry_root,
				       binder_read_proc_transactions,
				       NULL);
		create_proc_read_entry("transaction_log",
			    &binder_transactions_fops);
		proc_create_data("transaction_log",
				 S_IRUGO,
				 binder_proc_dir_entry_root,
				       binder_read_proc_transaction_log,
				 &binder_transaction_log_fops,
				 &binder_transaction_log);
		create_proc_read_entry("failed_transaction_log",
		proc_create_data("failed_transaction_log",
				 S_IRUGO,
				 binder_proc_dir_entry_root,
				       binder_read_proc_transaction_log,
				 &binder_transaction_log_fops,
				 &binder_transaction_log_failed);
	}
	return ret;