linux/arch/mips/kernel/uprobes.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/highmem.h>
   3#include <linux/kdebug.h>
   4#include <linux/types.h>
   5#include <linux/notifier.h>
   6#include <linux/sched.h>
   7#include <linux/uprobes.h>
   8
   9#include <asm/branch.h>
  10#include <asm/cpu-features.h>
  11#include <asm/ptrace.h>
  12
  13#include "probes-common.h"
  14
  15static inline int insn_has_delay_slot(const union mips_instruction insn)
  16{
  17        return __insn_has_delay_slot(insn);
  18}
  19
  20/**
  21 * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
  22 * @mm: the probed address space.
  23 * @arch_uprobe: the probepoint information.
  24 * @addr: virtual address at which to install the probepoint
  25 * Return 0 on success or a -ve number on error.
  26 */
  27int arch_uprobe_analyze_insn(struct arch_uprobe *aup,
  28        struct mm_struct *mm, unsigned long addr)
  29{
  30        union mips_instruction inst;
  31
  32        /*
  33         * For the time being this also blocks attempts to use uprobes with
  34         * MIPS16 and microMIPS.
  35         */
  36        if (addr & 0x03)
  37                return -EINVAL;
  38
  39        inst.word = aup->insn[0];
  40
  41        if (__insn_is_compact_branch(inst)) {
  42                pr_notice("Uprobes for compact branches are not supported\n");
  43                return -EINVAL;
  44        }
  45
  46        aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)];
  47        aup->ixol[1] = UPROBE_BRK_UPROBE_XOL;           /* NOP  */
  48
  49        return 0;
  50}
  51
  52/**
  53 * is_trap_insn - check if the instruction is a trap variant
  54 * @insn: instruction to be checked.
  55 * Returns true if @insn is a trap variant.
  56 *
  57 * This definition overrides the weak definition in kernel/events/uprobes.c.
  58 * and is needed for the case where an architecture has multiple trap
  59 * instructions (like PowerPC or MIPS).  We treat BREAK just like the more
  60 * modern conditional trap instructions.
  61 */
  62bool is_trap_insn(uprobe_opcode_t *insn)
  63{
  64        union mips_instruction inst;
  65
  66        inst.word = *insn;
  67
  68        switch (inst.i_format.opcode) {
  69        case spec_op:
  70                switch (inst.r_format.func) {
  71                case break_op:
  72                case teq_op:
  73                case tge_op:
  74                case tgeu_op:
  75                case tlt_op:
  76                case tltu_op:
  77                case tne_op:
  78                        return true;
  79                }
  80                break;
  81
  82        case bcond_op:  /* Yes, really ...  */
  83                switch (inst.u_format.rt) {
  84                case teqi_op:
  85                case tgei_op:
  86                case tgeiu_op:
  87                case tlti_op:
  88                case tltiu_op:
  89                case tnei_op:
  90                        return true;
  91                }
  92                break;
  93        }
  94
  95        return false;
  96}
  97
  98#define UPROBE_TRAP_NR  ULONG_MAX
  99
 100/*
 101 * arch_uprobe_pre_xol - prepare to execute out of line.
 102 * @auprobe: the probepoint information.
 103 * @regs: reflects the saved user state of current task.
 104 */
 105int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs)
 106{
 107        struct uprobe_task *utask = current->utask;
 108
 109        /*
 110         * Now find the EPC where to resume after the breakpoint has been
 111         * dealt with.  This may require emulation of a branch.
 112         */
 113        aup->resume_epc = regs->cp0_epc + 4;
 114        if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) {
 115                __compute_return_epc_for_insn(regs,
 116                        (union mips_instruction) aup->insn[0]);
 117                aup->resume_epc = regs->cp0_epc;
 118        }
 119        utask->autask.saved_trap_nr = current->thread.trap_nr;
 120        current->thread.trap_nr = UPROBE_TRAP_NR;
 121        regs->cp0_epc = current->utask->xol_vaddr;
 122
 123        return 0;
 124}
 125
 126int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs)
 127{
 128        struct uprobe_task *utask = current->utask;
 129
 130        current->thread.trap_nr = utask->autask.saved_trap_nr;
 131        regs->cp0_epc = aup->resume_epc;
 132
 133        return 0;
 134}
 135
 136/*
 137 * If xol insn itself traps and generates a signal(Say,
 138 * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped
 139 * instruction jumps back to its own address. It is assumed that anything
 140 * like do_page_fault/do_trap/etc sets thread.trap_nr != -1.
 141 *
 142 * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr,
 143 * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to
 144 * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol().
 145 */
 146bool arch_uprobe_xol_was_trapped(struct task_struct *tsk)
 147{
 148        if (tsk->thread.trap_nr != UPROBE_TRAP_NR)
 149                return true;
 150
 151        return false;
 152}
 153
 154int arch_uprobe_exception_notify(struct notifier_block *self,
 155        unsigned long val, void *data)
 156{
 157        struct die_args *args = data;
 158        struct pt_regs *regs = args->regs;
 159
 160        /* regs == NULL is a kernel bug */
 161        if (WARN_ON(!regs))
 162                return NOTIFY_DONE;
 163
 164        /* We are only interested in userspace traps */
 165        if (!user_mode(regs))
 166                return NOTIFY_DONE;
 167
 168        switch (val) {
 169        case DIE_UPROBE:
 170                if (uprobe_pre_sstep_notifier(regs))
 171                        return NOTIFY_STOP;
 172                break;
 173        case DIE_UPROBE_XOL:
 174                if (uprobe_post_sstep_notifier(regs))
 175                        return NOTIFY_STOP;
 176        default:
 177                break;
 178        }
 179
 180        return 0;
 181}
 182
 183/*
 184 * This function gets called when XOL instruction either gets trapped or
 185 * the thread has a fatal signal. Reset the instruction pointer to its
 186 * probed address for the potential restart or for post mortem analysis.
 187 */
 188void arch_uprobe_abort_xol(struct arch_uprobe *aup,
 189        struct pt_regs *regs)
 190{
 191        struct uprobe_task *utask = current->utask;
 192
 193        instruction_pointer_set(regs, utask->vaddr);
 194}
 195
 196unsigned long arch_uretprobe_hijack_return_addr(
 197        unsigned long trampoline_vaddr, struct pt_regs *regs)
 198{
 199        unsigned long ra;
 200
 201        ra = regs->regs[31];
 202
 203        /* Replace the return address with the trampoline address */
 204        regs->regs[31] = trampoline_vaddr;
 205
 206        return ra;
 207}
 208
 209/**
 210 * set_swbp - store breakpoint at a given address.
 211 * @auprobe: arch specific probepoint information.
 212 * @mm: the probed process address space.
 213 * @vaddr: the virtual address to insert the opcode.
 214 *
 215 * For mm @mm, store the breakpoint instruction at @vaddr.
 216 * Return 0 (success) or a negative errno.
 217 *
 218 * This version overrides the weak version in kernel/events/uprobes.c.
 219 * It is required to handle MIPS16 and microMIPS.
 220 */
 221int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
 222        unsigned long vaddr)
 223{
 224        return uprobe_write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN);
 225}
 226
 227void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
 228                                  void *src, unsigned long len)
 229{
 230        unsigned long kaddr, kstart;
 231
 232        /* Initialize the slot */
 233        kaddr = (unsigned long)kmap_atomic(page);
 234        kstart = kaddr + (vaddr & ~PAGE_MASK);
 235        memcpy((void *)kstart, src, len);
 236        flush_icache_range(kstart, kstart + len);
 237        kunmap_atomic((void *)kaddr);
 238}
 239
 240/**
 241 * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
 242 * @regs: Reflects the saved state of the task after it has hit a breakpoint
 243 * instruction.
 244 * Return the address of the breakpoint instruction.
 245 *
 246 * This overrides the weak version in kernel/events/uprobes.c.
 247 */
 248unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
 249{
 250        return instruction_pointer(regs);
 251}
 252
 253/*
 254 * See if the instruction can be emulated.
 255 * Returns true if instruction was emulated, false otherwise.
 256 *
 257 * For now we always emulate so this function just returns false.
 258 */
 259bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 260{
 261        return false;
 262}
 263