]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: fix resolving addresses of relocation records for SDT probe points
authorKris Van Hees <kris.van.hees@oracle.com>
Fri, 11 Nov 2011 07:34:04 +0000 (02:34 -0500)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:39:57 +0000 (22:39 +0100)
The addresses were being calculated based on the wrong starting point (_stext
whereas it ought to be _text), and the base was not taken into account.
Fixed the writing of NOPs in the location of the probe point calls, since
the existing case was causing kernel paging faults.  Made the add_nops()
function in alternative.c non-static so it can be used in sdt_register.
Use add_nops() to select the most appropriate NOP sequence for replacing the
probe point call, and write the NOPs using text_poke().

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
arch/x86/include/asm/alternative.h
arch/x86/kernel/alternative.c
include/linux/sdt.h
kernel/dtrace/sdt_register.c
scripts/dtrace_relocs.c

index ba32af062f61d69164a792630e3257c8cdc6deb5..7d2e9a5175d0d3cd3d938f649542fb1660f7ba47 100644 (file)
@@ -245,6 +245,7 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
 #define __parainstructions_end NULL
 #endif
 
+extern void add_nops(void *insns, unsigned int len);
 extern void *text_poke_early(void *addr, const void *opcode, size_t len);
 
 /*
index aef65319316065eab845f35141682c3550f18a22..5e4c38b20a0a5de215d20031824924d11a245895 100644 (file)
@@ -242,7 +242,7 @@ void __init arch_init_ideal_nops(void)
 }
 
 /* Use this to add nops to a buffer, then text_poke the whole buffer. */
-static void __init_or_module add_nops(void *insns, unsigned int len)
+void __init_or_module add_nops(void *insns, unsigned int len)
 {
        while (len > 0) {
                unsigned int noplen = len;
index c339478653cecbd7dfb956dbdd002fcfcbedfa2e..9484ffb678d7df075aec3222fd781ab495562273 100644 (file)
@@ -435,6 +435,8 @@ typedef struct sdt_probedesc {
        struct sdt_probedesc    *sdpd_next;     /* next static probe */
 } sdt_probedesc_t;
 
+extern void dtrace_register_builtins(void);
+
 #ifdef __cplusplus
 }
 #endif
index dad9cc34b4c9db76f8cd233dde6e3fa1011ebe88..e2bdf3a90b5837a14d098b65a6de8a53b7c90eca 100644 (file)
@@ -5,38 +5,27 @@
 #define DEBUG  1
 
 #include <linux/kernel.h>
+#include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/sdt.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <asm-generic/bitsperlong.h>
 #include <asm-generic/sections.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 */
+#include <asm/alternative.h>
 
 #define        SDT_NOP         0x90
-#define        SDT_NOPS        5
+#define        SDT_NOP_SIZE    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)
+static int sdt_reloc_resolve(struct module *mp, char *symname,
+                            uintptr_t offset, uintptr_t base, void *nops)
 {
        sdt_probedesc_t *sdp;
-       int i;
+       uint8_t *instr;
 
        /*
         * The "statically defined tracing" (SDT) provider for DTrace uses
@@ -54,6 +43,7 @@ static int sdt_reloc_resolve(struct module *mp, char *symname, uint8_t *instr)
        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);
@@ -70,9 +60,7 @@ static int sdt_reloc_resolve(struct module *mp, char *symname, uint8_t *instr)
         * not be necessary.
         */
        /* convert relative instr to absolute */
-       if ((unsigned long)instr < 0x1000000000000000UL)
-               instr = (uint8_t *)((unsigned long)instr +
-                                       (unsigned long)_stext);
+       instr = (uint8_t *)((uintptr_t)_text + base + offset - 1);
 
        /* TBD: use a kernel list? */
        sdp->sdpd_offset = (uintptr_t)instr;
@@ -83,9 +71,10 @@ static int sdt_reloc_resolve(struct module *mp, char *symname, uint8_t *instr)
        DPRINTK("this probe: instr offset=0x%lx, next ptr=0x%p, probe_name=%s\n",
                sdp->sdpd_offset, sdp->sdpd_next, sdp->sdpd_name);
 
-       /* TBD: need a safer write-to-exec-memory ? */
-       for (i = 0; i < SDT_NOPS; i++)
-               instr[i - 1] = SDT_NOP;
+       mutex_lock(&text_mutex);
+       text_poke(instr, nops, SDT_NOP_SIZE);
+       mutex_unlock(&text_mutex);
+       DPRINTK(" %02x %02x %02x %02x %02x\n", instr[0], instr[1], instr[2], instr[3], instr[4]);
 
        return 0;
 }
@@ -95,6 +84,9 @@ void dtrace_register_builtins(void)
        unsigned long cnt;
        struct reloc_info *ri = (struct reloc_info *)&dtrace_relocs;
        void *nextri;
+       uint8_t nops[SDT_NOP_SIZE];
+
+       add_nops(nops, SDT_NOP_SIZE);
 
        kernmod = kzalloc(sizeof(struct module), GFP_KERNEL);
        if (!kernmod) {
@@ -119,7 +111,8 @@ void dtrace_register_builtins(void)
                        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))
+                                     ri->probe_offset, ri->section_base,
+                                     nops))
                        printk(KERN_WARNING "%s: cannot resolve %s\n",
                                __func__, ri->probe_name);
 
@@ -133,3 +126,4 @@ void dtrace_register_builtins(void)
        dtrace_module_loaded(kernmod);
 #endif
 }
+EXPORT_SYMBOL(dtrace_register_builtins);
index 339dc2032380fa8bb705f84f6ffffa47df4fb250..a34f0e7d50cbc01430737c7ae76baa3751bdd584 100644 (file)
@@ -32,7 +32,7 @@ struct text_range {
        unsigned long long start, end;
 };
 
-static unsigned long long _text, _stext;       // from System.map
+static unsigned long long _stext;      // from System.map
 
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
@@ -285,8 +285,6 @@ static void read_info(FILE *fin)
                        if (get_symbol_info(buf, &table[table_cnt]) == 0)
                                table_cnt++;
                        else {
-                               if (_text == 0)
-                                       get_text_addr(buf, "_text", &_text);
                                if (_stext == 0)
                                        get_text_addr(buf, "_stext", &_stext);
                        }
@@ -322,12 +320,8 @@ static void write_relocs(FILE *fout)
        fprintf(fout, "\tPTR\t%d\n", relocs_count);
        fprintf(fout, "\n");
 
-       fprintf(fout, "_text_\t= 0x%llx\n", _text);
-       fprintf(fout, "_stext_\t= 0x%llx\n", _stext);
-       fprintf(fout, "\n");
-
        /*
-        * Provide proper symbols relocatability by their '_text'
+        * Provide proper symbols relocatability by their '_stext'
         * 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