Skip to contentSkip to conversation

Lists all registered markers/tracepoints on the system

PATCH New Takashi NISHIIE 1 participant 1 message Oct 15, 2008 Tracing

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Lists all registered markers/tracepoints on the system

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).

---

kernel/marker.c +4 -1
index 36a23f8..9f958a3 100644
@@ -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 */
+

kernel/tracepoint.c +4 -1
index f9121f8..594a6fa 100644
@@ -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