]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: Initial import of kernelspace code.
authorNick Alcock <nick.alcock@oracle.com>
Thu, 12 May 2011 22:46:51 +0000 (15:46 -0700)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:39:50 +0000 (22:39 +0100)
Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
15 files changed:
arch/x86/include/asm/stacktrace.h
include/linux/module.h
include/linux/sched.h
include/linux/sdt.h [new file with mode: 0644]
init/Kconfig
init/main.c
kernel/Makefile
kernel/dtrace/Kconfig [new file with mode: 0644]
kernel/dtrace/Makefile [new file with mode: 0644]
kernel/dtrace/cyclic.c [new file with mode: 0644]
kernel/dtrace/cyclic.h [new file with mode: 0644]
kernel/dtrace/dtrace_ioctl.h [new file with mode: 0644]
kernel/dtrace/sdt_register.c [new file with mode: 0644]
scripts/Makefile
scripts/dtrace_relocs.c [new file with mode: 0644]

index 70bbe39043a9cda384e9afcd0a2f633cfde20931..c57a075b9ef145ae7ca957c8b2554b04fc551fde 100644 (file)
@@ -43,6 +43,13 @@ struct stacktrace_ops {
        walk_stack_t    walk_stack;
 };
 
+extern unsigned long print_context_stack(struct thread_info *tinfo,
+                                        unsigned long *stack,
+                                        unsigned long bp,
+                                        const struct stacktrace_ops *ops,
+                                        void *data, unsigned long *end,
+                                        int *graph);
+
 void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data);
index c883b86ea9649ae62ca485dd3843e51e43edc346..b3389fc9a5a49e758edffa245901cd622f21c93e 100644 (file)
@@ -350,6 +350,11 @@ struct module {
        bool klp_alive;
 #endif
 
+#if defined(CONFIG_DTRACE) || defined(CONFIG_DTRACE_MODULE)
+       struct sdt_probedesc *sdt_probes;
+       unsigned int num_dtrace_probes;
+#endif
+
 #ifdef CONFIG_MODULE_UNLOAD
        /* What modules depend on me? */
        struct list_head source_list;
index 26a2e6122734f8237ac44d47fb6bf4e96cca124b..548a3b6c0037bc3db69728a477202057e98cb225 100644 (file)
@@ -1713,6 +1713,14 @@ struct task_struct {
                int order;
                unsigned int may_oom:1;
        } memcg_oom;
+#ifdef CONFIG_DTRACE
+       uint32_t predcache;
+       ktime_t dtrace_vtime;
+       ktime_t dtrace_start;
+       uint8_t dtrace_stop;
+       uint8_t dtrace_sig;
+
+       void *dtrace_helpers;
 #endif
 #ifdef CONFIG_UPROBES
        struct uprobe_task *utask;
diff --git a/include/linux/sdt.h b/include/linux/sdt.h
new file mode 100644 (file)
index 0000000..c339478
--- /dev/null
@@ -0,0 +1,442 @@
+#ifndef _SDT_H_
+#define        _SDT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(CONFIG_DTRACE) || defined(CONFIG_DTRACE_MODULE)
+
+#ifndef __KERNEL__
+
+#define        DTRACE_PROBE(provider, name) {                                  \
+       extern void __dtrace_##provider##___##name(void);               \
+       __dtrace_##provider##___##name();                               \
+}
+
+#define        DTRACE_PROBE1(provider, name, arg1) {                           \
+       extern void __dtrace_##provider##___##name(unsigned long);      \
+       __dtrace_##provider##___##name((unsigned long)arg1);            \
+}
+
+#define        DTRACE_PROBE2(provider, name, arg1, arg2) {                     \
+       extern void __dtrace_##provider##___##name(unsigned long,       \
+           unsigned long);                                             \
+       __dtrace_##provider##___##name((unsigned long)arg1,             \
+           (unsigned long)arg2);                                       \
+}
+
+#define        DTRACE_PROBE3(provider, name, arg1, arg2, arg3) {               \
+       extern void __dtrace_##provider##___##name(unsigned long,       \
+           unsigned long, unsigned long);                              \
+       __dtrace_##provider##___##name((unsigned long)arg1,             \
+           (unsigned long)arg2, (unsigned long)arg3);                  \
+}
+
+#define        DTRACE_PROBE4(provider, name, arg1, arg2, arg3, arg4) {         \
+       extern void __dtrace_##provider##___##name(unsigned long,       \
+           unsigned long, unsigned long, unsigned long);               \
+       __dtrace_##provider##___##name((unsigned long)arg1,             \
+           (unsigned long)arg2, (unsigned long)arg3,                   \
+           (unsigned long)arg4);                                       \
+}
+
+#define        DTRACE_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) {   \
+       extern void __dtrace_##provider##___##name(unsigned long,       \
+           unsigned long, unsigned long, unsigned long, unsigned long);\
+       __dtrace_##provider##___##name((unsigned long)arg1,             \
+           (unsigned long)arg2, (unsigned long)arg3,                   \
+           (unsigned long)arg4, (unsigned long)arg5);                  \
+}
+
+#else /* __KERNEL__ */
+
+#define        DTRACE_PROBE(name)      {                                       \
+       extern void __dtrace_probe_##name(void);                        \
+       __dtrace_probe_##name();                                        \
+}
+
+#define        DTRACE_PROBE1(name, type1, arg1)        {                       \
+       extern void __dtrace_probe_##name(uintptr_t);                   \
+       __dtrace_probe_##name((uintptr_t)(arg1));                       \
+}
+
+#define        DTRACE_PROBE2(name, type1, arg1, type2, arg2)   {               \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t);        \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2));    \
+}
+
+#define        DTRACE_PROBE3(name, type1, arg1, type2, arg2, type3, arg3) {    \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t, uintptr_t); \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2),     \
+           (uintptr_t)(arg3));                                         \
+}
+
+#define        DTRACE_PROBE4(name, type1, arg1, type2, arg2,                   \
+       type3, arg3, type4, arg4) {                                     \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t,         \
+           uintptr_t, uintptr_t);                                      \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2),     \
+           (uintptr_t)(arg3), (uintptr_t)(arg4));                      \
+}
+
+#define        DTRACE_PROBE5(name, type1, arg1, type2, arg2,                   \
+       type3, arg3, type4, arg4, type5, arg5) {                        \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t,         \
+           uintptr_t, uintptr_t, uintptr_t);                           \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2),     \
+           (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5));   \
+}
+
+#define        DTRACE_PROBE6(name, type1, arg1, type2, arg2,                   \
+       type3, arg3, type4, arg4, type5, arg5, type6, arg6) {           \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t,         \
+           uintptr_t, uintptr_t, uintptr_t, uintptr_t);                \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2),     \
+           (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5),    \
+           (uintptr_t)(arg6));                                         \
+}
+
+#define        DTRACE_PROBE7(name, type1, arg1, type2, arg2, type3, arg3,      \
+       type4, arg4, type5, arg5, type6, arg6, type7, arg7) {           \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t,         \
+           uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);     \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2),     \
+           (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5),    \
+           (uintptr_t)(arg6), (uintptr_t)(arg7));                      \
+}
+
+#define        DTRACE_PROBE8(name, type1, arg1, type2, arg2, type3, arg3,      \
+       type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8) { \
+       extern void __dtrace_probe_##name(uintptr_t, uintptr_t,         \
+           uintptr_t, uintptr_t, uintptr_t, uintptr_t,                 \
+           uintptr_t, uintptr_t);                                      \
+       __dtrace_probe_##name((uintptr_t)(arg1), (uintptr_t)(arg2),     \
+           (uintptr_t)(arg3), (uintptr_t)(arg4), (uintptr_t)(arg5),    \
+           (uintptr_t)(arg6), (uintptr_t)(arg7), (uintptr_t)(arg8));   \
+}
+
+/*
+ * vmlinux dtrace_probe__ caller reloc info;
+ * comes from vmlinux_info.S
+ */
+extern unsigned long dtrace_relocs_count __attribute__((weak));
+extern void *dtrace_relocs __attribute__((weak));
+
+struct reloc_info {
+       unsigned long probe_offset;
+       unsigned long section_base;
+       unsigned long probe_name_len;
+       char probe_name[0];
+} __aligned(sizeof(unsigned long));
+
+void dtrace_register_builtins(void);
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#endif /* __KERNEL__ */
+
+#else /* DTRACE not enabled: */
+
+#define        DTRACE_PROBE(name)      do { } while (0)
+#define        DTRACE_PROBE1(name, type1, arg1)                DTRACE_PROBE(name)
+#define        DTRACE_PROBE2(name, type1, arg1, type2, arg2)   DTRACE_PROBE(name)
+#define        DTRACE_PROBE3(name, type1, arg1, type2, arg2, type3, arg3)      \
+                       DTRACE_PROBE(name)
+#define        DTRACE_PROBE4(name, type1, arg1, type2, arg2, type3, arg3,      \
+                       type4, arg4)                    DTRACE_PROBE(name)
+#define        DTRACE_PROBE5(name, type1, arg1, type2, arg2, type3, arg3,      \
+                       type4, arg4, type5, arg5)       DTRACE_PROBE(name)
+#define        DTRACE_PROBE6(name, type1, arg1, type2, arg2, type3, arg3,      \
+       type4, arg4, type5, arg5, type6, arg6)          DTRACE_PROBE(name)
+#define        DTRACE_PROBE7(name, type1, arg1, type2, arg2, type3, arg3,      \
+       type4, arg4, type5, arg5, type6, arg6, type7, arg7) DTRACE_PROBE(name)
+#define        DTRACE_PROBE8(name, type1, arg1, type2, arg2, type3, arg3,      \
+       type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8) \
+                       DTRACE_PROBE(name)
+
+#endif /* CONFIG_DTRACE */
+
+
+#define        DTRACE_SCHED(name)                                              \
+       DTRACE_PROBE(__sched_##name);
+
+#define        DTRACE_SCHED1(name, type1, arg1)                                \
+       DTRACE_PROBE1(__sched_##name, type1, arg1);
+
+#define        DTRACE_SCHED2(name, type1, arg1, type2, arg2)                   \
+       DTRACE_PROBE2(__sched_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_SCHED3(name, type1, arg1, type2, arg2, type3, arg3)      \
+       DTRACE_PROBE3(__sched_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_SCHED4(name, type1, arg1, type2, arg2,                   \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__sched_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_PROC(name)                                               \
+       DTRACE_PROBE(__proc_##name);
+
+#define        DTRACE_PROC1(name, type1, arg1)                                 \
+       DTRACE_PROBE1(__proc_##name, type1, arg1);
+
+#define        DTRACE_PROC2(name, type1, arg1, type2, arg2)                    \
+       DTRACE_PROBE2(__proc_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_PROC3(name, type1, arg1, type2, arg2, type3, arg3)       \
+       DTRACE_PROBE3(__proc_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_PROC4(name, type1, arg1, type2, arg2,                    \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__proc_##name, type1, arg1, type2, arg2,          \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_IO(name)                                                 \
+       DTRACE_PROBE(__io_##name);
+
+#define        DTRACE_IO1(name, type1, arg1)                                   \
+       DTRACE_PROBE1(__io_##name, type1, arg1);
+
+#define        DTRACE_IO2(name, type1, arg1, type2, arg2)                      \
+       DTRACE_PROBE2(__io_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_IO3(name, type1, arg1, type2, arg2, type3, arg3) \
+       DTRACE_PROBE3(__io_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_IO4(name, type1, arg1, type2, arg2,                      \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__io_##name, type1, arg1, type2, arg2,            \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_ISCSI_2(name, type1, arg1, type2, arg2)                  \
+       DTRACE_PROBE2(__iscsi_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_ISCSI_3(name, type1, arg1, type2, arg2, type3, arg3)     \
+       DTRACE_PROBE3(__iscsi_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_ISCSI_4(name, type1, arg1, type2, arg2,                  \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__iscsi_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_ISCSI_5(name, type1, arg1, type2, arg2,                  \
+    type3, arg3, type4, arg4, type5, arg5)                             \
+       DTRACE_PROBE5(__iscsi_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4, type5, arg5);
+
+#define        DTRACE_ISCSI_6(name, type1, arg1, type2, arg2,                  \
+    type3, arg3, type4, arg4, type5, arg5, type6, arg6)                        \
+       DTRACE_PROBE6(__iscsi_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6);
+
+#define        DTRACE_ISCSI_7(name, type1, arg1, type2, arg2,                  \
+    type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7)   \
+       DTRACE_PROBE7(__iscsi_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6,         \
+           type7, arg7);
+
+#define        DTRACE_ISCSI_8(name, type1, arg1, type2, arg2,                  \
+    type3, arg3, type4, arg4, type5, arg5, type6, arg6,                        \
+    type7, arg7, type8, arg8)                                          \
+       DTRACE_PROBE8(__iscsi_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6,         \
+           type7, arg7, type8, arg8);
+
+#define        DTRACE_NFSV3_3(name, type1, arg1, type2, arg2,                  \
+    type3, arg3)                                                       \
+       DTRACE_PROBE3(__nfsv3_##name, type1, arg1, type2, arg2,         \
+           type3, arg3);
+#define        DTRACE_NFSV3_4(name, type1, arg1, type2, arg2,                  \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__nfsv3_##name, type1, arg1, type2, arg2,         \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_NFSV4_1(name, type1, arg1) \
+       DTRACE_PROBE1(__nfsv4_##name, type1, arg1);
+
+#define        DTRACE_NFSV4_2(name, type1, arg1, type2, arg2) \
+       DTRACE_PROBE2(__nfsv4_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_NFSV4_3(name, type1, arg1, type2, arg2, type3, arg3) \
+       DTRACE_PROBE3(__nfsv4_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_SMB_1(name, type1, arg1) \
+       DTRACE_PROBE1(__smb_##name, type1, arg1);
+
+#define        DTRACE_SMB_2(name, type1, arg1, type2, arg2) \
+       DTRACE_PROBE2(__smb_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_IP(name)                                         \
+       DTRACE_PROBE(__ip_##name);
+
+#define        DTRACE_IP1(name, type1, arg1)                                   \
+       DTRACE_PROBE1(__ip_##name, type1, arg1);
+
+#define        DTRACE_IP2(name, type1, arg1, type2, arg2)                      \
+       DTRACE_PROBE2(__ip_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_IP3(name, type1, arg1, type2, arg2, type3, arg3) \
+       DTRACE_PROBE3(__ip_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_IP4(name, type1, arg1, type2, arg2,                      \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__ip_##name, type1, arg1, type2, arg2,            \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_IP5(name, type1, arg1, type2, arg2,                      \
+    type3, arg3, type4, arg4, type5, arg5)                             \
+       DTRACE_PROBE5(__ip_##name, type1, arg1, type2, arg2,            \
+           type3, arg3, type4, arg4, type5, arg5);
+
+#define        DTRACE_IP6(name, type1, arg1, type2, arg2,                      \
+    type3, arg3, type4, arg4, type5, arg5, type6, arg6)                        \
+       DTRACE_PROBE6(__ip_##name, type1, arg1, type2, arg2,            \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6);
+
+#define        DTRACE_IP7(name, type1, arg1, type2, arg2, type3, arg3,         \
+    type4, arg4, type5, arg5, type6, arg6, type7, arg7)                        \
+       DTRACE_PROBE7(__ip_##name, type1, arg1, type2, arg2,            \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6,         \
+           type7, arg7);
+
+#define        DTRACE_TCP(name)                                                \
+       DTRACE_PROBE(__tcp_##name);
+
+#define        DTRACE_TCP1(name, type1, arg1)                                  \
+       DTRACE_PROBE1(__tcp_##name, type1, arg1);
+
+#define        DTRACE_TCP2(name, type1, arg1, type2, arg2)                     \
+       DTRACE_PROBE2(__tcp_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_TCP3(name, type1, arg1, type2, arg2, type3, arg3)        \
+       DTRACE_PROBE3(__tcp_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_TCP4(name, type1, arg1, type2, arg2,                     \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__tcp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_TCP5(name, type1, arg1, type2, arg2,                     \
+    type3, arg3, type4, arg4, type5, arg5)                             \
+       DTRACE_PROBE5(__tcp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5);
+
+#define        DTRACE_TCP6(name, type1, arg1, type2, arg2,                     \
+    type3, arg3, type4, arg4, type5, arg5, type6, arg6)                        \
+       DTRACE_PROBE6(__tcp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6);
+
+#define        DTRACE_UDP(name)                                                \
+       DTRACE_PROBE(__udp_##name);
+
+#define        DTRACE_UDP1(name, type1, arg1)                                  \
+       DTRACE_PROBE1(__udp_##name, type1, arg1);
+
+#define        DTRACE_UDP2(name, type1, arg1, type2, arg2)                     \
+       DTRACE_PROBE2(__udp_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_UDP3(name, type1, arg1, type2, arg2, type3, arg3)        \
+       DTRACE_PROBE3(__udp_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_UDP4(name, type1, arg1, type2, arg2,                     \
+    type3, arg3, type4, arg4)                                          \
+       DTRACE_PROBE4(__udp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_UDP5(name, type1, arg1, type2, arg2,                     \
+    type3, arg3, type4, arg4, type5, arg5)                             \
+       DTRACE_PROBE5(__udp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5);
+
+
+#define        DTRACE_SYSEVENT2(name, type1, arg1, type2, arg2)                \
+       DTRACE_PROBE2(__sysevent_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_XPV(name)                                                \
+       DTRACE_PROBE(__xpv_##name);
+
+#define        DTRACE_XPV1(name, type1, arg1)                                  \
+       DTRACE_PROBE1(__xpv_##name, type1, arg1);
+
+#define        DTRACE_XPV2(name, type1, arg1, type2, arg2)                     \
+       DTRACE_PROBE2(__xpv_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_XPV3(name, type1, arg1, type2, arg2, type3, arg3)        \
+       DTRACE_PROBE3(__xpv_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_XPV4(name, type1, arg1, type2, arg2, type3, arg3,        \
+           type4, arg4)                                                \
+       DTRACE_PROBE4(__xpv_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_FC_1(name, type1, arg1) \
+       DTRACE_PROBE1(__fc_##name, type1, arg1);
+
+#define        DTRACE_FC_2(name, type1, arg1, type2, arg2) \
+       DTRACE_PROBE2(__fc_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_FC_3(name, type1, arg1, type2, arg2, type3, arg3) \
+       DTRACE_PROBE3(__fc_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_FC_4(name, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \
+       DTRACE_PROBE4(__fc_##name, type1, arg1, type2, arg2, type3, arg3, \
+           type4, arg4);
+
+#define        DTRACE_FC_5(name, type1, arg1, type2, arg2, type3, arg3,        \
+           type4, arg4, type5, arg5)                                   \
+       DTRACE_PROBE5(__fc_##name, type1, arg1, type2, arg2, type3, arg3, \
+           type4, arg4, type5, arg5);
+
+#define        DTRACE_SRP_1(name, type1, arg1)                                 \
+       DTRACE_PROBE1(__srp_##name, type1, arg1);
+
+#define        DTRACE_SRP_2(name, type1, arg1, type2, arg2)                    \
+       DTRACE_PROBE2(__srp_##name, type1, arg1, type2, arg2);
+
+#define        DTRACE_SRP_3(name, type1, arg1, type2, arg2, type3, arg3)       \
+       DTRACE_PROBE3(__srp_##name, type1, arg1, type2, arg2, type3, arg3);
+
+#define        DTRACE_SRP_4(name, type1, arg1, type2, arg2, type3, arg3,       \
+           type4, arg4)                                                \
+       DTRACE_PROBE4(__srp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4);
+
+#define        DTRACE_SRP_5(name, type1, arg1, type2, arg2, type3, arg3,       \
+           type4, arg4, type5, arg5)                                   \
+       DTRACE_PROBE5(__srp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5);
+
+#define        DTRACE_SRP_6(name, type1, arg1, type2, arg2, type3, arg3,       \
+           type4, arg4, type5, arg5, type6, arg6)                      \
+       DTRACE_PROBE6(__srp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6);
+
+#define        DTRACE_SRP_7(name, type1, arg1, type2, arg2, type3, arg3,       \
+           type4, arg4, type5, arg5, type6, arg6, type7, arg7)         \
+       DTRACE_PROBE7(__srp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7);
+
+#define        DTRACE_SRP_8(name, type1, arg1, type2, arg2, type3, arg3,       \
+           type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8) \
+       DTRACE_PROBE8(__srp_##name, type1, arg1, type2, arg2,           \
+           type3, arg3, type4, arg4, type5, arg5, type6, arg6,         \
+           type7, arg7, type8, arg8);
+
+extern const char *sdt_prefix;
+
+typedef struct sdt_probedesc {
+       char                    *sdpd_name;     /* name of this probe */
+       unsigned long           sdpd_offset;    /* offset of call in text */
+       struct sdt_probedesc    *sdpd_next;     /* next static probe */
+} sdt_probedesc_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SDT_H_ */
index dc24dec6023292ac6f1bd484ce506074d3e53566..3fcaedfb970de98b05755ba27f798f8a780cab77 100644 (file)
@@ -1764,6 +1764,8 @@ config PROFILING
          Say Y here to enable the extended profiling support mechanisms used
          by profilers such as OProfile.
 
+source "kernel/dtrace/Kconfig"
+
 #
 # Place an empty function call at each tracepoint site. Can be
 # dynamically changed for a probe function.
index 2115055faeac948bd164c9e8d574795f557f02a5..da860d2f58c8f40da138602fb3c377eb7013834b 100644 (file)
@@ -81,6 +81,7 @@
 #include <linux/integrity.h>
 #include <linux/proc_ns.h>
 #include <linux/io.h>
+#include <linux/sdt.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -673,6 +674,10 @@ asmlinkage __visible void __init start_kernel(void)
 
        ftrace_init();
 
+#if defined(CONFIG_DT_SDT) || defined(CONFIG_DT_SDT_MODULE)
+       dtrace_register_builtins();
+#endif
+
        /* Do the rest non-__init'ed, we're now alive */
        rest_init();
 }
index 60c302cfb4d3cbb976f0b2d69f28a96899b1d4ce..6e6e12873c437de3f51a8cf285a8a32f1fece68c 100644 (file)
@@ -98,6 +98,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_JUMP_LABEL) += jump_label.o
 obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
 obj-$(CONFIG_TORTURE_TEST) += torture.o
+obj-$(CONFIG_DTRACE) += dtrace/
 
 $(obj)/configs.o: $(obj)/config_data.h
 
diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig
new file mode 100644 (file)
index 0000000..72a1f2a
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# DTrace Configuration
+#
+
+menuconfig DTRACE
+       bool "DTrace (Dynamic Tracing) Support"
+       default y
+       depends on X86_64
+       select KALLSYMS
+       help
+         To be written.
+
+if DTRACE
+
+config DT_CORE
+       tristate "DTrace core"
+       default m
+       help
+         To be written.
+
+if DT_CORE
+
+config DT_FASTTRAP
+       tristate "Fasttrap Tracing"
+       default m
+       help
+         To be written.
+
+config DT_FBT
+       tristate "Function Boundary Tracing"
+       default m
+       help
+         To be written.
+
+config DT_LOCKSTAT
+       tristate "Lock Statistics"
+       default m
+       help
+         To be written.
+
+config DT_PROFILE
+       tristate "Profile Interrupt Tracing"
+       default m
+       help
+         To be written.
+
+config DT_SDT
+       tristate "Statically Defined Tracing"
+       default m
+       select KALLSYMS
+       help
+         To be written.
+
+config DT_SYSTRACE
+       tristate "System Call Tracing"
+       default m
+       help
+         To be written.
+
+config DT_DEBUG
+       bool "DTrace debugging"
+       default m
+       help
+         This controls the inclusion of various piece of code that perform
+         internal checks within the DTrace core.  It also enables all the
+         assertions within the DTrace code.
+
+endif  # DT_CORE
+
+endif   #DTRACE
diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile
new file mode 100644 (file)
index 0000000..b200a7f
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# Makefile for DTrace
+#
+
+obj-$(CONFIG_DT_CORE)          += dtrace.o
+obj-$(CONFIG_DT_FASTTRAP)      += fasttrap.o
+obj-$(CONFIG_DT_FBT)           += fbt.o
+obj-$(CONFIG_DT_LOCKSTAT)      += lockstat.o
+obj-$(CONFIG_DT_PROFILE)       += profile.o
+obj-$(CONFIG_DT_SDT)           += sdt.o sdt_register.o
+obj-$(CONFIG_DT_SYSTRACE)      += systrace.o
+
+dtrace-y                       := dtrace_mod.o dtrace_dev.o \
+                                  dtrace_asm.o dtrace_isa.o \
+                                  dtrace_actdesc.o dtrace_anon.o \
+                                  dtrace_buffer.o dtrace_dif.o dtrace_dof.o \
+                                  dtrace_ecb.o dtrace_enable.o \
+                                  dtrace_fmt.o dtrace_hash.o dtrace_helper.o \
+                                  dtrace_match.o dtrace_priv.o \
+                                  dtrace_probe.o dtrace_probe_ctx.o \
+                                  dtrace_ptofapi.o dtrace_predicate.o \
+                                  dtrace_spec.o dtrace_state.o dtrace_util.o \
+                                  cyclic.o
+fasttrap-y                     := fasttrap_mod.o fasttrap_dev.o
+fbt-y                          := fbt_mod.o fbt_dev.o
+lockstat-y                     := lockstat_mod.o lockstat_dev.o
+profile-y                      := profile_mod.o profile_dev.o
+sdt-y                          := sdt_mod.o sdt_dev.o
+systrace-y                     := systrace_mod.o systrace_dev.o
diff --git a/kernel/dtrace/cyclic.c b/kernel/dtrace/cyclic.c
new file mode 100644 (file)
index 0000000..881b30a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * FILE:       cyclic.c
+ * DESCRIPTION:        Cyclic implementation
+ *
+ * Copyright (C) 2010 Oracle Corporation
+ */
+
+#include "cyclic.h"
+
+/*
+ * Add a new cyclic to the system.
+ */
+cyclic_id_t cyclic_add(cyc_handler_t *hdlr, cyc_time_t *when)
+{
+       return 0;
+}
+
+/*
+ * Remove the specific cyclic from the system.
+ */
+void cyclic_remove(cyclic_id_t id)
+{
+}
diff --git a/kernel/dtrace/cyclic.h b/kernel/dtrace/cyclic.h
new file mode 100644 (file)
index 0000000..c4b5057
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _CYCLIC_H_
+#define _CYCLIC_H_
+
+#include <linux/ktime.h>
+#include <linux/types.h>
+
+#define CY_LOW_LEVEL   0
+#define CY_LOCK_LEVEL  1
+#define CY_HIGH_LEVEL  2
+#define CY_SOFT_LEVELS 2
+#define CY_LEVELS      3
+
+typedef uintptr_t      cyclic_id_t;
+typedef uint16_t       cyc_level_t;
+typedef void           (*cyc_func_t)(void *);
+
+#define CYCLIC_NONE    ((cyclic_id_t)0)
+
+typedef struct cyc_handler {
+       cyc_func_t cyh_func;
+       void *cyh_arg;
+       cyc_level_t cyh_level;
+} cyc_handler_t;
+
+typedef struct cyc_time {
+       ktime_t cyt_when;
+       ktime_t cyt_interval;
+} cyc_time_t;
+
+extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
+extern void cyclic_remove(cyclic_id_t);
+
+#endif /* _CYCLIC_H_ */
diff --git a/kernel/dtrace/dtrace_ioctl.h b/kernel/dtrace/dtrace_ioctl.h
new file mode 100644 (file)
index 0000000..dc21937
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _DTRACE_IOCTL_H_
+#define _DTRACE_IOCTL_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define DTRACEIOC              0xd4
+#define DTRACEIOC_PROVIDER     _IOR(DTRACEIOC, 1, dtrace_providerdesc_t)
+#define DTRACEIOC_PROBES       _IOR(DTRACEIOC, 2, dtrace_probedesc_t)
+#define DTRACEIOC_BUFSNAP      _IOR(DTRACEIOC, 4, dtrace_bufdesc_t)
+#define DTRACEIOC_PROBEMATCH   _IOR(DTRACEIOC, 5, dtrace_probedesc_t)
+#define DTRACEIOC_ENABLE       _IOW(DTRACEIOC, 6, void *)
+#define DTRACEIOC_AGGSNAP      _IOR(DTRACEIOC, 7, dtrace_bufdesc_t)
+#define DTRACEIOC_EPROBE       _IOW(DTRACEIOC, 8, dtrace_eprobedesc_t)
+#define DTRACEIOC_PROBEARG     _IOR(DTRACEIOC, 9, dtrace_argdesc_t)
+#define DTRACEIOC_CONF         _IOR(DTRACEIOC, 10, dtrace_conf_t)
+#define DTRACEIOC_STATUS       _IOR(DTRACEIOC, 11, dtrace_status_t)
+#define DTRACEIOC_GO           _IOW(DTRACEIOC, 12, processorid_t)
+#define DTRACEIOC_STOP         _IOW(DTRACEIOC, 13, processorid_t)
+#define DTRACEIOC_AGGDESC      _IOR(DTRACEIOC, 15, dtrace_aggdesc_t)
+#define DTRACEIOC_FORMAT       _IOR(DTRACEIOC, 16, dtrace_fmtdesc_t)
+#define DTRACEIOC_DOFGET       _IOR(DTRACEIOC, 17, dof_hdr_t)
+#define DTRACEIOC_REPLICATE    _IOR(DTRACEIOC, 18, void *)
+
+#define DTRACEHIOC             0xd8
+#define DTRACEHIOC_ADD         _IOW(DTRACEHIOC, 1, int)
+#define DTRACEHIOC_REMOVE      _IOW(DTRACEHIOC, 2, int)
+#define DTRACEHIOC_ADDDOF      _IOW(DTRACEHIOC, 3, dof_helper_t)
+
+#endif
diff --git a/kernel/dtrace/sdt_register.c b/kernel/dtrace/sdt_register.c
new file mode 100644 (file)
index 0000000..2a00c98
--- /dev/null
@@ -0,0 +1,118 @@
+/* register static dtrace probe points */
+
+#define DEBUG  1
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sdt.h>
+#include <linux/slab.h>
+#include <asm-generic/bitsperlong.h>
+
+///#include <sys/types.h>
+///#include <sys/param.h>
+///#include <sys/sysmacros.h>
+///#include <sys/systm.h>
+///#include <sys/user.h>
+///#include <sys/bootconf.h>
+///#include <sys/modctl.h>
+///#include <sys/elf.h>
+///#include <sys/kobj.h>
+///#include <sys/kobj_impl.h>
+///#include "reloc.h"
+
+#define LOAD_ADDR      0xffffffff00000000ULL   /* temporary */
+
+#define        SDT_NOP         0x90
+#define        SDT_NOPS        5
+
+const char             *sdt_prefix = "__dtrace_probe_";
+
+static struct module   *kernmod; /* for kernel builtins; TBD: temporary ??? */
+
+static int sdt_reloc_resolve(struct module *mp, char *symname, uint8_t *instr)
+{
+       sdt_probedesc_t *sdp;
+       int i;
+
+       /*
+        * The "statically defined tracing" (SDT) provider for DTrace uses
+        * a mechanism similar to TNF, but somewhat simpler.  (Surprise,
+        * surprise.)  The SDT mechanism works by replacing calls to the
+        * undefined routine __dtrace_probe_[name] with nop instructions.
+        * The relocations are logged, and SDT itself will later patch the
+        * running binary appropriately.
+        */
+       if (strncmp(symname, sdt_prefix, strlen(sdt_prefix)) != 0)
+               return 1;
+
+       symname += strlen(sdt_prefix);
+
+       sdp = kmalloc(sizeof(sdt_probedesc_t), GFP_KERNEL);
+       if (!sdp)
+               return 1;
+       sdp->sdpd_name = kmalloc(strlen(symname) + 1, GFP_KERNEL);
+       if (!sdp->sdpd_name) {
+               kfree(sdp);
+               return 1;
+       }
+       memcpy(sdp->sdpd_name, symname, strlen(symname) + 1);
+
+       /* TBD: use a kernel list? */
+       sdp->sdpd_offset = (uintptr_t)instr;
+       sdp->sdpd_next = mp->sdt_probes;
+       mp->sdt_probes = sdp;
+
+       DPRINTK("sdt_probes -> 0x%p\n", mp->sdt_probes);
+       DPRINTK("this probe: instr offset=0x%lx, next ptr=0x%p, probe_name=%s\n",
+               sdp->sdpd_offset, sdp->sdpd_next, sdp->sdpd_name);
+#if 0
+       // NOT YET SAFE, since instr is relative, not absolute //
+       /* TBD: need a safer write-to-exec-memory ? */
+       for (i = 0; i < SDT_NOPS; i++)
+               instr[i - 1] = SDT_NOP;
+#endif
+
+       return 0;
+}
+
+void dtrace_register_builtins(void)
+{
+       unsigned long cnt;
+       struct reloc_info *ri = (struct reloc_info *)&dtrace_relocs;
+       void *nextri;
+
+       kernmod = kzalloc(sizeof(struct module), GFP_KERNEL);
+       if (!kernmod) {
+               printk(KERN_WARNING
+                       "%s: cannot allocate kernel builtin module memory\n",
+                       __func__);
+               return;
+       }
+
+       DPRINTK("%lu SDT relocation entries beg. @0x%p\n",
+               dtrace_relocs_count, &dtrace_relocs);
+
+       if (dtrace_relocs_count == 0)
+               return;
+
+       for (cnt = 0; cnt < dtrace_relocs_count; cnt++) {
+               DPRINTK("SDT relocs [%lu]: "
+                       "probe_offset=0x%lx, section_base=0x%lx, "
+                       "name_len=0x%lx, probe_name=%s\n",
+                       cnt, ri->probe_offset, ri->section_base,
+                       ri->probe_name_len, ri->probe_name);
+               if (sdt_reloc_resolve(kernmod, ri->probe_name,
+                   (uint8_t *)ri->probe_offset))
+                       printk(KERN_WARNING "%s: cannot resolve %s\n",
+                               __func__, ri->probe_name);
+
+               nextri = (void *)ri + sizeof(struct reloc_info)
+                       + roundup(ri->probe_name_len, BITS_PER_LONG / 8);
+               ri = nextri;
+               DPRINTK("SDT relocs: next entry at 0x%p\n", ri);
+       }
+
+#if 0
+       dtrace_module_loaded(kernmod);
+#endif
+}
index 2016a64497ab1cca3074a73a76057ff02947b3a0..7fe1c538a2579b5546f4251ede5833ee04eae14c 100644 (file)
@@ -3,6 +3,7 @@
 # the kernel for the build process.
 # ---------------------------------------------------------------------------
 # kallsyms:      Find all symbols in vmlinux
+# dtrace_relocs: find and save all __dtrace_probe_ calling probepoints
 # pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
@@ -11,6 +12,7 @@
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
+hostprogs-$(CONFIG_DTRACE)       += dtrace_relocs
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
diff --git a/scripts/dtrace_relocs.c b/scripts/dtrace_relocs.c
new file mode 100644 (file)
index 0000000..a220d7b
--- /dev/null
@@ -0,0 +1,398 @@
+/* Generate assembler source containing __dtrace_probe_* calls (reloc info)
+ *
+ * Based on scripts/kallsyms.c
+ * Copyright 2002       by Kai Germaschewski
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: dtrace_relocs input_file_text output_file_elf
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <elf.h>
+
+struct sym_entry {
+       unsigned long long addr;
+       unsigned char is_section;
+       unsigned char section_used;
+       int section_index;
+       unsigned long long section_base;
+       unsigned int len;
+       char *sym;
+};
+
+struct text_range {
+       const char *stext, *etext;
+       unsigned long long start, end;
+};
+
+static unsigned long long _text; // TBD: need this from System.map
+
+static struct sym_entry *table;
+static unsigned int table_size, table_cnt;
+static int this_section_index;
+static unsigned long long this_section_addr;
+static int relocs_count;
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: dtrace_relocs input_file_text output_file_elf\n");
+       exit(1);
+}
+
+// skip over whitespace (spaces or tabs)
+static char *deblank(char *str)
+{
+       while (*str == ' ' || *str == '\t')
+                       str++;
+       return str;
+}
+
+static int find_section(char *sect, int sectlen)
+{
+       int ix;
+       struct sym_entry *sym = table;
+
+#if 0
+       fprintf(stderr, "%s: search for sect=<%s>, sectlen=%d:\n",
+               __func__, sect, sectlen);
+#endif
+
+       for (ix = 0; ix < table_cnt; ix++, sym++) {
+#if 0
+               if (sym->is_section && strlen(sym->sym) == sectlen)
+                       fprintf(stderr, "%s: ix=%d, symlen=%d, symname=<%s>\n",
+                               __func__, ix, strlen(sym->sym), sym->sym);
+#endif
+               if (sym->is_section && strlen(sym->sym) == sectlen &&
+                       strncmp(sym->sym, sect, sectlen) == 0) {
+                               sym->section_used = true;
+                               this_section_addr = sym->addr;
+                               return sym->section_index;
+               }
+       }
+
+       return -1;
+}
+
+static int get_this_section(char buf[500])
+{
+       char *sect;
+       int sectlen;
+       int sect_index;
+
+       if (strncmp(buf, "RELOCATION RECORDS FOR [", 24) != 0) {
+               fprintf(stderr, "Bad relocation header: %s\n", buf);
+               exit(2);
+       }
+
+       sect = buf + 24;
+       sectlen = strlen(sect); // includes a trailing newline
+#if 0
+       fprintf(stderr, "%s: sect=<%s>, sectlen=%d\n",
+               __func__, sect, sectlen);
+#endif
+       if (*(sect + sectlen - 3) != ']' || *(sect + sectlen - 2) != ':') {
+               fprintf(stderr, "Bad relocation header: %s\n", buf);
+               exit(2);
+       }
+       *(sect + sectlen - 3) = '\0';
+       sectlen -= 3;   // drop the "]:\n"
+#if 0
+       fprintf(stderr, "%s: isolated section name=<%s>\n", __func__, sect);
+#endif
+       sect_index = find_section(sect, sectlen);
+       if (sect_index < 0) {
+               fprintf(stderr, "Bad section name in relocation header: %s\n",
+                       sect);
+               exit(2);
+       }
+
+       return sect_index;
+}
+
+/*
+ * scans 2 lines of section info;
+ * first line is already in buf;
+ * second line is noise for now;
+ */
+static int get_section_info(FILE *fin, char buf[500], struct sym_entry *sect)
+{
+       int rc;
+       int sect_index;
+       char sect_name[200], sect_align[100];
+       unsigned long sect_size, file_offset;
+       unsigned long long vma, lma;
+       char sect_flags[500];
+       char *flags;
+
+       rc = sscanf(buf, " %d %s %lx %llx %llx %lx %s \n",
+               &sect_index, (char *)&sect_name, &sect_size, &vma, &lma,
+               &file_offset, (char *)&sect_align);
+#ifdef SCANF
+       fprintf(stderr, "%s: sscanf.1 rc= %d\n", __func__, rc);
+#endif
+       if (rc != 7)
+               return -1;
+
+       if (!fgets(sect_flags, sizeof(sect_flags), fin))
+               return -1;
+
+#ifdef SCANF
+       fprintf(stderr, "%s: fgets.2 read=<%s>", __func__, sect_flags);
+#endif
+       flags = deblank(sect_flags);
+
+       sect->addr = file_offset;
+       sect->is_section = true;
+       sect->section_used = false;
+       sect->section_index = sect_index;
+       sect->len = sect_size;
+       sect->sym = malloc(strlen(sect_name));
+       if (!sect->sym) {
+               fprintf(stderr, "relocs failure: "
+                       "unable to allocate required amount of memory\n");
+               exit(1);
+       }
+       strcpy((char *)sect->sym, sect_name);
+
+#ifdef INFO
+       fprintf(stderr, "sect: index=%d, name=%s, addr/offset=0x%llx, sect_size=0x%x, align=%s, vma=0x%llx, lma=0x%llx, flags=%s\n",
+               sect_index, sect->sym, sect->addr, sect->len, sect_align,
+               vma, lma, flags);
+#endif
+
+       return 0;
+}
+
+static int get_symbol_info(char buf[500], struct sym_entry *s)
+{
+       int rc;
+       unsigned long long relo_offset, pp_offset;
+       char relo_type[200];
+       char probepoint[200];
+
+       //rc = sscanf(buf, " %llx %s %200s-%llx \n",
+       rc = sscanf(buf, " %llx %s %[^ -]-%llx \n",
+               &relo_offset, (char *)&relo_type,
+               (char *)&probepoint, &pp_offset);
+#ifdef SCANF
+       fprintf(stderr, "%s: sscanf.1 rc= %d\n", __func__, rc);
+#endif
+       if (rc != 4)
+               return -1;
+
+       s->addr = relo_offset;
+       s->len = strlen(probepoint);
+       s->is_section = false;
+       s->section_used = false;
+       s->section_index = -1;
+       s->section_base = this_section_addr;
+       s->sym = malloc(s->len + 1);
+       if (!s->sym) {
+               fprintf(stderr, "relocs failure: "
+                       "unable to allocate required amount of memory\n");
+               exit(1);
+       }
+       strcpy((char *)s->sym, probepoint);
+
+#ifdef INFO
+       fprintf(stderr, "sym: addr/offset=0x%llx, strlen=%d, type=%s, name=%s\n",
+               s->addr, s->len, relo_type, s->sym);
+#endif
+
+       relocs_count++;
+       return 0;
+}
+
+static void read_info(FILE *fin)
+{
+       char buf[500];
+       bool in_sections = false, in_symbols = false;
+
+       while (!feof(fin)) {
+               if (table_cnt >= table_size) {
+                       table_size += 10000;
+                       table = realloc(table, sizeof(*table) * table_size);
+                       if (!table) {
+                               fprintf(stderr, "out of memory\n");
+                               exit(1);
+                       }
+               }
+
+               if (!fgets(buf, sizeof(buf), fin))
+                       break;
+#ifdef SCANF
+               fprintf(stderr, "dtr: buf=<%s>\n", buf);
+#endif
+
+               if (strncmp(buf, "Sections:", 9) == 0) {
+                       in_sections = true;
+                       continue;
+               }
+               if (strncmp(buf, "RELOCATION RECORDS", 11) == 0) {
+                       in_sections = false;
+                       in_symbols = true;
+                       // isolate & look up section name, get its index
+                       // this call also sets 'this_section_addr'
+                       this_section_index = get_this_section(buf);
+                       continue;
+               }
+
+               if (in_sections) {
+                       if (strncmp(buf, "Idx ", 4) != 0)
+                               if (get_section_info(fin, buf, &table[table_cnt]) == 0)
+                                       table_cnt++;
+                       continue;
+               }
+
+               if (in_symbols)
+                       if (get_symbol_info(buf, &table[table_cnt]) == 0)
+                               table_cnt++;
+       }
+}
+
+static void output_label(FILE *fout, char *label)
+{
+       fprintf(fout, ".globl %s\n", label);
+       fprintf(fout, "\tALGN\n");
+       fprintf(fout, "%s:\n", label);
+}
+
+static void write_relocs(FILE *fout)
+{
+       unsigned int i;
+       int reloc_count = 0;
+
+       fprintf(fout, "#include <asm/types.h>\n");
+       fprintf(fout, "#if BITS_PER_LONG == 64\n");
+       fprintf(fout, "#define PTR .quad\n");
+       fprintf(fout, "#define ALGN .align 8\n");
+       fprintf(fout, "#else\n");
+       fprintf(fout, "#define PTR .long\n");
+       fprintf(fout, "#define ALGN .align 4\n");
+       fprintf(fout, "#endif\n");
+
+       fprintf(fout, "\t.section .rodata, \"a\"\n");
+       fprintf(fout, "\n");
+
+       output_label(fout, "dtrace_relocs_count");
+       fprintf(fout, "\tPTR\t%d\n", relocs_count);
+       fprintf(fout, "\n");
+
+       /*
+        * Provide proper symbols relocatability by their '_text'
+        * relativeness.  The symbol names cannot be used to construct
+        * normal symbol references as the list of symbols contains
+        * symbols that are declared static and are private to their
+        * .o files.  This prevents .tmp_kallsyms.o or any other
+        * object from referencing them.
+        */
+       output_label(fout, "dtrace_relocs");
+       for (i = 0; i < table_cnt; i++) {
+#if 0
+               if (_text <= table[i].addr)
+                       fprintf(fout, "\tPTR\t_text + %#llx\n",
+                               table[i].addr - _text);
+               else
+                       fprintf(fout, "\tPTR\t_text - %#llx\n",
+                               _text - table[i].addr);
+#endif
+               // for reloc symbols (not sections):
+               // print symbol relative address, section base address,
+               // call target string length, call target string/name;
+               // TBD: figure out how to find the next 4-tuple;
+               if (!table[i].is_section) {
+                       fprintf(fout, "\tPTR\t%#llx\n", table[i].addr);
+                       fprintf(fout, "\tPTR\t%#llx\n", table[i].section_base);
+                       fprintf(fout, "\tPTR\t%d\n", table[i].len);
+                       fprintf(fout, "\t.asciz\t\"%s\"\n", table[i].sym);
+                       fprintf(fout, "\tALGN\n");
+                       reloc_count++;
+               }
+       }
+
+       fprintf(fout, "\n");
+
+       if (reloc_count != relocs_count) {
+               fprintf(fout, "relocs error: reloc counters do not agree (%d vs. %d\n)",
+                       relocs_count, reloc_count);
+               exit(3);
+       }
+}
+
+#if 0
+/* guess for "linker script provide" symbol */
+static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
+{
+       const char *symbol = (char *)se->sym + 1;
+       int len = se->len - 1;
+
+       if (len < 8)
+               return 0;
+
+       if (symbol[0] != '_' || symbol[1] != '_')
+               return 0;
+
+       /* __start_XXXXX */
+       if (!memcmp(symbol + 2, "start_", 6))
+               return 1;
+
+       /* __stop_XXXXX */
+       if (!memcmp(symbol + 2, "stop_", 5))
+               return 1;
+
+       /* __end_XXXXX */
+       if (!memcmp(symbol + 2, "end_", 4))
+               return 1;
+
+       /* __XXXXX_start */
+       if (!memcmp(symbol + len - 6, "_start", 6))
+               return 1;
+
+       /* __XXXXX_end */
+       if (!memcmp(symbol + len - 4, "_end", 4))
+               return 1;
+
+       return 0;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+       char *infile, *outfile;
+       FILE *fin, *fout;
+
+
+       if (argc != 3)
+               usage();
+
+       infile = argv[1];
+       outfile = argv[2];
+
+       fin = fopen(infile, "r");
+       if (!fin) {
+               fprintf(stderr, "relocs: cannot open input file '%s'\n",
+                       infile);
+               exit(2);
+       }
+       fout = fopen(outfile, "w");
+       if (!fout) {
+               fprintf(stderr, "relocs: cannot create output file '%s'\n",
+                       outfile);
+               exit(2);
+       }
+
+       read_info(fin);
+       fclose(fin);
+
+       write_relocs(fout);
+       fclose(fout);
+
+       return 0;
+}