From 764dfba3497ae7c449555bdd42e804121c0ca188 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Fri, 11 Nov 2011 02:34:04 -0500 Subject: [PATCH] dtrace: fix resolving addresses of relocation records for SDT probe points 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 --- arch/x86/include/asm/alternative.h | 1 + arch/x86/kernel/alternative.c | 2 +- include/linux/sdt.h | 2 ++ kernel/dtrace/sdt_register.c | 42 +++++++++++++----------------- scripts/dtrace_relocs.c | 10 ++----- 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index ba32af062f61..7d2e9a5175d0 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -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); /* diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index aef653193160..5e4c38b20a0a 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -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; diff --git a/include/linux/sdt.h b/include/linux/sdt.h index c339478653ce..9484ffb678d7 100644 --- a/include/linux/sdt.h +++ b/include/linux/sdt.h @@ -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 diff --git a/kernel/dtrace/sdt_register.c b/kernel/dtrace/sdt_register.c index dad9cc34b4c9..e2bdf3a90b58 100644 --- a/kernel/dtrace/sdt_register.c +++ b/kernel/dtrace/sdt_register.c @@ -5,38 +5,27 @@ #define DEBUG 1 #include +#include #include #include #include #include #include #include - -///#include -///#include -///#include -///#include -///#include -///#include -///#include -///#include -///#include -///#include -///#include "reloc.h" - -#define LOAD_ADDR 0xffffffff00000000ULL /* temporary */ +#include #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); diff --git a/scripts/dtrace_relocs.c b/scripts/dtrace_relocs.c index 339dc2032380..a34f0e7d50cb 100644 --- a/scripts/dtrace_relocs.c +++ b/scripts/dtrace_relocs.c @@ -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 -- 2.50.1