Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/kernel/ftrace.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* arch/arm64/kernel/ftrace.c
4
*
5
* Copyright (C) 2013 Linaro Limited
6
* Author: AKASHI Takahiro <[email protected]>
7
*/
8
9
#include <linux/ftrace.h>
10
#include <linux/module.h>
11
#include <linux/swab.h>
12
#include <linux/uaccess.h>
13
14
#include <asm/cacheflush.h>
15
#include <asm/debug-monitors.h>
16
#include <asm/ftrace.h>
17
#include <asm/insn.h>
18
#include <asm/text-patching.h>
19
20
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
21
struct fregs_offset {
22
const char *name;
23
int offset;
24
};
25
26
#define FREGS_OFFSET(n, field) \
27
{ \
28
.name = n, \
29
.offset = offsetof(struct __arch_ftrace_regs, field), \
30
}
31
32
static const struct fregs_offset fregs_offsets[] = {
33
FREGS_OFFSET("x0", regs[0]),
34
FREGS_OFFSET("x1", regs[1]),
35
FREGS_OFFSET("x2", regs[2]),
36
FREGS_OFFSET("x3", regs[3]),
37
FREGS_OFFSET("x4", regs[4]),
38
FREGS_OFFSET("x5", regs[5]),
39
FREGS_OFFSET("x6", regs[6]),
40
FREGS_OFFSET("x7", regs[7]),
41
FREGS_OFFSET("x8", regs[8]),
42
43
FREGS_OFFSET("x29", fp),
44
FREGS_OFFSET("x30", lr),
45
FREGS_OFFSET("lr", lr),
46
47
FREGS_OFFSET("sp", sp),
48
FREGS_OFFSET("pc", pc),
49
};
50
51
int ftrace_regs_query_register_offset(const char *name)
52
{
53
for (int i = 0; i < ARRAY_SIZE(fregs_offsets); i++) {
54
const struct fregs_offset *roff = &fregs_offsets[i];
55
if (!strcmp(roff->name, name))
56
return roff->offset;
57
}
58
59
return -EINVAL;
60
}
61
#endif
62
63
unsigned long ftrace_call_adjust(unsigned long addr)
64
{
65
/*
66
* When using mcount, addr is the address of the mcount call
67
* instruction, and no adjustment is necessary.
68
*/
69
if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS))
70
return addr;
71
72
/*
73
* When using patchable-function-entry without pre-function NOPS, addr
74
* is the address of the first NOP after the function entry point.
75
*
76
* The compiler has either generated:
77
*
78
* addr+00: func: NOP // To be patched to MOV X9, LR
79
* addr+04: NOP // To be patched to BL <caller>
80
*
81
* Or:
82
*
83
* addr-04: BTI C
84
* addr+00: func: NOP // To be patched to MOV X9, LR
85
* addr+04: NOP // To be patched to BL <caller>
86
*
87
* We must adjust addr to the address of the NOP which will be patched
88
* to `BL <caller>`, which is at `addr + 4` bytes in either case.
89
*
90
*/
91
if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
92
return addr + AARCH64_INSN_SIZE;
93
94
/*
95
* When using patchable-function-entry with pre-function NOPs, addr is
96
* the address of the first pre-function NOP.
97
*
98
* Starting from an 8-byte aligned base, the compiler has either
99
* generated:
100
*
101
* addr+00: NOP // Literal (first 32 bits)
102
* addr+04: NOP // Literal (last 32 bits)
103
* addr+08: func: NOP // To be patched to MOV X9, LR
104
* addr+12: NOP // To be patched to BL <caller>
105
*
106
* Or:
107
*
108
* addr+00: NOP // Literal (first 32 bits)
109
* addr+04: NOP // Literal (last 32 bits)
110
* addr+08: func: BTI C
111
* addr+12: NOP // To be patched to MOV X9, LR
112
* addr+16: NOP // To be patched to BL <caller>
113
*
114
* We must adjust addr to the address of the NOP which will be patched
115
* to `BL <caller>`, which is at either addr+12 or addr+16 depending on
116
* whether there is a BTI.
117
*/
118
119
if (!IS_ALIGNED(addr, sizeof(unsigned long))) {
120
WARN_RATELIMIT(1, "Misaligned patch-site %pS\n",
121
(void *)(addr + 8));
122
return 0;
123
}
124
125
/* Skip the NOPs placed before the function entry point */
126
addr += 2 * AARCH64_INSN_SIZE;
127
128
/* Skip any BTI */
129
if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) {
130
u32 insn = le32_to_cpu(*(__le32 *)addr);
131
132
if (aarch64_insn_is_bti(insn)) {
133
addr += AARCH64_INSN_SIZE;
134
} else if (insn != aarch64_insn_gen_nop()) {
135
WARN_RATELIMIT(1, "unexpected insn in patch-site %pS: 0x%08x\n",
136
(void *)addr, insn);
137
}
138
}
139
140
/* Skip the first NOP after function entry */
141
addr += AARCH64_INSN_SIZE;
142
143
return addr;
144
}
145
146
/* Convert fentry_ip to the symbol address without kallsyms */
147
unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip)
148
{
149
u32 insn;
150
151
/*
152
* When using patchable-function-entry without pre-function NOPS, ftrace
153
* entry is the address of the first NOP after the function entry point.
154
*
155
* The compiler has either generated:
156
*
157
* func+00: func: NOP // To be patched to MOV X9, LR
158
* func+04: NOP // To be patched to BL <caller>
159
*
160
* Or:
161
*
162
* func-04: BTI C
163
* func+00: func: NOP // To be patched to MOV X9, LR
164
* func+04: NOP // To be patched to BL <caller>
165
*
166
* The fentry_ip is the address of `BL <caller>` which is at `func + 4`
167
* bytes in either case.
168
*/
169
if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
170
return fentry_ip - AARCH64_INSN_SIZE;
171
172
/*
173
* When using patchable-function-entry with pre-function NOPs, BTI is
174
* a bit different.
175
*
176
* func+00: func: NOP // To be patched to MOV X9, LR
177
* func+04: NOP // To be patched to BL <caller>
178
*
179
* Or:
180
*
181
* func+00: func: BTI C
182
* func+04: NOP // To be patched to MOV X9, LR
183
* func+08: NOP // To be patched to BL <caller>
184
*
185
* The fentry_ip is the address of `BL <caller>` which is at either
186
* `func + 4` or `func + 8` depends on whether there is a BTI.
187
*/
188
189
/* If there is no BTI, the func address should be one instruction before. */
190
if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
191
return fentry_ip - AARCH64_INSN_SIZE;
192
193
/* We want to be extra safe in case entry ip is on the page edge,
194
* but otherwise we need to avoid get_kernel_nofault()'s overhead.
195
*/
196
if ((fentry_ip & ~PAGE_MASK) < AARCH64_INSN_SIZE * 2) {
197
if (get_kernel_nofault(insn, (u32 *)(fentry_ip - AARCH64_INSN_SIZE * 2)))
198
return 0;
199
} else {
200
insn = *(u32 *)(fentry_ip - AARCH64_INSN_SIZE * 2);
201
}
202
203
if (aarch64_insn_is_bti(le32_to_cpu((__le32)insn)))
204
return fentry_ip - AARCH64_INSN_SIZE * 2;
205
206
return fentry_ip - AARCH64_INSN_SIZE;
207
}
208
209
/*
210
* Replace a single instruction, which may be a branch or NOP.
211
* If @validate == true, a replaced instruction is checked against 'old'.
212
*/
213
static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
214
bool validate)
215
{
216
u32 replaced;
217
218
/*
219
* Note:
220
* We are paranoid about modifying text, as if a bug were to happen, it
221
* could cause us to read or write to someplace that could cause harm.
222
* Carefully read and modify the code with aarch64_insn_*() which uses
223
* probe_kernel_*(), and make sure what we read is what we expected it
224
* to be before modifying it.
225
*/
226
if (validate) {
227
if (aarch64_insn_read((void *)pc, &replaced))
228
return -EFAULT;
229
230
if (replaced != old)
231
return -EINVAL;
232
}
233
if (aarch64_insn_patch_text_nosync((void *)pc, new))
234
return -EPERM;
235
236
return 0;
237
}
238
239
/*
240
* Replace tracer function in ftrace_caller()
241
*/
242
int ftrace_update_ftrace_func(ftrace_func_t func)
243
{
244
unsigned long pc;
245
u32 new;
246
247
/*
248
* When using CALL_OPS, the function to call is associated with the
249
* call site, and we don't have a global function pointer to update.
250
*/
251
if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
252
return 0;
253
254
pc = (unsigned long)ftrace_call;
255
new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func,
256
AARCH64_INSN_BRANCH_LINK);
257
258
return ftrace_modify_code(pc, 0, new, false);
259
}
260
261
static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
262
{
263
#ifdef CONFIG_MODULES
264
struct plt_entry *plt = NULL;
265
266
if (within_module_mem_type(addr, mod, MOD_INIT_TEXT))
267
plt = mod->arch.init_ftrace_trampolines;
268
else if (within_module_mem_type(addr, mod, MOD_TEXT))
269
plt = mod->arch.ftrace_trampolines;
270
else
271
return NULL;
272
273
return &plt[FTRACE_PLT_IDX];
274
#else
275
return NULL;
276
#endif
277
}
278
279
static bool reachable_by_bl(unsigned long addr, unsigned long pc)
280
{
281
long offset = (long)addr - (long)pc;
282
283
return offset >= -SZ_128M && offset < SZ_128M;
284
}
285
286
/*
287
* Find the address the callsite must branch to in order to reach '*addr'.
288
*
289
* Due to the limited range of 'BL' instructions, modules may be placed too far
290
* away to branch directly and must use a PLT.
291
*
292
* Returns true when '*addr' contains a reachable target address, or has been
293
* modified to contain a PLT address. Returns false otherwise.
294
*/
295
static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
296
struct module *mod,
297
unsigned long *addr)
298
{
299
unsigned long pc = rec->ip;
300
struct plt_entry *plt;
301
302
/*
303
* If a custom trampoline is unreachable, rely on the ftrace_caller
304
* trampoline which knows how to indirectly reach that trampoline
305
* through ops->direct_call.
306
*/
307
if (*addr != FTRACE_ADDR && !reachable_by_bl(*addr, pc))
308
*addr = FTRACE_ADDR;
309
310
/*
311
* When the target is within range of the 'BL' instruction, use 'addr'
312
* as-is and branch to that directly.
313
*/
314
if (reachable_by_bl(*addr, pc))
315
return true;
316
317
/*
318
* When the target is outside of the range of a 'BL' instruction, we
319
* must use a PLT to reach it. We can only place PLTs for modules, and
320
* only when module PLT support is built-in.
321
*/
322
if (!IS_ENABLED(CONFIG_MODULES))
323
return false;
324
325
/*
326
* 'mod' is only set at module load time, but if we end up
327
* dealing with an out-of-range condition, we can assume it
328
* is due to a module being loaded far away from the kernel.
329
*
330
* NOTE: __module_text_address() must be called within a RCU read
331
* section, but we can rely on ftrace_lock to ensure that 'mod'
332
* retains its validity throughout the remainder of this code.
333
*/
334
if (!mod) {
335
guard(rcu)();
336
mod = __module_text_address(pc);
337
}
338
339
if (WARN_ON(!mod))
340
return false;
341
342
plt = get_ftrace_plt(mod, pc);
343
if (!plt) {
344
pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
345
return false;
346
}
347
348
*addr = (unsigned long)plt;
349
return true;
350
}
351
352
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
353
static const struct ftrace_ops *arm64_rec_get_ops(struct dyn_ftrace *rec)
354
{
355
const struct ftrace_ops *ops = NULL;
356
357
if (rec->flags & FTRACE_FL_CALL_OPS_EN) {
358
ops = ftrace_find_unique_ops(rec);
359
WARN_ON_ONCE(!ops);
360
}
361
362
if (!ops)
363
ops = &ftrace_list_ops;
364
365
return ops;
366
}
367
368
static int ftrace_rec_set_ops(const struct dyn_ftrace *rec,
369
const struct ftrace_ops *ops)
370
{
371
unsigned long literal = ALIGN_DOWN(rec->ip - 12, 8);
372
return aarch64_insn_write_literal_u64((void *)literal,
373
(unsigned long)ops);
374
}
375
376
static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec)
377
{
378
return ftrace_rec_set_ops(rec, &ftrace_nop_ops);
379
}
380
381
static int ftrace_rec_update_ops(struct dyn_ftrace *rec)
382
{
383
return ftrace_rec_set_ops(rec, arm64_rec_get_ops(rec));
384
}
385
#else
386
static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) { return 0; }
387
static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; }
388
#endif
389
390
/*
391
* Turn on the call to ftrace_caller() in instrumented function
392
*/
393
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
394
{
395
unsigned long pc = rec->ip;
396
u32 old, new;
397
int ret;
398
399
ret = ftrace_rec_update_ops(rec);
400
if (ret)
401
return ret;
402
403
if (!ftrace_find_callable_addr(rec, NULL, &addr))
404
return -EINVAL;
405
406
old = aarch64_insn_gen_nop();
407
new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
408
409
return ftrace_modify_code(pc, old, new, true);
410
}
411
412
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
413
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
414
unsigned long addr)
415
{
416
unsigned long pc = rec->ip;
417
u32 old, new;
418
int ret;
419
420
ret = ftrace_rec_set_ops(rec, arm64_rec_get_ops(rec));
421
if (ret)
422
return ret;
423
424
if (!ftrace_find_callable_addr(rec, NULL, &old_addr))
425
return -EINVAL;
426
if (!ftrace_find_callable_addr(rec, NULL, &addr))
427
return -EINVAL;
428
429
old = aarch64_insn_gen_branch_imm(pc, old_addr,
430
AARCH64_INSN_BRANCH_LINK);
431
new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
432
433
return ftrace_modify_code(pc, old, new, true);
434
}
435
#endif
436
437
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
438
/*
439
* The compiler has inserted two NOPs before the regular function prologue.
440
* All instrumented functions follow the AAPCS, so x0-x8 and x19-x30 are live,
441
* and x9-x18 are free for our use.
442
*
443
* At runtime we want to be able to swing a single NOP <-> BL to enable or
444
* disable the ftrace call. The BL requires us to save the original LR value,
445
* so here we insert a <MOV X9, LR> over the first NOP so the instructions
446
* before the regular prologue are:
447
*
448
* | Compiled | Disabled | Enabled |
449
* +----------+------------+------------+
450
* | NOP | MOV X9, LR | MOV X9, LR |
451
* | NOP | NOP | BL <entry> |
452
*
453
* The LR value will be recovered by ftrace_caller, and restored into LR
454
* before returning to the regular function prologue. When a function is not
455
* being traced, the MOV is not harmful given x9 is not live per the AAPCS.
456
*
457
* Note: ftrace_process_locs() has pre-adjusted rec->ip to be the address of
458
* the BL.
459
*/
460
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
461
{
462
unsigned long pc = rec->ip - AARCH64_INSN_SIZE;
463
u32 old, new;
464
int ret;
465
466
ret = ftrace_rec_set_nop_ops(rec);
467
if (ret)
468
return ret;
469
470
old = aarch64_insn_gen_nop();
471
new = aarch64_insn_gen_move_reg(AARCH64_INSN_REG_9,
472
AARCH64_INSN_REG_LR,
473
AARCH64_INSN_VARIANT_64BIT);
474
return ftrace_modify_code(pc, old, new, true);
475
}
476
#endif
477
478
/*
479
* Turn off the call to ftrace_caller() in instrumented function
480
*/
481
int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
482
unsigned long addr)
483
{
484
unsigned long pc = rec->ip;
485
u32 old = 0, new;
486
int ret;
487
488
new = aarch64_insn_gen_nop();
489
490
ret = ftrace_rec_set_nop_ops(rec);
491
if (ret)
492
return ret;
493
494
/*
495
* When using mcount, callsites in modules may have been initalized to
496
* call an arbitrary module PLT (which redirects to the _mcount stub)
497
* rather than the ftrace PLT we'll use at runtime (which redirects to
498
* the ftrace trampoline). We can ignore the old PLT when initializing
499
* the callsite.
500
*
501
* Note: 'mod' is only set at module load time.
502
*/
503
if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) && mod)
504
return aarch64_insn_patch_text_nosync((void *)pc, new);
505
506
if (!ftrace_find_callable_addr(rec, mod, &addr))
507
return -EINVAL;
508
509
old = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
510
511
return ftrace_modify_code(pc, old, new, true);
512
}
513
514
void arch_ftrace_update_code(int command)
515
{
516
command |= FTRACE_MAY_SLEEP;
517
ftrace_modify_all_code(command);
518
}
519
520
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
521
/*
522
* function_graph tracer expects ftrace_return_to_handler() to be called
523
* on the way back to parent. For this purpose, this function is called
524
* in _mcount() or ftrace_caller() to replace return address (*parent) on
525
* the call stack to return_to_handler.
526
*/
527
void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
528
unsigned long frame_pointer)
529
{
530
unsigned long return_hooker = (unsigned long)&return_to_handler;
531
unsigned long old;
532
533
if (unlikely(atomic_read(&current->tracing_graph_pause)))
534
return;
535
536
/*
537
* Note:
538
* No protection against faulting at *parent, which may be seen
539
* on other archs. It's unlikely on AArch64.
540
*/
541
old = *parent;
542
543
if (!function_graph_enter(old, self_addr, frame_pointer,
544
(void *)frame_pointer)) {
545
*parent = return_hooker;
546
}
547
}
548
549
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
550
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
551
struct ftrace_ops *op, struct ftrace_regs *fregs)
552
{
553
unsigned long return_hooker = (unsigned long)&return_to_handler;
554
unsigned long frame_pointer = arch_ftrace_regs(fregs)->fp;
555
unsigned long *parent = &arch_ftrace_regs(fregs)->lr;
556
unsigned long old;
557
558
if (unlikely(atomic_read(&current->tracing_graph_pause)))
559
return;
560
561
old = *parent;
562
563
if (!function_graph_enter_regs(old, ip, frame_pointer,
564
(void *)frame_pointer, fregs)) {
565
*parent = return_hooker;
566
}
567
}
568
#else
569
/*
570
* Turn on/off the call to ftrace_graph_caller() in ftrace_caller()
571
* depending on @enable.
572
*/
573
static int ftrace_modify_graph_caller(bool enable)
574
{
575
unsigned long pc = (unsigned long)&ftrace_graph_call;
576
u32 branch, nop;
577
578
branch = aarch64_insn_gen_branch_imm(pc,
579
(unsigned long)ftrace_graph_caller,
580
AARCH64_INSN_BRANCH_NOLINK);
581
nop = aarch64_insn_gen_nop();
582
583
if (enable)
584
return ftrace_modify_code(pc, nop, branch, true);
585
else
586
return ftrace_modify_code(pc, branch, nop, true);
587
}
588
589
int ftrace_enable_ftrace_graph_caller(void)
590
{
591
return ftrace_modify_graph_caller(true);
592
}
593
594
int ftrace_disable_ftrace_graph_caller(void)
595
{
596
return ftrace_modify_graph_caller(false);
597
}
598
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
599
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
600
601