aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-11-15 02:39:05 -0500
committerSteven Rostedt <srostedt@redhat.com>2008-11-20 13:52:53 -0500
commit7cc45e64323c8a1042f56e6a8d1dc982f98d52a8 (patch)
tree4402eb9bdaca4087a92f5003cfa655e6293dc890
parentf48cb8b48b0b10025ca9c451b9b32cac3fcd33ba (diff)
powerpc/ppc32: ftrace, dynamic ftrace to handle modules
Impact: add ability to trace modules on 32 bit PowerPC This patch performs the necessary trampoline calls to handle modules with dynamic ftrace on 32 bit PowerPC. Signed-off-by: Steven Rostedt <srostedt@redhat.com>
-rw-r--r--arch/powerpc/include/asm/module.h5
-rw-r--r--arch/powerpc/kernel/ftrace.c101
-rw-r--r--arch/powerpc/kernel/module_32.c10
3 files changed, 109 insertions, 7 deletions
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index 340bc699b620..08454880a2c0 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -39,11 +39,14 @@ struct mod_arch_specific {
39 unsigned long tramp; 39 unsigned long tramp;
40#endif 40#endif
41 41
42#else 42#else /* powerpc64 */
43 /* Indices of PLT sections within module. */ 43 /* Indices of PLT sections within module. */
44 unsigned int core_plt_section; 44 unsigned int core_plt_section;
45 unsigned int init_plt_section; 45 unsigned int init_plt_section;
46#ifdef CONFIG_DYNAMIC_FTRACE
47 unsigned long tramp;
46#endif 48#endif
49#endif /* powerpc64 */
47 50
48 /* List of BUG addresses, source line numbers and filenames */ 51 /* List of BUG addresses, source line numbers and filenames */
49 struct list_head bug_list; 52 struct list_head bug_list;
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 1aec559bdfcb..3271cd698e4c 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -274,7 +274,63 @@ static int
274__ftrace_make_nop(struct module *mod, 274__ftrace_make_nop(struct module *mod,
275 struct dyn_ftrace *rec, unsigned long addr) 275 struct dyn_ftrace *rec, unsigned long addr)
276{ 276{
277 /* Ignore modules for PPC32 (for now) */ 277 unsigned char replaced[MCOUNT_INSN_SIZE];
278 unsigned int *op = (unsigned *)&replaced;
279 unsigned char jmp[8];
280 unsigned int *ptr = (unsigned int *)&jmp;
281 unsigned long ip = rec->ip;
282 unsigned long tramp;
283 int offset;
284
285 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
286 return -EFAULT;
287
288 /* Make sure that that this is still a 24bit jump */
289 if (!is_bl_op(*op)) {
290 printk(KERN_ERR "Not expected bl: opcode is %x\n", *op);
291 return -EINVAL;
292 }
293
294 /* lets find where the pointer goes */
295 tramp = find_bl_target(ip, *op);
296
297 /*
298 * On PPC32 the trampoline looks like:
299 * lis r11,sym@ha
300 * addi r11,r11,sym@l
301 * mtctr r11
302 * bctr
303 */
304
305 DEBUGP("ip:%lx jumps to %lx", ip, tramp);
306
307 /* Find where the trampoline jumps to */
308 if (probe_kernel_read(jmp, (void *)tramp, 8)) {
309 printk(KERN_ERR "Failed to read %lx\n", tramp);
310 return -EFAULT;
311 }
312
313 DEBUGP(" %08x %08x ", ptr[0], ptr[1]);
314
315 tramp = (ptr[1] & 0xffff) |
316 ((ptr[0] & 0xffff) << 16);
317 if (tramp & 0x8000)
318 tramp -= 0x10000;
319
320 DEBUGP(" %x ", tramp);
321
322 if (tramp != addr) {
323 printk(KERN_ERR
324 "Trampoline location %08lx does not match addr\n",
325 tramp);
326 return -EINVAL;
327 }
328
329 op[0] = PPC_NOP_INSTR;
330
331 if (probe_kernel_write((void *)ip, replaced, MCOUNT_INSN_SIZE))
332 return -EPERM;
333
278 return 0; 334 return 0;
279} 335}
280#endif /* PPC64 */ 336#endif /* PPC64 */
@@ -297,7 +353,6 @@ int ftrace_make_nop(struct module *mod,
297 return ftrace_modify_code(ip, old, new); 353 return ftrace_modify_code(ip, old, new);
298 } 354 }
299 355
300#ifdef CONFIG_PPC64
301 /* 356 /*
302 * Out of range jumps are called from modules. 357 * Out of range jumps are called from modules.
303 * We should either already have a pointer to the module 358 * We should either already have a pointer to the module
@@ -320,7 +375,6 @@ int ftrace_make_nop(struct module *mod,
320 /* nothing to do if mod == rec->arch.mod */ 375 /* nothing to do if mod == rec->arch.mod */
321 } else 376 } else
322 mod = rec->arch.mod; 377 mod = rec->arch.mod;
323#endif /* CONFIG_PPC64 */
324 378
325 return __ftrace_make_nop(mod, rec, addr); 379 return __ftrace_make_nop(mod, rec, addr);
326 380
@@ -380,7 +434,44 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
380static int 434static int
381__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 435__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
382{ 436{
383 /* PPC32 ignores modules for now */ 437 unsigned char replaced[MCOUNT_INSN_SIZE];
438 unsigned int *op = (unsigned *)&replaced;
439 unsigned long ip = rec->ip;
440 unsigned long offset;
441
442 /* read where this goes */
443 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
444 return -EFAULT;
445
446 /* It should be pointing to a nop */
447 if (op[0] != PPC_NOP_INSTR) {
448 printk(KERN_ERR "Expected NOP but have %x\n", op[0]);
449 return -EINVAL;
450 }
451
452 /* If we never set up a trampoline to ftrace_caller, then bail */
453 if (!rec->arch.mod->arch.tramp) {
454 printk(KERN_ERR "No ftrace trampoline\n");
455 return -EINVAL;
456 }
457
458 /* now calculate a jump to the ftrace caller trampoline */
459 offset = rec->arch.mod->arch.tramp - ip;
460
461 if (test_offset(offset)) {
462 printk(KERN_ERR "REL24 %li out of range!\n",
463 (long int)offset);
464 return -EINVAL;
465 }
466
467 /* Set to "bl addr" */
468 op[0] = branch_offset(offset);
469
470 DEBUGP("write to %lx\n", rec->ip);
471
472 if (probe_kernel_write((void *)ip, replaced, MCOUNT_INSN_SIZE))
473 return -EPERM;
474
384 return 0; 475 return 0;
385} 476}
386#endif /* CONFIG_PPC64 */ 477#endif /* CONFIG_PPC64 */
@@ -402,7 +493,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
402 return ftrace_modify_code(ip, old, new); 493 return ftrace_modify_code(ip, old, new);
403 } 494 }
404 495
405#ifdef CONFIG_PPC64
406 /* 496 /*
407 * Out of range jumps are called from modules. 497 * Out of range jumps are called from modules.
408 * Being that we are converting from nop, it had better 498 * Being that we are converting from nop, it had better
@@ -412,7 +502,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
412 printk(KERN_ERR "No module loaded\n"); 502 printk(KERN_ERR "No module loaded\n");
413 return -EINVAL; 503 return -EINVAL;
414 } 504 }
415#endif
416 505
417 return __ftrace_make_call(rec, addr); 506 return __ftrace_make_call(rec, addr);
418} 507}
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
index 2df91a03462a..f832773fc28e 100644
--- a/arch/powerpc/kernel/module_32.c
+++ b/arch/powerpc/kernel/module_32.c
@@ -22,6 +22,7 @@
22#include <linux/fs.h> 22#include <linux/fs.h>
23#include <linux/string.h> 23#include <linux/string.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/ftrace.h>
25#include <linux/cache.h> 26#include <linux/cache.h>
26#include <linux/bug.h> 27#include <linux/bug.h>
27#include <linux/sort.h> 28#include <linux/sort.h>
@@ -53,6 +54,9 @@ static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
53 r_addend = rela[i].r_addend; 54 r_addend = rela[i].r_addend;
54 } 55 }
55 56
57#ifdef CONFIG_DYNAMIC_FTRACE
58 _count_relocs++; /* add one for ftrace_caller */
59#endif
56 return _count_relocs; 60 return _count_relocs;
57} 61}
58 62
@@ -306,5 +310,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
306 return -ENOEXEC; 310 return -ENOEXEC;
307 } 311 }
308 } 312 }
313#ifdef CONFIG_DYNAMIC_FTRACE
314 module->arch.tramp =
315 do_plt_call(module->module_core,
316 (unsigned long)ftrace_caller,
317 sechdrs, module);
318#endif
309 return 0; 319 return 0;
310} 320}