Loading arch/s390/kernel/ftrace.c +49 −46 Original line number Original line Diff line number Diff line Loading @@ -59,62 +59,65 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) unsigned long addr) { { struct ftrace_insn insn; struct ftrace_insn orig, new, old; unsigned short op; void *from, *to; if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) size_t size; ftrace_generate_nop_insn(&insn); size = sizeof(insn); from = &insn; to = (void *) rec->ip; if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) return -EFAULT; return -EFAULT; if (addr == MCOUNT_ADDR) { /* Initial code replacement; we expect to see stg r14,8(r15) */ orig.opc = 0xe3e0; orig.disp = 0xf0080024; ftrace_generate_nop_insn(&new); } else if (old.opc == BREAKPOINT_INSTRUCTION) { /* /* * If we find a breakpoint instruction, a kprobe has been placed * If we find a breakpoint instruction, a kprobe has been * at the beginning of the function. We write the constant * placed at the beginning of the function. We write the * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original * constant KPROBE_ON_FTRACE_NOP into the remaining four * instruction so that the kprobes handler can execute a nop, if it * bytes of the original instruction so that the kprobes * reaches this breakpoint. * handler can execute a nop, if it reaches this breakpoint. */ */ if (op == BREAKPOINT_INSTRUCTION) { new.opc = orig.opc = BREAKPOINT_INSTRUCTION; size -= 2; orig.disp = KPROBE_ON_FTRACE_CALL; from += 2; new.disp = KPROBE_ON_FTRACE_NOP; to += 2; } else { insn.disp = KPROBE_ON_FTRACE_NOP; /* Replace ftrace call with a nop. */ ftrace_generate_call_insn(&orig, rec->ip); ftrace_generate_nop_insn(&new); } } if (probe_kernel_write(to, from, size)) /* Verify that the to be replaced code matches what we expect. */ if (memcmp(&orig, &old, sizeof(old))) return -EINVAL; if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return -EPERM; return 0; return 0; } } int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { { struct ftrace_insn insn; struct ftrace_insn orig, new, old; unsigned short op; void *from, *to; if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) size_t size; ftrace_generate_call_insn(&insn, rec->ip); size = sizeof(insn); from = &insn; to = (void *) rec->ip; if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) return -EFAULT; return -EFAULT; if (old.opc == BREAKPOINT_INSTRUCTION) { /* /* * If we find a breakpoint instruction, a kprobe has been placed * If we find a breakpoint instruction, a kprobe has been * at the beginning of the function. We write the constant * placed at the beginning of the function. We write the * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original * constant KPROBE_ON_FTRACE_CALL into the remaining four * instruction so that the kprobes handler can execute a brasl if it * bytes of the original instruction so that the kprobes * reaches this breakpoint. * handler can execute a brasl if it reaches this breakpoint. */ */ if (op == BREAKPOINT_INSTRUCTION) { new.opc = orig.opc = BREAKPOINT_INSTRUCTION; size -= 2; orig.disp = KPROBE_ON_FTRACE_NOP; from += 2; new.disp = KPROBE_ON_FTRACE_CALL; to += 2; } else { insn.disp = KPROBE_ON_FTRACE_CALL; /* Replace nop with an ftrace call. */ ftrace_generate_nop_insn(&orig); ftrace_generate_call_insn(&new, rec->ip); } } if (probe_kernel_write(to, from, size)) /* Verify that the to be replaced code matches what we expect. */ if (memcmp(&orig, &old, sizeof(old))) return -EINVAL; if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return -EPERM; return 0; return 0; } } Loading Loading
arch/s390/kernel/ftrace.c +49 −46 Original line number Original line Diff line number Diff line Loading @@ -59,62 +59,65 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) unsigned long addr) { { struct ftrace_insn insn; struct ftrace_insn orig, new, old; unsigned short op; void *from, *to; if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) size_t size; ftrace_generate_nop_insn(&insn); size = sizeof(insn); from = &insn; to = (void *) rec->ip; if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) return -EFAULT; return -EFAULT; if (addr == MCOUNT_ADDR) { /* Initial code replacement; we expect to see stg r14,8(r15) */ orig.opc = 0xe3e0; orig.disp = 0xf0080024; ftrace_generate_nop_insn(&new); } else if (old.opc == BREAKPOINT_INSTRUCTION) { /* /* * If we find a breakpoint instruction, a kprobe has been placed * If we find a breakpoint instruction, a kprobe has been * at the beginning of the function. We write the constant * placed at the beginning of the function. We write the * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original * constant KPROBE_ON_FTRACE_NOP into the remaining four * instruction so that the kprobes handler can execute a nop, if it * bytes of the original instruction so that the kprobes * reaches this breakpoint. * handler can execute a nop, if it reaches this breakpoint. */ */ if (op == BREAKPOINT_INSTRUCTION) { new.opc = orig.opc = BREAKPOINT_INSTRUCTION; size -= 2; orig.disp = KPROBE_ON_FTRACE_CALL; from += 2; new.disp = KPROBE_ON_FTRACE_NOP; to += 2; } else { insn.disp = KPROBE_ON_FTRACE_NOP; /* Replace ftrace call with a nop. */ ftrace_generate_call_insn(&orig, rec->ip); ftrace_generate_nop_insn(&new); } } if (probe_kernel_write(to, from, size)) /* Verify that the to be replaced code matches what we expect. */ if (memcmp(&orig, &old, sizeof(old))) return -EINVAL; if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return -EPERM; return 0; return 0; } } int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { { struct ftrace_insn insn; struct ftrace_insn orig, new, old; unsigned short op; void *from, *to; if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) size_t size; ftrace_generate_call_insn(&insn, rec->ip); size = sizeof(insn); from = &insn; to = (void *) rec->ip; if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) return -EFAULT; return -EFAULT; if (old.opc == BREAKPOINT_INSTRUCTION) { /* /* * If we find a breakpoint instruction, a kprobe has been placed * If we find a breakpoint instruction, a kprobe has been * at the beginning of the function. We write the constant * placed at the beginning of the function. We write the * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original * constant KPROBE_ON_FTRACE_CALL into the remaining four * instruction so that the kprobes handler can execute a brasl if it * bytes of the original instruction so that the kprobes * reaches this breakpoint. * handler can execute a brasl if it reaches this breakpoint. */ */ if (op == BREAKPOINT_INSTRUCTION) { new.opc = orig.opc = BREAKPOINT_INSTRUCTION; size -= 2; orig.disp = KPROBE_ON_FTRACE_NOP; from += 2; new.disp = KPROBE_ON_FTRACE_CALL; to += 2; } else { insn.disp = KPROBE_ON_FTRACE_CALL; /* Replace nop with an ftrace call. */ ftrace_generate_nop_insn(&orig); ftrace_generate_call_insn(&new, rec->ip); } } if (probe_kernel_write(to, from, size)) /* Verify that the to be replaced code matches what we expect. */ if (memcmp(&orig, &old, sizeof(old))) return -EINVAL; if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return -EPERM; return 0; return 0; } } Loading