root/arch/mips/kernel/uprobes.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. insn_has_delay_slot
  2. arch_uprobe_analyze_insn
  3. is_trap_insn
  4. arch_uprobe_pre_xol
  5. arch_uprobe_post_xol
  6. arch_uprobe_xol_was_trapped
  7. arch_uprobe_exception_notify
  8. arch_uprobe_abort_xol
  9. arch_uretprobe_hijack_return_addr
  10. set_swbp
  11. arch_uprobe_copy_ixol
  12. uprobe_get_swbp_addr
  13. arch_uprobe_skip_sstep

   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 
  15 static 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  */
  27 int 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  */
  62 bool 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 1;
  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 1;
  91                 }
  92                 break;
  93         }
  94 
  95         return 0;
  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  */
 105 int 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 
 126 int 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  */
 146 bool 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 
 154 int 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  */
 188 void 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 
 196 unsigned 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  */
 221 int __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 
 227 void 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  */
 248 unsigned 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 0.
 258  */
 259 bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 260 {
 261         return 0;
 262 }

/* [<][>][^][v][top][bottom][index][help] */