| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 2 | +#include <linux/objtool.h> |
|---|
| 1 | 3 | #include <linux/module.h> |
|---|
| 2 | 4 | #include <linux/sort.h> |
|---|
| 3 | 5 | #include <asm/ptrace.h> |
|---|
| .. | .. |
|---|
| 7 | 9 | #include <asm/orc_lookup.h> |
|---|
| 8 | 10 | |
|---|
| 9 | 11 | #define orc_warn(fmt, ...) \ |
|---|
| 10 | | - printk_deferred_once(KERN_WARNING pr_fmt("WARNING: " fmt), ##__VA_ARGS__) |
|---|
| 12 | + printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__) |
|---|
| 13 | + |
|---|
| 14 | +#define orc_warn_current(args...) \ |
|---|
| 15 | +({ \ |
|---|
| 16 | + if (state->task == current) \ |
|---|
| 17 | + orc_warn(args); \ |
|---|
| 18 | +}) |
|---|
| 11 | 19 | |
|---|
| 12 | 20 | extern int __start_orc_unwind_ip[]; |
|---|
| 13 | 21 | extern int __stop_orc_unwind_ip[]; |
|---|
| 14 | 22 | extern struct orc_entry __start_orc_unwind[]; |
|---|
| 15 | 23 | extern struct orc_entry __stop_orc_unwind[]; |
|---|
| 16 | 24 | |
|---|
| 17 | | -static DEFINE_MUTEX(sort_mutex); |
|---|
| 18 | | -int *cur_orc_ip_table = __start_orc_unwind_ip; |
|---|
| 19 | | -struct orc_entry *cur_orc_table = __start_orc_unwind; |
|---|
| 20 | | - |
|---|
| 21 | | -unsigned int lookup_num_blocks; |
|---|
| 22 | | -bool orc_init; |
|---|
| 25 | +static bool orc_init __ro_after_init; |
|---|
| 26 | +static unsigned int lookup_num_blocks __ro_after_init; |
|---|
| 23 | 27 | |
|---|
| 24 | 28 | static inline unsigned long orc_ip(const int *ip) |
|---|
| 25 | 29 | { |
|---|
| .. | .. |
|---|
| 81 | 85 | * But they are copies of the ftrace entries that are static and |
|---|
| 82 | 86 | * defined in ftrace_*.S, which do have orc entries. |
|---|
| 83 | 87 | * |
|---|
| 84 | | - * If the undwinder comes across a ftrace trampoline, then find the |
|---|
| 88 | + * If the unwinder comes across a ftrace trampoline, then find the |
|---|
| 85 | 89 | * ftrace function that was used to create it, and use that ftrace |
|---|
| 86 | | - * function's orc entrie, as the placement of the return code in |
|---|
| 90 | + * function's orc entry, as the placement of the return code in |
|---|
| 87 | 91 | * the stack will be identical. |
|---|
| 88 | 92 | */ |
|---|
| 89 | 93 | static struct orc_entry *orc_ftrace_find(unsigned long ip) |
|---|
| 90 | 94 | { |
|---|
| 91 | 95 | struct ftrace_ops *ops; |
|---|
| 92 | | - unsigned long caller; |
|---|
| 96 | + unsigned long tramp_addr, offset; |
|---|
| 93 | 97 | |
|---|
| 94 | 98 | ops = ftrace_ops_trampoline(ip); |
|---|
| 95 | 99 | if (!ops) |
|---|
| 96 | 100 | return NULL; |
|---|
| 97 | 101 | |
|---|
| 102 | + /* Set tramp_addr to the start of the code copied by the trampoline */ |
|---|
| 98 | 103 | if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) |
|---|
| 99 | | - caller = (unsigned long)ftrace_regs_call; |
|---|
| 104 | + tramp_addr = (unsigned long)ftrace_regs_caller; |
|---|
| 100 | 105 | else |
|---|
| 101 | | - caller = (unsigned long)ftrace_call; |
|---|
| 106 | + tramp_addr = (unsigned long)ftrace_caller; |
|---|
| 107 | + |
|---|
| 108 | + /* Now place tramp_addr to the location within the trampoline ip is at */ |
|---|
| 109 | + offset = ip - ops->trampoline; |
|---|
| 110 | + tramp_addr += offset; |
|---|
| 102 | 111 | |
|---|
| 103 | 112 | /* Prevent unlikely recursion */ |
|---|
| 104 | | - if (ip == caller) |
|---|
| 113 | + if (ip == tramp_addr) |
|---|
| 105 | 114 | return NULL; |
|---|
| 106 | 115 | |
|---|
| 107 | | - return orc_find(caller); |
|---|
| 116 | + return orc_find(tramp_addr); |
|---|
| 108 | 117 | } |
|---|
| 109 | 118 | #else |
|---|
| 110 | 119 | static struct orc_entry *orc_ftrace_find(unsigned long ip) |
|---|
| .. | .. |
|---|
| 124 | 133 | .sp_offset = sizeof(long), |
|---|
| 125 | 134 | .sp_reg = ORC_REG_SP, |
|---|
| 126 | 135 | .bp_reg = ORC_REG_UNDEFINED, |
|---|
| 127 | | - .type = ORC_TYPE_CALL |
|---|
| 136 | + .type = UNWIND_HINT_TYPE_CALL |
|---|
| 137 | +}; |
|---|
| 138 | + |
|---|
| 139 | +/* Fake frame pointer entry -- used as a fallback for generated code */ |
|---|
| 140 | +static struct orc_entry orc_fp_entry = { |
|---|
| 141 | + .type = UNWIND_HINT_TYPE_CALL, |
|---|
| 142 | + .sp_reg = ORC_REG_BP, |
|---|
| 143 | + .sp_offset = 16, |
|---|
| 144 | + .bp_reg = ORC_REG_PREV_SP, |
|---|
| 145 | + .bp_offset = -16, |
|---|
| 146 | + .end = 0, |
|---|
| 128 | 147 | }; |
|---|
| 129 | 148 | |
|---|
| 130 | 149 | static struct orc_entry *orc_find(unsigned long ip) |
|---|
| .. | .. |
|---|
| 173 | 192 | return orc_ftrace_find(ip); |
|---|
| 174 | 193 | } |
|---|
| 175 | 194 | |
|---|
| 195 | +#ifdef CONFIG_MODULES |
|---|
| 196 | + |
|---|
| 197 | +static DEFINE_MUTEX(sort_mutex); |
|---|
| 198 | +static int *cur_orc_ip_table = __start_orc_unwind_ip; |
|---|
| 199 | +static struct orc_entry *cur_orc_table = __start_orc_unwind; |
|---|
| 200 | + |
|---|
| 176 | 201 | static void orc_sort_swap(void *_a, void *_b, int size) |
|---|
| 177 | 202 | { |
|---|
| 178 | 203 | struct orc_entry *orc_a, *orc_b; |
|---|
| .. | .. |
|---|
| 215 | 240 | return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; |
|---|
| 216 | 241 | } |
|---|
| 217 | 242 | |
|---|
| 218 | | -#ifdef CONFIG_MODULES |
|---|
| 219 | 243 | void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size, |
|---|
| 220 | 244 | void *_orc, size_t orc_size) |
|---|
| 221 | 245 | { |
|---|
| .. | .. |
|---|
| 259 | 283 | return; |
|---|
| 260 | 284 | } |
|---|
| 261 | 285 | |
|---|
| 262 | | - /* Sort the .orc_unwind and .orc_unwind_ip tables: */ |
|---|
| 263 | | - sort(__start_orc_unwind_ip, num_entries, sizeof(int), orc_sort_cmp, |
|---|
| 264 | | - orc_sort_swap); |
|---|
| 286 | + /* |
|---|
| 287 | + * Note, the orc_unwind and orc_unwind_ip tables were already |
|---|
| 288 | + * sorted at build time via the 'sorttable' tool. |
|---|
| 289 | + * It's ready for binary search straight away, no need to sort it. |
|---|
| 290 | + */ |
|---|
| 265 | 291 | |
|---|
| 266 | 292 | /* Initialize the fast lookup table: */ |
|---|
| 267 | 293 | lookup_num_blocks = orc_lookup_end - orc_lookup; |
|---|
| .. | .. |
|---|
| 420 | 446 | * call instruction itself. |
|---|
| 421 | 447 | */ |
|---|
| 422 | 448 | orc = orc_find(state->signal ? state->ip : state->ip - 1); |
|---|
| 423 | | - if (!orc) |
|---|
| 424 | | - goto err; |
|---|
| 449 | + if (!orc) { |
|---|
| 450 | + /* |
|---|
| 451 | + * As a fallback, try to assume this code uses a frame pointer. |
|---|
| 452 | + * This is useful for generated code, like BPF, which ORC |
|---|
| 453 | + * doesn't know about. This is just a guess, so the rest of |
|---|
| 454 | + * the unwind is no longer considered reliable. |
|---|
| 455 | + */ |
|---|
| 456 | + orc = &orc_fp_entry; |
|---|
| 457 | + state->error = true; |
|---|
| 458 | + } |
|---|
| 425 | 459 | |
|---|
| 426 | 460 | /* End-of-stack check for kernel threads: */ |
|---|
| 427 | 461 | if (orc->sp_reg == ORC_REG_UNDEFINED) { |
|---|
| .. | .. |
|---|
| 453 | 487 | |
|---|
| 454 | 488 | case ORC_REG_R10: |
|---|
| 455 | 489 | if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) { |
|---|
| 456 | | - orc_warn("missing regs for base reg R10 at ip %pB\n", |
|---|
| 457 | | - (void *)state->ip); |
|---|
| 490 | + orc_warn_current("missing R10 value at %pB\n", |
|---|
| 491 | + (void *)state->ip); |
|---|
| 458 | 492 | goto err; |
|---|
| 459 | 493 | } |
|---|
| 460 | 494 | break; |
|---|
| 461 | 495 | |
|---|
| 462 | 496 | case ORC_REG_R13: |
|---|
| 463 | 497 | if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) { |
|---|
| 464 | | - orc_warn("missing regs for base reg R13 at ip %pB\n", |
|---|
| 465 | | - (void *)state->ip); |
|---|
| 498 | + orc_warn_current("missing R13 value at %pB\n", |
|---|
| 499 | + (void *)state->ip); |
|---|
| 466 | 500 | goto err; |
|---|
| 467 | 501 | } |
|---|
| 468 | 502 | break; |
|---|
| 469 | 503 | |
|---|
| 470 | 504 | case ORC_REG_DI: |
|---|
| 471 | 505 | if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) { |
|---|
| 472 | | - orc_warn("missing regs for base reg DI at ip %pB\n", |
|---|
| 473 | | - (void *)state->ip); |
|---|
| 506 | + orc_warn_current("missing RDI value at %pB\n", |
|---|
| 507 | + (void *)state->ip); |
|---|
| 474 | 508 | goto err; |
|---|
| 475 | 509 | } |
|---|
| 476 | 510 | break; |
|---|
| 477 | 511 | |
|---|
| 478 | 512 | case ORC_REG_DX: |
|---|
| 479 | 513 | if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) { |
|---|
| 480 | | - orc_warn("missing regs for base reg DX at ip %pB\n", |
|---|
| 481 | | - (void *)state->ip); |
|---|
| 514 | + orc_warn_current("missing DX value at %pB\n", |
|---|
| 515 | + (void *)state->ip); |
|---|
| 482 | 516 | goto err; |
|---|
| 483 | 517 | } |
|---|
| 484 | 518 | break; |
|---|
| 485 | 519 | |
|---|
| 486 | 520 | default: |
|---|
| 487 | | - orc_warn("unknown SP base reg %d for ip %pB\n", |
|---|
| 521 | + orc_warn("unknown SP base reg %d at %pB\n", |
|---|
| 488 | 522 | orc->sp_reg, (void *)state->ip); |
|---|
| 489 | 523 | goto err; |
|---|
| 490 | 524 | } |
|---|
| .. | .. |
|---|
| 496 | 530 | |
|---|
| 497 | 531 | /* Find IP, SP and possibly regs: */ |
|---|
| 498 | 532 | switch (orc->type) { |
|---|
| 499 | | - case ORC_TYPE_CALL: |
|---|
| 533 | + case UNWIND_HINT_TYPE_CALL: |
|---|
| 500 | 534 | ip_p = sp - sizeof(long); |
|---|
| 501 | 535 | |
|---|
| 502 | 536 | if (!deref_stack_reg(state, ip_p, &state->ip)) |
|---|
| .. | .. |
|---|
| 511 | 545 | state->signal = false; |
|---|
| 512 | 546 | break; |
|---|
| 513 | 547 | |
|---|
| 514 | | - case ORC_TYPE_REGS: |
|---|
| 548 | + case UNWIND_HINT_TYPE_REGS: |
|---|
| 515 | 549 | if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) { |
|---|
| 516 | | - orc_warn("can't dereference registers at %p for ip %pB\n", |
|---|
| 517 | | - (void *)sp, (void *)orig_ip); |
|---|
| 550 | + orc_warn_current("can't access registers at %pB\n", |
|---|
| 551 | + (void *)orig_ip); |
|---|
| 518 | 552 | goto err; |
|---|
| 519 | 553 | } |
|---|
| 520 | 554 | |
|---|
| .. | .. |
|---|
| 524 | 558 | state->signal = true; |
|---|
| 525 | 559 | break; |
|---|
| 526 | 560 | |
|---|
| 527 | | - case ORC_TYPE_REGS_IRET: |
|---|
| 561 | + case UNWIND_HINT_TYPE_REGS_PARTIAL: |
|---|
| 528 | 562 | if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) { |
|---|
| 529 | | - orc_warn("can't dereference iret registers at %p for ip %pB\n", |
|---|
| 530 | | - (void *)sp, (void *)orig_ip); |
|---|
| 563 | + orc_warn_current("can't access iret registers at %pB\n", |
|---|
| 564 | + (void *)orig_ip); |
|---|
| 531 | 565 | goto err; |
|---|
| 532 | 566 | } |
|---|
| 533 | 567 | |
|---|
| .. | .. |
|---|
| 539 | 573 | break; |
|---|
| 540 | 574 | |
|---|
| 541 | 575 | default: |
|---|
| 542 | | - orc_warn("unknown .orc_unwind entry type %d for ip %pB\n", |
|---|
| 576 | + orc_warn("unknown .orc_unwind entry type %d at %pB\n", |
|---|
| 543 | 577 | orc->type, (void *)orig_ip); |
|---|
| 544 | 578 | goto err; |
|---|
| 545 | 579 | } |
|---|
| .. | .. |
|---|
| 571 | 605 | if (state->stack_info.type == prev_type && |
|---|
| 572 | 606 | on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) && |
|---|
| 573 | 607 | state->sp <= prev_sp) { |
|---|
| 574 | | - orc_warn("stack going in the wrong direction? ip=%pB\n", |
|---|
| 575 | | - (void *)orig_ip); |
|---|
| 608 | + orc_warn_current("stack going in the wrong direction? at %pB\n", |
|---|
| 609 | + (void *)orig_ip); |
|---|
| 576 | 610 | goto err; |
|---|
| 577 | 611 | } |
|---|
| 578 | 612 | |
|---|
| .. | .. |
|---|
| 611 | 645 | goto the_end; |
|---|
| 612 | 646 | |
|---|
| 613 | 647 | state->ip = regs->ip; |
|---|
| 614 | | - state->sp = kernel_stack_pointer(regs); |
|---|
| 648 | + state->sp = regs->sp; |
|---|
| 615 | 649 | state->bp = regs->bp; |
|---|
| 616 | 650 | state->regs = regs; |
|---|
| 617 | 651 | state->full_regs = true; |
|---|
| .. | .. |
|---|
| 663 | 697 | /* Otherwise, skip ahead to the user-specified starting frame: */ |
|---|
| 664 | 698 | while (!unwind_done(state) && |
|---|
| 665 | 699 | (!on_stack(&state->stack_info, first_frame, sizeof(long)) || |
|---|
| 666 | | - state->sp < (unsigned long)first_frame)) |
|---|
| 700 | + state->sp <= (unsigned long)first_frame)) |
|---|
| 667 | 701 | unwind_next_frame(state); |
|---|
| 668 | 702 | |
|---|
| 669 | 703 | return; |
|---|