[ltt-dev] [PATCH] Lists all registered markers/tracepoints on the system

Takashi NISHIIE t-nishiie at np.css.fujitsu.com
Tue Oct 14 22:33:31 EDT 2008


Hi

 I propose the marker/tracepoint debugfs interface. (like kprobe
debugfs interface style.)
 The list of registered marker/tracepoint is visible under the 
/debug/markers/ directory and /debug/tracepoint/ directory 
(assuming debugfs is mounted at /debug).

/debug/markers/list: Lists all registered markers on the system

# cat /debug/markers/list
core_marker_id : (c05060bc,f6b993a0)
core_marker_format : (c05060bc,f6b993bc)

/debug/tracepoint/list: Lists all registered markers on the system

# cat /debug/tracepoint/list
ipc_sem_create:TPPROTO(long id, int flags) : f89f0024
timer_update_time:TPPROTO(struct timespec *_xtime, struct timespec 
*_wall_to_monotonic) : f8a1310c
sched_process_fork:TPPROTO(struct task_struct *parent, struct 
task_struct *child) : f8a131ce

/debug/markers/debug: Turn debug ON/OFF (default 0:OFF)
/debug/tracepoint/debug: Turn debug ON/OFF (default 0:OFF)

TODO:
 switch marker/tracepoint list to one file per marker/tracepoint
 (for LTTng).

---

Signed-off-by: Takashi NISHIIE <t-nishiie at np.css.fujitsu.com>

diff --git a/kernel/marker.c b/kernel/marker.c
index 36a23f8..9f958a3 100644
--- a/kernel/marker.c
+++ b/kernel/marker.c
@@ -28,12 +28,15 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 #include <linux/user_marker.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
 
 extern struct marker __start___markers[];
 extern struct marker __stop___markers[];
 
 /* Set to 1 to enable marker debug output */
-static const int marker_debug;
+static int marker_debug;
 
 /*
  * markers_mutex nests inside module_mutex. Markers mutex protects the
builtin
@@ -1179,3 +1182,162 @@ int is_marker_enabled(const char *name)
 	return entry && !!entry->refcount;
 }
 #endif
+
+#ifdef CONFIG_DEBUG_FS
+
+static struct dentry *debugfs_marker_dir;
+static struct dentry *debugfs_debug_file;
+static struct dentry *debugfs_list_file;
+
+static void report_marker(struct seq_file *pi, struct marker_entry *entry)
+{
+	int i;
+
+	if (!entry)
+		return;
+
+	if (!entry->ptype) {
+		seq_printf(pi, "%s :", entry->name);
+		seq_printf(pi, " (%p,%p)",
+			entry->single.func,
+			entry->single.probe_private);
+		seq_printf(pi, "\n");
+	} else {
+		seq_printf(pi, "%s :", entry->name);
+		for (i = 0; entry->multi[i].func; i++)
+			seq_printf(pi, " (%p,%p)",
+				entry->multi[i].func,
+				entry->multi[i].probe_private);
+		seq_printf(pi, "\n");
+	}
+}
+
+static void *marker_list_seq_start(struct seq_file *f, loff_t *pos)
+{
+	return (*pos < MARKER_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *marker_list_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	(*pos)++;
+	if (*pos >= MARKER_TABLE_SIZE)
+		return NULL;
+	return pos;
+}
+
+static void marker_list_seq_stop(struct seq_file *f, void *v)
+{
+	/* Nothing to do */
+}
+
+static int show_marker_list(struct seq_file *pi, void *v)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct marker_entry *entry;
+	unsigned int i = *(loff_t *) v;
+
+	head = &marker_table[i];
+	preempt_disable();
+	hlist_for_each_entry_rcu(entry, node, head, hlist) {
+		report_marker(pi, entry);
+	}
+	preempt_enable();
+	return 0;
+}
+
+static struct seq_operations marker_list_seq_ops = {
+	.start = marker_list_seq_start,
+	.next  = marker_list_seq_next,
+	.stop  = marker_list_seq_stop,
+	.show  = show_marker_list
+};
+
+static int marker_list_open(struct inode *inode, struct file *filp)
+{
+	return seq_open(filp, &marker_list_seq_ops);
+}
+
+static struct file_operations debugfs_list_operations = {
+	.open           = marker_list_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = seq_release,
+};
+
+
+static ssize_t read_debug_file_bool(struct file *file,
+	       char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[3];
+
+	if (marker_debug)
+		buf[0] = '1';
+	else
+		buf[0] = '0';
+	buf[1] = '\n';
+	buf[2] = 0x00;
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_debug_file_bool(struct file *file,
+	       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[32];
+	int buf_size;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	switch (buf[0]) {
+	case 'y':
+	case 'Y':
+	case '1':
+		marker_debug = 1;
+		break;
+	case 'n':
+	case 'N':
+	case '0':
+		marker_debug = 0;
+		break;
+	}
+
+	return count;
+}
+
+static struct file_operations fops_debug = {
+	.read =         read_debug_file_bool,
+	.write =        write_debug_file_bool,
+};
+
+static int __init debugfs_marker_init(void)
+{
+	unsigned int value = 0;
+
+	debugfs_marker_dir = debugfs_create_dir("markers", NULL);
+	if (!debugfs_marker_dir)
+		return -ENOMEM;
+
+	debugfs_list_file = debugfs_create_file("list", 0444,
debugfs_marker_dir,
+					NULL, &debugfs_list_operations);
+	if (!debugfs_list_file) {
+		debugfs_remove(debugfs_marker_dir);
+		debugfs_marker_dir = NULL;
+		return -ENOMEM;
+	}
+
+	debugfs_debug_file = debugfs_create_file("debug", 0600,
debugfs_marker_dir,
+					&value, &fops_debug);
+	if (!debugfs_debug_file) {
+		debugfs_remove(debugfs_marker_dir);
+		debugfs_marker_dir = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+late_initcall(debugfs_marker_init);
+#endif /* CONFIG_DEBUG_FS */
+
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index f9121f8..594a6fa 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -25,12 +25,15 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/immediate.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
 
 extern struct tracepoint __start___tracepoints[];
 extern struct tracepoint __stop___tracepoints[];
 
 /* Set to 1 to enable tracepoint debug output */
-static const int tracepoint_debug;
+static int tracepoint_debug;
 
 /*
  * tracepoints_mutex nests inside module_mutex. Tracepoints mutex protects
the
@@ -478,3 +481,151 @@ void tracepoint_iter_reset(struct tracepoint_iter
*iter)
 	iter->tracepoint = NULL;
 }
 EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
+
+#ifdef CONFIG_DEBUG_FS
+
+static struct dentry *debugfs_tracepoint_dir;
+static struct dentry *debugfs_debug_file;
+static struct dentry *debugfs_list_file;
+
+static void report_tracepoint(struct seq_file *pi, struct tracepoint_entry
*entry)
+{
+	int i;
+
+	if (!entry)
+		return;
+
+	seq_printf(pi, "%s :", entry->name);
+	for (i = 0; entry->funcs[i]; i++)
+		seq_printf(pi, " %p", entry->funcs[i]);
+	seq_printf(pi, "\n");
+}
+
+static void *tracepoint_list_seq_start(struct seq_file *f, loff_t *pos)
+{
+	return (*pos < TRACEPOINT_TABLE_SIZE) ? pos : NULL;
+}
+
+static void *tracepoint_list_seq_next(struct seq_file *f, void *v, loff_t
*pos)
+{
+	(*pos)++;
+	if (*pos >= TRACEPOINT_TABLE_SIZE)
+		return NULL;
+	return pos;
+}
+
+static void tracepoint_list_seq_stop(struct seq_file *f, void *v)
+{
+	/* Nothing to do */
+}
+
+static int show_tracepoint_list(struct seq_file *pi, void *v)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct tracepoint_entry *entry;
+	unsigned int i = *(loff_t *) v;
+
+	head = &tracepoint_table[i];
+	preempt_disable();
+	hlist_for_each_entry_rcu(entry, node, head, hlist) {
+		report_tracepoint(pi, entry);
+	}
+	preempt_enable();
+	return 0;
+}
+
+static struct seq_operations tracepoint_list_seq_ops = {
+	.start = tracepoint_list_seq_start,
+	.next  = tracepoint_list_seq_next,
+	.stop  = tracepoint_list_seq_stop,
+	.show  = show_tracepoint_list
+};
+
+static int tracepoint_list_open(struct inode *inode, struct file *filp)
+{
+	return seq_open(filp, &tracepoint_list_seq_ops);
+}
+
+static struct file_operations debugfs_list_operations = {
+	.open           = tracepoint_list_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = seq_release,
+};
+
+static ssize_t read_debug_file_bool(struct file *file,
+	       char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[3];
+
+	if (tracepoint_debug)
+		buf[0] = '1';
+	else
+		buf[0] = '0';
+	buf[1] = '\n';
+	buf[2] = 0x00;
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_debug_file_bool(struct file *file,
+	       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[32];
+	int buf_size;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	switch (buf[0]) {
+	case 'y':
+	case 'Y':
+	case '1':
+		tracepoint_debug = 1;
+		break;
+	case 'n':
+	case 'N':
+	case '0':
+		tracepoint_debug = 0;
+		break;
+	}
+
+	return count;
+}
+
+static struct file_operations fops_debug = {
+	.read =         read_debug_file_bool,
+	.write =        write_debug_file_bool,
+};
+
+static int debugfs_tracepoint_init(void)
+{
+	unsigned int value = 0;
+
+	debugfs_tracepoint_dir = debugfs_create_dir("tracepoint", NULL);
+	if (!debugfs_tracepoint_dir)
+		return -ENOMEM;
+
+	debugfs_list_file = debugfs_create_file("list", 0444,
debugfs_tracepoint_dir,
+					NULL, &debugfs_list_operations);
+	if (!debugfs_list_file) {
+		debugfs_remove(debugfs_tracepoint_dir);
+		debugfs_tracepoint_dir = NULL;
+		return -ENOMEM;
+	}
+
+	debugfs_debug_file = debugfs_create_file("debug", 0600,
debugfs_tracepoint_dir,
+					&value, &fops_debug);
+	if (!debugfs_debug_file) {
+		debugfs_remove(debugfs_tracepoint_dir);
+		debugfs_tracepoint_dir = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+late_initcall(debugfs_tracepoint_init);
+#endif /* CONFIG_DEBUG_FS */
+

Regards,Takashi
---
Takashi NISHIIE






More information about the lttng-dev mailing list