diff options
Diffstat (limited to 'arch/powerpc/kernel/kprobes.c')
| -rw-r--r-- | arch/powerpc/kernel/kprobes.c | 92 |
1 files changed, 44 insertions, 48 deletions
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index bebc3007a793..ca5d5a081e75 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c | |||
| @@ -43,12 +43,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | |||
| 43 | 43 | ||
| 44 | struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}}; | 44 | struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}}; |
| 45 | 45 | ||
| 46 | int is_current_kprobe_addr(unsigned long addr) | ||
| 47 | { | ||
| 48 | struct kprobe *p = kprobe_running(); | ||
| 49 | return (p && (unsigned long)p->addr == addr) ? 1 : 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | bool arch_within_kprobe_blacklist(unsigned long addr) | 46 | bool arch_within_kprobe_blacklist(unsigned long addr) |
| 53 | { | 47 | { |
| 54 | return (addr >= (unsigned long)__kprobes_text_start && | 48 | return (addr >= (unsigned long)__kprobes_text_start && |
| @@ -59,7 +53,7 @@ bool arch_within_kprobe_blacklist(unsigned long addr) | |||
| 59 | 53 | ||
| 60 | kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset) | 54 | kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset) |
| 61 | { | 55 | { |
| 62 | kprobe_opcode_t *addr; | 56 | kprobe_opcode_t *addr = NULL; |
| 63 | 57 | ||
| 64 | #ifdef PPC64_ELF_ABI_v2 | 58 | #ifdef PPC64_ELF_ABI_v2 |
| 65 | /* PPC64 ABIv2 needs local entry point */ | 59 | /* PPC64 ABIv2 needs local entry point */ |
| @@ -91,36 +85,29 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset) | |||
| 91 | * Also handle <module:symbol> format. | 85 | * Also handle <module:symbol> format. |
| 92 | */ | 86 | */ |
| 93 | char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN]; | 87 | char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN]; |
| 94 | const char *modsym; | ||
| 95 | bool dot_appended = false; | 88 | bool dot_appended = false; |
| 96 | if ((modsym = strchr(name, ':')) != NULL) { | 89 | const char *c; |
| 97 | modsym++; | 90 | ssize_t ret = 0; |
| 98 | if (*modsym != '\0' && *modsym != '.') { | 91 | int len = 0; |
| 99 | /* Convert to <module:.symbol> */ | 92 | |
| 100 | strncpy(dot_name, name, modsym - name); | 93 | if ((c = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) { |
| 101 | dot_name[modsym - name] = '.'; | 94 | c++; |
| 102 | dot_name[modsym - name + 1] = '\0'; | 95 | len = c - name; |
| 103 | strncat(dot_name, modsym, | 96 | memcpy(dot_name, name, len); |
| 104 | sizeof(dot_name) - (modsym - name) - 2); | 97 | } else |
| 105 | dot_appended = true; | 98 | c = name; |
| 106 | } else { | 99 | |
| 107 | dot_name[0] = '\0'; | 100 | if (*c != '\0' && *c != '.') { |
| 108 | strncat(dot_name, name, sizeof(dot_name) - 1); | 101 | dot_name[len++] = '.'; |
| 109 | } | ||
| 110 | } else if (name[0] != '.') { | ||
| 111 | dot_name[0] = '.'; | ||
| 112 | dot_name[1] = '\0'; | ||
| 113 | strncat(dot_name, name, KSYM_NAME_LEN - 2); | ||
| 114 | dot_appended = true; | 102 | dot_appended = true; |
| 115 | } else { | ||
| 116 | dot_name[0] = '\0'; | ||
| 117 | strncat(dot_name, name, KSYM_NAME_LEN - 1); | ||
| 118 | } | 103 | } |
| 119 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); | 104 | ret = strscpy(dot_name + len, c, KSYM_NAME_LEN); |
| 120 | if (!addr && dot_appended) { | 105 | if (ret > 0) |
| 121 | /* Let's try the original non-dot symbol lookup */ | 106 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); |
| 107 | |||
| 108 | /* Fallback to the original non-dot symbol lookup */ | ||
| 109 | if (!addr && dot_appended) | ||
| 122 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); | 110 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); |
| 123 | } | ||
| 124 | #else | 111 | #else |
| 125 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); | 112 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); |
| 126 | #endif | 113 | #endif |
| @@ -239,7 +226,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) | |||
| 239 | } | 226 | } |
| 240 | NOKPROBE_SYMBOL(arch_prepare_kretprobe); | 227 | NOKPROBE_SYMBOL(arch_prepare_kretprobe); |
| 241 | 228 | ||
| 242 | int try_to_emulate(struct kprobe *p, struct pt_regs *regs) | 229 | static int try_to_emulate(struct kprobe *p, struct pt_regs *regs) |
| 243 | { | 230 | { |
| 244 | int ret; | 231 | int ret; |
| 245 | unsigned int insn = *p->ainsn.insn; | 232 | unsigned int insn = *p->ainsn.insn; |
| @@ -261,9 +248,20 @@ int try_to_emulate(struct kprobe *p, struct pt_regs *regs) | |||
| 261 | */ | 248 | */ |
| 262 | printk("Can't step on instruction %x\n", insn); | 249 | printk("Can't step on instruction %x\n", insn); |
| 263 | BUG(); | 250 | BUG(); |
| 264 | } else if (ret == 0) | 251 | } else { |
| 265 | /* This instruction can't be boosted */ | 252 | /* |
| 266 | p->ainsn.boostable = -1; | 253 | * If we haven't previously emulated this instruction, then it |
| 254 | * can't be boosted. Note it down so we don't try to do so again. | ||
| 255 | * | ||
| 256 | * If, however, we had emulated this instruction in the past, | ||
| 257 | * then this is just an error with the current run (for | ||
| 258 | * instance, exceptions due to a load/store). We return 0 so | ||
| 259 | * that this is now single-stepped, but continue to try | ||
| 260 | * emulating it in subsequent probe hits. | ||
| 261 | */ | ||
| 262 | if (unlikely(p->ainsn.boostable != 1)) | ||
| 263 | p->ainsn.boostable = -1; | ||
| 264 | } | ||
| 267 | 265 | ||
| 268 | return ret; | 266 | return ret; |
| 269 | } | 267 | } |
| @@ -639,24 +637,22 @@ NOKPROBE_SYMBOL(setjmp_pre_handler); | |||
| 639 | 637 | ||
| 640 | void __used jprobe_return(void) | 638 | void __used jprobe_return(void) |
| 641 | { | 639 | { |
| 642 | asm volatile("trap" ::: "memory"); | 640 | asm volatile("jprobe_return_trap:\n" |
| 641 | "trap\n" | ||
| 642 | ::: "memory"); | ||
| 643 | } | 643 | } |
| 644 | NOKPROBE_SYMBOL(jprobe_return); | 644 | NOKPROBE_SYMBOL(jprobe_return); |
| 645 | 645 | ||
| 646 | static void __used jprobe_return_end(void) | ||
| 647 | { | ||
| 648 | } | ||
| 649 | NOKPROBE_SYMBOL(jprobe_return_end); | ||
| 650 | |||
| 651 | int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 646 | int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
| 652 | { | 647 | { |
| 653 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 648 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 654 | 649 | ||
| 655 | /* | 650 | if (regs->nip != ppc_kallsyms_lookup_name("jprobe_return_trap")) { |
| 656 | * FIXME - we should ideally be validating that we got here 'cos | 651 | pr_debug("longjmp_break_handler NIP (0x%lx) does not match jprobe_return_trap (0x%lx)\n", |
| 657 | * of the "trap" in jprobe_return() above, before restoring the | 652 | regs->nip, ppc_kallsyms_lookup_name("jprobe_return_trap")); |
| 658 | * saved regs... | 653 | return 0; |
| 659 | */ | 654 | } |
| 655 | |||
| 660 | memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); | 656 | memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); |
| 661 | /* It's OK to start function graph tracing again */ | 657 | /* It's OK to start function graph tracing again */ |
| 662 | unpause_graph_tracing(); | 658 | unpause_graph_tracing(); |
