* [PATCH] Lists all registered markers/tracepoints on the system
@ 2008-10-15 2:33 Takashi NISHIIE
0 siblings, 0 replies; only message in thread
From: Takashi NISHIIE @ 2008-10-15 2:33 UTC (permalink / raw)
To: ltt-dev; +Cc: linux-kernel
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@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
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2008-10-15 2:33 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-15 2:33 [PATCH] Lists all registered markers/tracepoints on the system Takashi NISHIIE
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.