.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * arch/arm/kernel/kprobes.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
8 | 9 | * |
---|
9 | 10 | * Nicolas Pitre <nico@marvell.com> |
---|
10 | 11 | * Copyright (C) 2007 Marvell Ltd. |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify |
---|
13 | | - * it under the terms of the GNU General Public License version 2 as |
---|
14 | | - * published by the Free Software Foundation. |
---|
15 | | - * |
---|
16 | | - * This program is distributed in the hope that it will be useful, |
---|
17 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
19 | | - * General Public License for more details. |
---|
20 | 12 | */ |
---|
21 | 13 | |
---|
22 | 14 | #include <linux/kernel.h> |
---|
.. | .. |
---|
239 | 231 | * kprobe, and that level is reserved for user kprobe handlers, so we can't |
---|
240 | 232 | * risk encountering a new kprobe in an interrupt handler. |
---|
241 | 233 | */ |
---|
242 | | -void __kprobes kprobe_handler(struct pt_regs *regs) |
---|
| 234 | +static void __kprobes kprobe_handler(struct pt_regs *regs) |
---|
243 | 235 | { |
---|
244 | 236 | struct kprobe *p, *cur; |
---|
245 | 237 | struct kprobe_ctlblk *kcb; |
---|
.. | .. |
---|
288 | 280 | /* A nested probe was hit in FIQ, it is a BUG */ |
---|
289 | 281 | pr_warn("Unrecoverable kprobe detected.\n"); |
---|
290 | 282 | dump_kprobe(p); |
---|
291 | | - /* fall through */ |
---|
| 283 | + fallthrough; |
---|
292 | 284 | default: |
---|
293 | 285 | /* impossible cases */ |
---|
294 | 286 | BUG(); |
---|
.. | .. |
---|
421 | 413 | /* Called from kretprobe_trampoline */ |
---|
422 | 414 | static __used __kprobes void *trampoline_handler(struct pt_regs *regs) |
---|
423 | 415 | { |
---|
424 | | - struct kretprobe_instance *ri = NULL; |
---|
425 | | - struct hlist_head *head, empty_rp; |
---|
426 | | - struct hlist_node *tmp; |
---|
427 | | - unsigned long flags, orig_ret_address = 0; |
---|
428 | | - unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; |
---|
429 | | - kprobe_opcode_t *correct_ret_addr = NULL; |
---|
430 | | - |
---|
431 | | - INIT_HLIST_HEAD(&empty_rp); |
---|
432 | | - kretprobe_hash_lock(current, &head, &flags); |
---|
433 | | - |
---|
434 | | - /* |
---|
435 | | - * It is possible to have multiple instances associated with a given |
---|
436 | | - * task either because multiple functions in the call path have |
---|
437 | | - * a return probe installed on them, and/or more than one return |
---|
438 | | - * probe was registered for a target function. |
---|
439 | | - * |
---|
440 | | - * We can handle this because: |
---|
441 | | - * - instances are always inserted at the head of the list |
---|
442 | | - * - when multiple return probes are registered for the same |
---|
443 | | - * function, the first instance's ret_addr will point to the |
---|
444 | | - * real return address, and all the rest will point to |
---|
445 | | - * kretprobe_trampoline |
---|
446 | | - */ |
---|
447 | | - hlist_for_each_entry_safe(ri, tmp, head, hlist) { |
---|
448 | | - if (ri->task != current) |
---|
449 | | - /* another task is sharing our hash bucket */ |
---|
450 | | - continue; |
---|
451 | | - |
---|
452 | | - orig_ret_address = (unsigned long)ri->ret_addr; |
---|
453 | | - |
---|
454 | | - if (orig_ret_address != trampoline_address) |
---|
455 | | - /* |
---|
456 | | - * This is the real return address. Any other |
---|
457 | | - * instances associated with this task are for |
---|
458 | | - * other calls deeper on the call stack |
---|
459 | | - */ |
---|
460 | | - break; |
---|
461 | | - } |
---|
462 | | - |
---|
463 | | - kretprobe_assert(ri, orig_ret_address, trampoline_address); |
---|
464 | | - |
---|
465 | | - correct_ret_addr = ri->ret_addr; |
---|
466 | | - hlist_for_each_entry_safe(ri, tmp, head, hlist) { |
---|
467 | | - if (ri->task != current) |
---|
468 | | - /* another task is sharing our hash bucket */ |
---|
469 | | - continue; |
---|
470 | | - |
---|
471 | | - orig_ret_address = (unsigned long)ri->ret_addr; |
---|
472 | | - if (ri->rp && ri->rp->handler) { |
---|
473 | | - __this_cpu_write(current_kprobe, &ri->rp->kp); |
---|
474 | | - get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; |
---|
475 | | - ri->ret_addr = correct_ret_addr; |
---|
476 | | - ri->rp->handler(ri, regs); |
---|
477 | | - __this_cpu_write(current_kprobe, NULL); |
---|
478 | | - } |
---|
479 | | - |
---|
480 | | - recycle_rp_inst(ri, &empty_rp); |
---|
481 | | - |
---|
482 | | - if (orig_ret_address != trampoline_address) |
---|
483 | | - /* |
---|
484 | | - * This is the real return address. Any other |
---|
485 | | - * instances associated with this task are for |
---|
486 | | - * other calls deeper on the call stack |
---|
487 | | - */ |
---|
488 | | - break; |
---|
489 | | - } |
---|
490 | | - |
---|
491 | | - kretprobe_hash_unlock(current, &flags); |
---|
492 | | - |
---|
493 | | - hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { |
---|
494 | | - hlist_del(&ri->hlist); |
---|
495 | | - kfree(ri); |
---|
496 | | - } |
---|
497 | | - |
---|
498 | | - return (void *)orig_ret_address; |
---|
| 416 | + return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, |
---|
| 417 | + (void *)regs->ARM_fp); |
---|
499 | 418 | } |
---|
500 | 419 | |
---|
501 | 420 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, |
---|
502 | 421 | struct pt_regs *regs) |
---|
503 | 422 | { |
---|
504 | 423 | ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr; |
---|
| 424 | + ri->fp = (void *)regs->ARM_fp; |
---|
505 | 425 | |
---|
506 | 426 | /* Replace the return addr with trampoline addr. */ |
---|
507 | 427 | regs->ARM_lr = (unsigned long)&kretprobe_trampoline; |
---|