linux/arch/csky/kernel/probes/uprobes.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com>
   4 */
   5#include <linux/highmem.h>
   6#include <linux/ptrace.h>
   7#include <linux/uprobes.h>
   8#include <asm/cacheflush.h>
   9
  10#include "decode-insn.h"
  11
  12#define UPROBE_TRAP_NR  UINT_MAX
  13
  14bool is_swbp_insn(uprobe_opcode_t *insn)
  15{
  16        return (*insn & 0xffff) == UPROBE_SWBP_INSN;
  17}
  18
  19unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
  20{
  21        return instruction_pointer(regs);
  22}
  23
  24int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
  25                unsigned long addr)
  26{
  27        probe_opcode_t insn;
  28
  29        insn = *(probe_opcode_t *)(&auprobe->insn[0]);
  30
  31        auprobe->insn_size = is_insn32(insn) ? 4 : 2;
  32
  33        switch (csky_probe_decode_insn(&insn, &auprobe->api)) {
  34        case INSN_REJECTED:
  35                return -EINVAL;
  36
  37        case INSN_GOOD_NO_SLOT:
  38                auprobe->simulate = true;
  39                break;
  40
  41        default:
  42                break;
  43        }
  44
  45        return 0;
  46}
  47
  48int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
  49{
  50        struct uprobe_task *utask = current->utask;
  51
  52        utask->autask.saved_trap_no = current->thread.trap_no;
  53        current->thread.trap_no = UPROBE_TRAP_NR;
  54
  55        instruction_pointer_set(regs, utask->xol_vaddr);
  56
  57        user_enable_single_step(current);
  58
  59        return 0;
  60}
  61
  62int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
  63{
  64        struct uprobe_task *utask = current->utask;
  65
  66        WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR);
  67
  68        instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
  69
  70        user_disable_single_step(current);
  71
  72        return 0;
  73}
  74
  75bool arch_uprobe_xol_was_trapped(struct task_struct *t)
  76{
  77        if (t->thread.trap_no != UPROBE_TRAP_NR)
  78                return true;
  79
  80        return false;
  81}
  82
  83bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
  84{
  85        probe_opcode_t insn;
  86        unsigned long addr;
  87
  88        if (!auprobe->simulate)
  89                return false;
  90
  91        insn = *(probe_opcode_t *)(&auprobe->insn[0]);
  92        addr = instruction_pointer(regs);
  93
  94        if (auprobe->api.handler)
  95                auprobe->api.handler(insn, addr, regs);
  96
  97        return true;
  98}
  99
 100void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 101{
 102        struct uprobe_task *utask = current->utask;
 103
 104        /*
 105         * Task has received a fatal signal, so reset back to probbed
 106         * address.
 107         */
 108        instruction_pointer_set(regs, utask->vaddr);
 109
 110        user_disable_single_step(current);
 111}
 112
 113bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
 114                struct pt_regs *regs)
 115{
 116        if (ctx == RP_CHECK_CHAIN_CALL)
 117                return regs->usp <= ret->stack;
 118        else
 119                return regs->usp < ret->stack;
 120}
 121
 122unsigned long
 123arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
 124                                  struct pt_regs *regs)
 125{
 126        unsigned long ra;
 127
 128        ra = regs->lr;
 129
 130        regs->lr = trampoline_vaddr;
 131
 132        return ra;
 133}
 134
 135int arch_uprobe_exception_notify(struct notifier_block *self,
 136                                 unsigned long val, void *data)
 137{
 138        return NOTIFY_DONE;
 139}
 140
 141int uprobe_breakpoint_handler(struct pt_regs *regs)
 142{
 143        if (uprobe_pre_sstep_notifier(regs))
 144                return 1;
 145
 146        return 0;
 147}
 148
 149int uprobe_single_step_handler(struct pt_regs *regs)
 150{
 151        if (uprobe_post_sstep_notifier(regs))
 152                return 1;
 153
 154        return 0;
 155}
 156