History

s390/ftrace,kprobes: allow to patch first instruction

If the function tracer is enabled, allow to set kprobes on the first instruction of a function (which is the function trace caller): If no kprobe is set handling of enabling and disabling function tracing of a function simply patches the first instruction. Either it is a nop (right now it's an unconditional branch, which skips the mcount block), or it's a branch to the ftrace_caller() function. If a kprobe is being placed on a function tracer calling instruction we encode if we actually have a nop or branch in the remaining bytes after the breakpoint instruction (illegal opcode). This is possible, since the size of the instruction used for the nop and branch is six bytes, while the size of the breakpoint is only two bytes. Therefore the first two bytes contain the illegal opcode and the last four bytes contain either "0" for nop or "1" for branch. The kprobes code will then execute/simulate the correct instruction. Instruction patching for kprobes and function tracer is always done with stop_machine(). Therefore we don't have any races where an instruction is patched concurrently on a different cpu. Besides that also the program check handler which executes the function trace caller instruction won't be executed concurrently to any stop_machine() execution. This allows to keep full fault based kprobes handling which generates correct pt_regs contents automatically.

Heiko Carstens committed 12 years ago

Commit c9331461 parent f7f242f13 files · +214 −92Browse files

Unified · Split

13 files
  1. arch/s390/include/asm/ftrace.h +47 −5
  2. arch/s390/include/asm/kprobes.h +1 −0
  3. arch/s390/include/asm/lowcore.h +2 −2
  4. arch/s390/include/asm/pgtable.h +12 −0
  5. arch/s390/kernel/asm-offsets.c +0 −1
  6. arch/s390/kernel/early.c +0 −4
  7. arch/s390/kernel/ftrace.c +84 −48
  8. arch/s390/kernel/kprobes.c +65 −27
  9. arch/s390/kernel/mcount.S +1 −0
  10. arch/s390/kernel/setup.c +0 −2
  11. arch/s390/kernel/smp.c +0 −1
  12. scripts/recordmcount.c +1 −1
  13. scripts/recordmcount.pl +1 −1
arch/s390/include/asm/ftrace.h+47−5
@@ -1,25 +1,67 @@
11 #ifndef _ASM_S390_FTRACE_H
22 #define _ASM_S390_FTRACE_H
33
4+#define ARCH_SUPPORTS_FTRACE_OPS 1
5+
6+#define MCOUNT_INSN_SIZE 24
7+#define MCOUNT_RETURN_FIXUP 18
8+
49 #ifndef __ASSEMBLY__
510
6−extern void _mcount(void);
11+void _mcount(void);
12+void ftrace_caller(void);
13+
714 extern char ftrace_graph_caller_end;
15+extern unsigned long ftrace_plt;
816
917 struct dyn_arch_ftrace { };
1018
11−#define MCOUNT_ADDR ((long)_mcount)
19+#define MCOUNT_ADDR ((unsigned long)_mcount)
20+#define FTRACE_ADDR ((unsigned long)ftrace_caller)
1221
22+#define KPROBE_ON_FTRACE_NOP 0
23+#define KPROBE_ON_FTRACE_CALL 1
1324
1425 static inline unsigned long ftrace_call_adjust(unsigned long addr)
1526 {
1627 return addr;
1728 }
1829
19−#endif /* __ASSEMBLY__ */
30+struct ftrace_insn {
31+ u16 opc;
32+ s32 disp;
33+} __packed;
2034
21−#define MCOUNT_INSN_SIZE 18
35+static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
36+{
37+#ifdef CONFIG_FUNCTION_TRACER
38+ /* jg .+24 */
39+ insn->opc = 0xc0f4;
40+ insn->disp = MCOUNT_INSN_SIZE / 2;
41+#endif
42+}
2243
23−#define ARCH_SUPPORTS_FTRACE_OPS 1
44+static inline int is_ftrace_nop(struct ftrace_insn *insn)
45+{
46+#ifdef CONFIG_FUNCTION_TRACER
47+ if (insn->disp == MCOUNT_INSN_SIZE / 2)
48+ return 1;
49+#endif
50+ return 0;
51+}
52+
53+static inline void ftrace_generate_call_insn(struct ftrace_insn *insn,
54+ unsigned long ip)
55+{
56+#ifdef CONFIG_FUNCTION_TRACER
57+ unsigned long target;
2458
59+ /* brasl r0,ftrace_caller */
60+ target = is_module_addr((void *) ip) ? ftrace_plt : FTRACE_ADDR;
61+ insn->opc = 0xc005;
62+ insn->disp = (target - ip) / 2;
63+#endif
64+}
65+
66+#endif /* __ASSEMBLY__ */
2567 #endif /* _ASM_S390_FTRACE_H */
arch/s390/include/asm/kprobes.h+1−0
@@ -60,6 +60,7 @@ typedef u16 kprobe_opcode_t; · 59 unmodified lines
6060 struct arch_specific_insn {
6161 /* copy of original instruction */
6262 kprobe_opcode_t *insn;
63+ unsigned int is_ftrace_insn : 1;
6364 };
6465
6566 struct prev_kprobe {
arch/s390/include/asm/lowcore.h+2−2
@@ -147,7 +147,7 @@ struct _lowcore { · 146 unmodified lines
147147 __u32 softirq_pending; /* 0x02ec */
148148 __u32 percpu_offset; /* 0x02f0 */
149149 __u32 machine_flags; /* 0x02f4 */
150− __u32 ftrace_func; /* 0x02f8 */
150+ __u8 pad_0x02f8[0x02fc-0x02f8]; /* 0x02f8 */
151151 __u32 spinlock_lockval; /* 0x02fc */
152152
153153 __u8 pad_0x0300[0x0e00-0x0300]; /* 0x0300 */
@@ -297,7 +297,7 @@ struct _lowcore { · 143 unmodified lines
297297 __u64 percpu_offset; /* 0x0378 */
298298 __u64 vdso_per_cpu_data; /* 0x0380 */
299299 __u64 machine_flags; /* 0x0388 */
300− __u64 ftrace_func; /* 0x0390 */
300+ __u8 pad_0x0390[0x0398-0x0390]; /* 0x0390 */
301301 __u64 gmap; /* 0x0398 */
302302 __u32 spinlock_lockval; /* 0x03a0 */
303303 __u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */
arch/s390/include/asm/pgtable.h+12−0
@@ -133,6 +133,18 @@ extern unsigned long MODULES_END; · 132 unmodified lines
133133 #define MODULES_LEN (1UL << 31)
134134 #endif
135135
136+static inline int is_module_addr(void *addr)
137+{
138+#ifdef CONFIG_64BIT
139+ BUILD_BUG_ON(MODULES_LEN > (1UL << 31));
140+ if (addr < (void *)MODULES_VADDR)
141+ return 0;
142+ if (addr > (void *)MODULES_END)
143+ return 0;
144+#endif
145+ return 1;
146+}
147+
136148 /*
137149 * A 31 bit pagetable entry of S390 has following format:
138150 * | PFRA | | OS |
arch/s390/kernel/asm-offsets.c+0−1
@@ -156,7 +156,6 @@ int main(void) · 155 unmodified lines
156156 DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
157157 DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
158158 DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
159− DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
160159 DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
161160 BLANK();
162161 DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
arch/s390/kernel/early.c+0−4
@@ -12,7 +12,6 @@ · 11 unmodified lines
1212 #include <linux/errno.h>
1313 #include <linux/string.h>
1414 #include <linux/ctype.h>
15−#include <linux/ftrace.h>
1615 #include <linux/lockdep.h>
1716 #include <linux/module.h>
1817 #include <linux/pfn.h>
@@ -490,8 +489,5 @@ void __init startup_init(void) · 471 unmodified lines
490489 detect_machine_facilities();
491490 setup_topology();
492491 sclp_early_detect();
493−#ifdef CONFIG_DYNAMIC_FTRACE
494− S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
495−#endif
496492 lockdep_on();
497493 }
arch/s390/kernel/ftrace.c+84−48
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 * Martin Schwidefsky <schwidefsky@de.ibm.com>
88 */
99
10+#include <linux/moduleloader.h>
1011 #include <linux/hardirq.h>
1112 #include <linux/uaccess.h>
1213 #include <linux/ftrace.h>
@@ -15,60 +16,39 @@ · 2 unmodified lines
1516 #include <linux/kprobes.h>
1617 #include <trace/syscall.h>
1718 #include <asm/asm-offsets.h>
19+#include <asm/cacheflush.h>
1820 #include "entry.h"
1921
20−void mcount_replace_code(void);
21−void ftrace_disable_code(void);
22−void ftrace_enable_insn(void);
23−
2422 /*
2523 * The mcount code looks like this:
2624 * stg %r14,8(%r15) # offset 0
2725 * larl %r1,<&counter> # offset 6
2826 * brasl %r14,_mcount # offset 12
2927 * lg %r14,8(%r15) # offset 18
30− * Total length is 24 bytes. The complete mcount block initially gets replaced
31− * by ftrace_make_nop. Subsequent calls to ftrace_make_call / ftrace_make_nop
32− * only patch the jg/lg instruction within the block.
33− * Note: we do not patch the first instruction to an unconditional branch,
34− * since that would break kprobes/jprobes. It is easier to leave the larl
35− * instruction in and only modify the second instruction.
28+ * Total length is 24 bytes. Only the first instruction will be patched
29+ * by ftrace_make_call / ftrace_make_nop.
3630 * The enabled ftrace code block looks like this:
37− * larl %r0,.+24 # offset 0
38− * > lg %r1,__LC_FTRACE_FUNC # offset 6
39− * br %r1 # offset 12
40− * brcl 0,0 # offset 14
41− * brc 0,0 # offset 20
31+ * > brasl %r0,ftrace_caller # offset 0
32+ * larl %r1,<&counter> # offset 6
33+ * brasl %r14,_mcount # offset 12
34+ * lg %r14,8(%r15) # offset 18
4235 * The ftrace function gets called with a non-standard C function call ABI
4336 * where r0 contains the return address. It is also expected that the called
4437 * function only clobbers r0 and r1, but restores r2-r15.
38+ * For module code we can't directly jump to ftrace caller, but need a
39+ * trampoline (ftrace_plt), which clobbers also r1.
4540 * The return point of the ftrace function has offset 24, so execution
4641 * continues behind the mcount block.
47− * larl %r0,.+24 # offset 0
48− * > jg .+18 # offset 6
49− * br %r1 # offset 12
50− * brcl 0,0 # offset 14
51− * brc 0,0 # offset 20
42+ * The disabled ftrace code block looks like this:
43+ * > jg .+24 # offset 0
44+ * larl %r1,<&counter> # offset 6
45+ * brasl %r14,_mcount # offset 12
46+ * lg %r14,8(%r15) # offset 18
5247 * The jg instruction branches to offset 24 to skip as many instructions
5348 * as possible.
5449 */
55−asm(
56− " .align 4\n"
57− "mcount_replace_code:\n"
58− " larl %r0,0f\n"
59− "ftrace_disable_code:\n"
60− " jg 0f\n"
61− " br %r1\n"
62− " brcl 0,0\n"
63− " brc 0,0\n"
64− "0:\n"
65− " .align 4\n"
66− "ftrace_enable_insn:\n"
67− " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n");
68−
69−#define MCOUNT_BLOCK_SIZE 24
70−#define MCOUNT_INSN_OFFSET 6
71−#define FTRACE_INSN_SIZE 6
50+
51+unsigned long ftrace_plt;
7252
7353 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
7454 unsigned long addr)
@@ -79,24 +59,62 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, · 4 unmodified lines
7959 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
8060 unsigned long addr)
8161 {
82− /* Initial replacement of the whole mcount block */
83− if (addr == MCOUNT_ADDR) {
84− if (probe_kernel_write((void *) rec->ip - MCOUNT_INSN_OFFSET,
85− mcount_replace_code,
86− MCOUNT_BLOCK_SIZE))
87− return -EPERM;
88− return 0;
62+ struct ftrace_insn insn;
63+ unsigned short op;
64+ void *from, *to;
65+ size_t size;
66+
67+ ftrace_generate_nop_insn(&insn);
68+ size = sizeof(insn);
69+ from = &insn;
70+ to = (void *) rec->ip;
71+ if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op)))
72+ return -EFAULT;
73+ /*
74+ * If we find a breakpoint instruction, a kprobe has been placed
75+ * at the beginning of the function. We write the constant
76+ * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original
77+ * instruction so that the kprobes handler can execute a nop, if it
78+ * reaches this breakpoint.
79+ */
80+ if (op == BREAKPOINT_INSTRUCTION) {
81+ size -= 2;
82+ from += 2;
83+ to += 2;
84+ insn.disp = KPROBE_ON_FTRACE_NOP;
8985 }
90− if (probe_kernel_write((void *) rec->ip, ftrace_disable_code,
91− MCOUNT_INSN_SIZE))
86+ if (probe_kernel_write(to, from, size))
9287 return -EPERM;
9388 return 0;
9489 }
9590
9691 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
9792 {
98− if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn,
99− FTRACE_INSN_SIZE))
93+ struct ftrace_insn insn;
94+ unsigned short op;
95+ void *from, *to;
96+ size_t size;
97+
98+ ftrace_generate_call_insn(&insn, rec->ip);
99+ size = sizeof(insn);
100+ from = &insn;
101+ to = (void *) rec->ip;
102+ if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op)))
103+ return -EFAULT;
104+ /*
105+ * If we find a breakpoint instruction, a kprobe has been placed
106+ * at the beginning of the function. We write the constant
107+ * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original
108+ * instruction so that the kprobes handler can execute a brasl if it
109+ * reaches this breakpoint.
110+ */
111+ if (op == BREAKPOINT_INSTRUCTION) {
112+ size -= 2;
113+ from += 2;
114+ to += 2;
115+ insn.disp = KPROBE_ON_FTRACE_CALL;
116+ }
117+ if (probe_kernel_write(to, from, size))
100118 return -EPERM;
101119 return 0;
102120 }
@@ -111,6 +129,24 @@ int __init ftrace_dyn_arch_init(void) · 8 unmodified lines
111129 return 0;
112130 }
113131
132+static int __init ftrace_plt_init(void)
133+{
134+ unsigned int *ip;
135+
136+ ftrace_plt = (unsigned long) module_alloc(PAGE_SIZE);
137+ if (!ftrace_plt)
138+ panic("cannot allocate ftrace plt\n");
139+ ip = (unsigned int *) ftrace_plt;
140+ ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
141+ ip[1] = 0x100a0004;
142+ ip[2] = 0x07f10000;
143+ ip[3] = FTRACE_ADDR >> 32;
144+ ip[4] = FTRACE_ADDR & 0xffffffff;
145+ set_memory_ro(ftrace_plt, 1);
146+ return 0;
147+}
148+device_initcall(ftrace_plt_init);
149+
114150 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
115151 /*
116152 * Hook the return address and push it in the stack of return addresses
arch/s390/kernel/kprobes.c+65−27
@@ -29,6 +29,7 @@ · 28 unmodified lines
2929 #include <linux/module.h>
3030 #include <linux/slab.h>
3131 #include <linux/hardirq.h>
32+#include <linux/ftrace.h>
3233 #include <asm/cacheflush.h>
3334 #include <asm/sections.h>
3435 #include <asm/dis.h>
@@ -60,10 +61,21 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = { · 25 unmodified lines
6061
6162 static void __kprobes copy_instruction(struct kprobe *p)
6263 {
64+ unsigned long ip = (unsigned long) p->addr;
6365 s64 disp, new_disp;
6466 u64 addr, new_addr;
6567
66− memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8));
68+ if (ftrace_location(ip) == ip) {
69+ /*
70+ * If kprobes patches the instruction that is morphed by
71+ * ftrace make sure that kprobes always sees the branch
72+ * "jg .+24" that skips the mcount block
73+ */
74+ ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
75+ p->ainsn.is_ftrace_insn = 1;
76+ } else
77+ memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8));
78+ p->opcode = p->ainsn.insn[0];
6779 if (!probe_is_insn_relative_long(p->ainsn.insn))
6880 return;
6981 /*
@@ -85,18 +97,6 @@ static inline int is_kernel_addr(void *addr) · 15 unmodified lines
8597 return addr < (void *)_end;
8698 }
8799
88−static inline int is_module_addr(void *addr)
89−{
90−#ifdef CONFIG_64BIT
91− BUILD_BUG_ON(MODULES_LEN > (1UL << 31));
92− if (addr < (void *)MODULES_VADDR)
93− return 0;
94− if (addr > (void *)MODULES_END)
95− return 0;
96−#endif
97− return 1;
98−}
99−
100100 static int __kprobes s390_get_insn_slot(struct kprobe *p)
101101 {
102102 /*
@@ -132,43 +132,63 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) · 29 unmodified lines
132132 return -EINVAL;
133133 if (s390_get_insn_slot(p))
134134 return -ENOMEM;
135− p->opcode = *p->addr;
136135 copy_instruction(p);
137136 return 0;
138137 }
139138
140−struct ins_replace_args {
141− kprobe_opcode_t *ptr;
142− kprobe_opcode_t opcode;
139+int arch_check_ftrace_location(struct kprobe *p)
140+{
141+ return 0;
142+}
143+
144+struct swap_insn_args {
145+ struct kprobe *p;
146+ unsigned int arm_kprobe : 1;
143147 };
144148
145−static int __kprobes swap_instruction(void *aref)
149+static int __kprobes swap_instruction(void *data)
146150 {
147151 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
148152 unsigned long status = kcb->kprobe_status;
149− struct ins_replace_args *args = aref;
150−
153+ struct swap_insn_args *args = data;
154+ struct ftrace_insn new_insn, *insn;
155+ struct kprobe *p = args->p;
156+ size_t len;
157+
158+ new_insn.opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode;
159+ len = sizeof(new_insn.opc);
160+ if (!p->ainsn.is_ftrace_insn)
161+ goto skip_ftrace;
162+ len = sizeof(new_insn);
163+ insn = (struct ftrace_insn *) p->addr;
164+ if (args->arm_kprobe) {
165+ if (is_ftrace_nop(insn))
166+ new_insn.disp = KPROBE_ON_FTRACE_NOP;
167+ else
168+ new_insn.disp = KPROBE_ON_FTRACE_CALL;
169+ } else {
170+ ftrace_generate_call_insn(&new_insn, (unsigned long)p->addr);
171+ if (insn->disp == KPROBE_ON_FTRACE_NOP)
172+ ftrace_generate_nop_insn(&new_insn);
173+ }
174+skip_ftrace:
151175 kcb->kprobe_status = KPROBE_SWAP_INST;
152− probe_kernel_write(args->ptr, &args->opcode, sizeof(args->opcode));
176+ probe_kernel_write(p->addr, &new_insn, len);
153177 kcb->kprobe_status = status;
154178 return 0;
155179 }
156180
157181 void __kprobes arch_arm_kprobe(struct kprobe *p)
158182 {
159− struct ins_replace_args args;
183+ struct swap_insn_args args = {.p = p, .arm_kprobe = 1};
160184
161− args.ptr = p->addr;
162− args.opcode = BREAKPOINT_INSTRUCTION;
163185 stop_machine(swap_instruction, &args, NULL);
164186 }
165187
166188 void __kprobes arch_disarm_kprobe(struct kprobe *p)
167189 {
168− struct ins_replace_args args;
190+ struct swap_insn_args args = {.p = p, .arm_kprobe = 0};
169191
170− args.ptr = p->addr;
171− args.opcode = p->opcode;
172192 stop_machine(swap_instruction, &args, NULL);
173193 }
174194
@@ -459,6 +479,24 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) · 284 unmodified lines
459479 unsigned long ip = regs->psw.addr & PSW_ADDR_INSN;
460480 int fixup = probe_get_fixup_type(p->ainsn.insn);
461481
482+ /* Check if the kprobes location is an enabled ftrace caller */
483+ if (p->ainsn.is_ftrace_insn) {
484+ struct ftrace_insn *insn = (struct ftrace_insn *) p->addr;
485+ struct ftrace_insn call_insn;
486+
487+ ftrace_generate_call_insn(&call_insn, (unsigned long) p->addr);
488+ /*
489+ * A kprobe on an enabled ftrace call site actually single
490+ * stepped an unconditional branch (ftrace nop equivalent).
491+ * Now we need to fixup things and pretend that a brasl r0,...
492+ * was executed instead.
493+ */
494+ if (insn->disp == KPROBE_ON_FTRACE_CALL) {
495+ ip += call_insn.disp * 2 - MCOUNT_INSN_SIZE;
496+ regs->gprs[0] = (unsigned long)p->addr + sizeof(*insn);
497+ }
498+ }
499+
462500 if (fixup & FIXUP_PSW_NORMAL)
463501 ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
464502
arch/s390/kernel/mcount.S+1−0
@@ -27,6 +27,7 @@ ENTRY(ftrace_caller) · 26 unmodified lines
2727 .globl ftrace_regs_caller
2828 .set ftrace_regs_caller,ftrace_caller
2929 lgr %r1,%r15
30+ aghi %r0,MCOUNT_RETURN_FIXUP
3031 aghi %r15,-STACK_FRAME_SIZE
3132 stg %r1,__SF_BACKCHAIN(%r15)
3233 stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
arch/s390/kernel/setup.c+0−2
@@ -41,7 +41,6 @@ · 40 unmodified lines
4141 #include <linux/ctype.h>
4242 #include <linux/reboot.h>
4343 #include <linux/topology.h>
44−#include <linux/ftrace.h>
4544 #include <linux/kexec.h>
4645 #include <linux/crash_dump.h>
4746 #include <linux/memory.h>
@@ -356,7 +355,6 @@ static void __init setup_lowcore(void) · 308 unmodified lines
356355 lc->steal_timer = S390_lowcore.steal_timer;
357356 lc->last_update_timer = S390_lowcore.last_update_timer;
358357 lc->last_update_clock = S390_lowcore.last_update_clock;
359− lc->ftrace_func = S390_lowcore.ftrace_func;
360358
361359 restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
362360 restart_stack += ASYNC_SIZE;
arch/s390/kernel/smp.c+0−1
@@ -236,7 +236,6 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) · 235 unmodified lines
236236 lc->percpu_offset = __per_cpu_offset[cpu];
237237 lc->kernel_asce = S390_lowcore.kernel_asce;
238238 lc->machine_flags = S390_lowcore.machine_flags;
239− lc->ftrace_func = S390_lowcore.ftrace_func;
240239 lc->user_timer = lc->system_timer = lc->steal_timer = 0;
241240 __ctl_store(lc->cregs_save_area, 0, 15);
242241 save_access_regs((unsigned int *) lc->access_regs_save_area);
scripts/recordmcount.c+1−1
@@ -404,7 +404,7 @@ do_file(char const *const fname) · 403 unmodified lines
404404 }
405405 if (w2(ghdr->e_machine) == EM_S390) {
406406 reltype = R_390_64;
407− mcount_adjust_64 = -8;
407+ mcount_adjust_64 = -14;
408408 }
409409 if (w2(ghdr->e_machine) == EM_MIPS) {
410410 reltype = R_MIPS_64;
scripts/recordmcount.pl+1−1
@@ -243,7 +243,7 @@ if ($arch eq "x86_64") { · 242 unmodified lines
243243
244244 } elsif ($arch eq "s390" && $bits == 64) {
245245 $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
246− $mcount_adjust = -8;
246+ $mcount_adjust = -14;
247247 $alignment = 8;
248248 $type = ".quad";
249249 $ld .= " -m elf64_s390";