|
@@ -173,6 +173,20 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
|
|
|
return *insn == UPROBE_SWBP_INSN;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * is_trap_insn - check if instruction is breakpoint instruction.
|
|
|
+ * @insn: instruction to be checked.
|
|
|
+ * Default implementation of is_trap_insn
|
|
|
+ * Returns true if @insn is a breakpoint instruction.
|
|
|
+ *
|
|
|
+ * This function is needed for the case where an architecture has multiple
|
|
|
+ * trap instructions (like powerpc).
|
|
|
+ */
|
|
|
+bool __weak is_trap_insn(uprobe_opcode_t *insn)
|
|
|
+{
|
|
|
+ return is_swbp_insn(insn);
|
|
|
+}
|
|
|
+
|
|
|
static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode)
|
|
|
{
|
|
|
void *kaddr = kmap_atomic(page);
|
|
@@ -185,6 +199,15 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
|
|
|
uprobe_opcode_t old_opcode;
|
|
|
bool is_swbp;
|
|
|
|
|
|
+ /*
|
|
|
+ * Note: We only check if the old_opcode is UPROBE_SWBP_INSN here.
|
|
|
+ * We do not check if it is any other 'trap variant' which could
|
|
|
+ * be conditional trap instruction such as the one powerpc supports.
|
|
|
+ *
|
|
|
+ * The logic is that we do not care if the underlying instruction
|
|
|
+ * is a trap variant; uprobes always wins over any other (gdb)
|
|
|
+ * breakpoint.
|
|
|
+ */
|
|
|
copy_opcode(page, vaddr, &old_opcode);
|
|
|
is_swbp = is_swbp_insn(&old_opcode);
|
|
|
|
|
@@ -204,7 +227,7 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
|
|
|
* Expect the breakpoint instruction to be the smallest size instruction for
|
|
|
* the architecture. If an arch has variable length instruction and the
|
|
|
* breakpoint instruction is not of the smallest length instruction
|
|
|
- * supported by that architecture then we need to modify is_swbp_at_addr and
|
|
|
+ * supported by that architecture then we need to modify is_trap_at_addr and
|
|
|
* write_opcode accordingly. This would never be a problem for archs that
|
|
|
* have fixed length instructions.
|
|
|
*/
|
|
@@ -550,7 +573,7 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
|
|
|
goto out;
|
|
|
|
|
|
ret = -ENOTSUPP;
|
|
|
- if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn))
|
|
|
+ if (is_trap_insn((uprobe_opcode_t *)uprobe->arch.insn))
|
|
|
goto out;
|
|
|
|
|
|
ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr);
|
|
@@ -1431,7 +1454,7 @@ static void mmf_recalc_uprobes(struct mm_struct *mm)
|
|
|
clear_bit(MMF_HAS_UPROBES, &mm->flags);
|
|
|
}
|
|
|
|
|
|
-static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
|
|
|
+static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
|
|
|
{
|
|
|
struct page *page;
|
|
|
uprobe_opcode_t opcode;
|
|
@@ -1452,7 +1475,8 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
|
|
|
copy_opcode(page, vaddr, &opcode);
|
|
|
put_page(page);
|
|
|
out:
|
|
|
- return is_swbp_insn(&opcode);
|
|
|
+ /* This needs to return true for any variant of the trap insn */
|
|
|
+ return is_trap_insn(&opcode);
|
|
|
}
|
|
|
|
|
|
static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
|
|
@@ -1472,7 +1496,7 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
|
|
|
}
|
|
|
|
|
|
if (!uprobe)
|
|
|
- *is_swbp = is_swbp_at_addr(mm, bp_vaddr);
|
|
|
+ *is_swbp = is_trap_at_addr(mm, bp_vaddr);
|
|
|
} else {
|
|
|
*is_swbp = -EFAULT;
|
|
|
}
|