kprobes.c (c39f2d9db0fd81ea20bb5cce9b3f082ca63753e2) kprobes.c (657480d9c01574d1e11bbb29e725db9907daf782)
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Kernel Probes (KProbes)
4 *
5 * Copyright IBM Corp. 2002, 2006
6 *
7 * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com>
8 */

--- 42 unchanged lines hidden (view full) ---

51 .alloc = alloc_s390_insn_page,
52 .free = free_s390_insn_page,
53 .pages = LIST_HEAD_INIT(kprobe_s390_insn_slots.pages),
54 .insn_size = MAX_INSN_SIZE,
55};
56
57static void copy_instruction(struct kprobe *p)
58{
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Kernel Probes (KProbes)
4 *
5 * Copyright IBM Corp. 2002, 2006
6 *
7 * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com>
8 */

--- 42 unchanged lines hidden (view full) ---

51 .alloc = alloc_s390_insn_page,
52 .free = free_s390_insn_page,
53 .pages = LIST_HEAD_INIT(kprobe_s390_insn_slots.pages),
54 .insn_size = MAX_INSN_SIZE,
55};
56
57static void copy_instruction(struct kprobe *p)
58{
59 unsigned long ip = (unsigned long) p->addr;
60 s64 disp, new_disp;
61 u64 addr, new_addr;
62
59 s64 disp, new_disp;
60 u64 addr, new_addr;
61
63 if (ftrace_location(ip) == ip) {
64 /*
65 * If kprobes patches the instruction that is morphed by
66 * ftrace make sure that kprobes always sees the branch
67 * "jg .+24" that skips the mcount block or the "brcl 0,0"
68 * in case of hotpatch.
69 */
70 ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
71 p->ainsn.is_ftrace_insn = 1;
72 } else
73 memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8));
62 memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8));
74 p->opcode = p->ainsn.insn[0];
75 if (!probe_is_insn_relative_long(p->ainsn.insn))
76 return;
77 /*
78 * For pc-relative instructions in RIL-b or RIL-c format patch the
79 * RI2 displacement field. We have already made sure that the insn
80 * slot for the patched instruction is within the same 2GB area
81 * as the original instruction (either kernel image or module area).

--- 49 unchanged lines hidden (view full) ---

131 return -EINVAL;
132 if (s390_get_insn_slot(p))
133 return -ENOMEM;
134 copy_instruction(p);
135 return 0;
136}
137NOKPROBE_SYMBOL(arch_prepare_kprobe);
138
63 p->opcode = p->ainsn.insn[0];
64 if (!probe_is_insn_relative_long(p->ainsn.insn))
65 return;
66 /*
67 * For pc-relative instructions in RIL-b or RIL-c format patch the
68 * RI2 displacement field. We have already made sure that the insn
69 * slot for the patched instruction is within the same 2GB area
70 * as the original instruction (either kernel image or module area).

--- 49 unchanged lines hidden (view full) ---

120 return -EINVAL;
121 if (s390_get_insn_slot(p))
122 return -ENOMEM;
123 copy_instruction(p);
124 return 0;
125}
126NOKPROBE_SYMBOL(arch_prepare_kprobe);
127
139int arch_check_ftrace_location(struct kprobe *p)
140{
141 return 0;
142}
143
144struct swap_insn_args {
145 struct kprobe *p;
146 unsigned int arm_kprobe : 1;
147};
148
149static int swap_instruction(void *data)
150{
151 struct swap_insn_args *args = data;
128struct swap_insn_args {
129 struct kprobe *p;
130 unsigned int arm_kprobe : 1;
131};
132
133static int swap_instruction(void *data)
134{
135 struct swap_insn_args *args = data;
152 struct ftrace_insn new_insn, *insn;
153 struct kprobe *p = args->p;
136 struct kprobe *p = args->p;
154 size_t len;
137 u16 opc;
155
138
156 new_insn.opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode;
157 len = sizeof(new_insn.opc);
158 if (!p->ainsn.is_ftrace_insn)
159 goto skip_ftrace;
160 len = sizeof(new_insn);
161 insn = (struct ftrace_insn *) p->addr;
162 if (args->arm_kprobe) {
163 if (is_ftrace_nop(insn))
164 new_insn.disp = KPROBE_ON_FTRACE_NOP;
165 else
166 new_insn.disp = KPROBE_ON_FTRACE_CALL;
167 } else {
168 ftrace_generate_call_insn(&new_insn, (unsigned long)p->addr);
169 if (insn->disp == KPROBE_ON_FTRACE_NOP)
170 ftrace_generate_nop_insn(&new_insn);
171 }
172skip_ftrace:
173 s390_kernel_write(p->addr, &new_insn, len);
139 opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode;
140 s390_kernel_write(p->addr, &opc, sizeof(opc));
174 return 0;
175}
176NOKPROBE_SYMBOL(swap_instruction);
177
178void arch_arm_kprobe(struct kprobe *p)
179{
180 struct swap_insn_args args = {.p = p, .arm_kprobe = 1};
181

--- 277 unchanged lines hidden (view full) ---

459 * copy is p->ainsn.insn.
460 */
461static void resume_execution(struct kprobe *p, struct pt_regs *regs)
462{
463 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
464 unsigned long ip = regs->psw.addr;
465 int fixup = probe_get_fixup_type(p->ainsn.insn);
466
141 return 0;
142}
143NOKPROBE_SYMBOL(swap_instruction);
144
145void arch_arm_kprobe(struct kprobe *p)
146{
147 struct swap_insn_args args = {.p = p, .arm_kprobe = 1};
148

--- 277 unchanged lines hidden (view full) ---

426 * copy is p->ainsn.insn.
427 */
428static void resume_execution(struct kprobe *p, struct pt_regs *regs)
429{
430 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
431 unsigned long ip = regs->psw.addr;
432 int fixup = probe_get_fixup_type(p->ainsn.insn);
433
467 /* Check if the kprobes location is an enabled ftrace caller */
468 if (p->ainsn.is_ftrace_insn) {
469 struct ftrace_insn *insn = (struct ftrace_insn *) p->addr;
470 struct ftrace_insn call_insn;
471
472 ftrace_generate_call_insn(&call_insn, (unsigned long) p->addr);
473 /*
474 * A kprobe on an enabled ftrace call site actually single
475 * stepped an unconditional branch (ftrace nop equivalent).
476 * Now we need to fixup things and pretend that a brasl r0,...
477 * was executed instead.
478 */
479 if (insn->disp == KPROBE_ON_FTRACE_CALL) {
480 ip += call_insn.disp * 2 - MCOUNT_INSN_SIZE;
481 regs->gprs[0] = (unsigned long)p->addr + sizeof(*insn);
482 }
483 }
484
485 if (fixup & FIXUP_PSW_NORMAL)
486 ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
487
488 if (fixup & FIXUP_BRANCH_NOT_TAKEN) {
489 int ilen = insn_length(p->ainsn.insn[0] >> 8);
490 if (ip - (unsigned long) p->ainsn.insn == ilen)
491 ip = (unsigned long) p->addr + ilen;
492 }

--- 167 unchanged lines hidden ---
434 if (fixup & FIXUP_PSW_NORMAL)
435 ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
436
437 if (fixup & FIXUP_BRANCH_NOT_TAKEN) {
438 int ilen = insn_length(p->ainsn.insn[0] >> 8);
439 if (ip - (unsigned long) p->ainsn.insn == ilen)
440 ip = (unsigned long) p->addr + ilen;
441 }

--- 167 unchanged lines hidden ---