diff options
Diffstat (limited to 'kernel/events/uprobes.c')
-rw-r--r-- | kernel/events/uprobes.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 26bc2e24e9e3..ca9012930ce7 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -173,6 +173,20 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn) | |||
173 | return *insn == UPROBE_SWBP_INSN; | 173 | return *insn == UPROBE_SWBP_INSN; |
174 | } | 174 | } |
175 | 175 | ||
176 | /** | ||
177 | * is_trap_insn - check if instruction is breakpoint instruction. | ||
178 | * @insn: instruction to be checked. | ||
179 | * Default implementation of is_trap_insn | ||
180 | * Returns true if @insn is a breakpoint instruction. | ||
181 | * | ||
182 | * This function is needed for the case where an architecture has multiple | ||
183 | * trap instructions (like powerpc). | ||
184 | */ | ||
185 | bool __weak is_trap_insn(uprobe_opcode_t *insn) | ||
186 | { | ||
187 | return is_swbp_insn(insn); | ||
188 | } | ||
189 | |||
176 | static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode) | 190 | static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode) |
177 | { | 191 | { |
178 | void *kaddr = kmap_atomic(page); | 192 | void *kaddr = kmap_atomic(page); |
@@ -185,6 +199,15 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t | |||
185 | uprobe_opcode_t old_opcode; | 199 | uprobe_opcode_t old_opcode; |
186 | bool is_swbp; | 200 | bool is_swbp; |
187 | 201 | ||
202 | /* | ||
203 | * Note: We only check if the old_opcode is UPROBE_SWBP_INSN here. | ||
204 | * We do not check if it is any other 'trap variant' which could | ||
205 | * be conditional trap instruction such as the one powerpc supports. | ||
206 | * | ||
207 | * The logic is that we do not care if the underlying instruction | ||
208 | * is a trap variant; uprobes always wins over any other (gdb) | ||
209 | * breakpoint. | ||
210 | */ | ||
188 | copy_opcode(page, vaddr, &old_opcode); | 211 | copy_opcode(page, vaddr, &old_opcode); |
189 | is_swbp = is_swbp_insn(&old_opcode); | 212 | is_swbp = is_swbp_insn(&old_opcode); |
190 | 213 | ||
@@ -204,7 +227,7 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t | |||
204 | * Expect the breakpoint instruction to be the smallest size instruction for | 227 | * Expect the breakpoint instruction to be the smallest size instruction for |
205 | * the architecture. If an arch has variable length instruction and the | 228 | * the architecture. If an arch has variable length instruction and the |
206 | * breakpoint instruction is not of the smallest length instruction | 229 | * breakpoint instruction is not of the smallest length instruction |
207 | * supported by that architecture then we need to modify is_swbp_at_addr and | 230 | * supported by that architecture then we need to modify is_trap_at_addr and |
208 | * write_opcode accordingly. This would never be a problem for archs that | 231 | * write_opcode accordingly. This would never be a problem for archs that |
209 | * have fixed length instructions. | 232 | * have fixed length instructions. |
210 | */ | 233 | */ |
@@ -550,7 +573,7 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file, | |||
550 | goto out; | 573 | goto out; |
551 | 574 | ||
552 | ret = -ENOTSUPP; | 575 | ret = -ENOTSUPP; |
553 | if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) | 576 | if (is_trap_insn((uprobe_opcode_t *)uprobe->arch.insn)) |
554 | goto out; | 577 | goto out; |
555 | 578 | ||
556 | ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); | 579 | ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); |
@@ -1431,7 +1454,7 @@ static void mmf_recalc_uprobes(struct mm_struct *mm) | |||
1431 | clear_bit(MMF_HAS_UPROBES, &mm->flags); | 1454 | clear_bit(MMF_HAS_UPROBES, &mm->flags); |
1432 | } | 1455 | } |
1433 | 1456 | ||
1434 | static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | 1457 | static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr) |
1435 | { | 1458 | { |
1436 | struct page *page; | 1459 | struct page *page; |
1437 | uprobe_opcode_t opcode; | 1460 | uprobe_opcode_t opcode; |
@@ -1452,7 +1475,8 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | |||
1452 | copy_opcode(page, vaddr, &opcode); | 1475 | copy_opcode(page, vaddr, &opcode); |
1453 | put_page(page); | 1476 | put_page(page); |
1454 | out: | 1477 | out: |
1455 | return is_swbp_insn(&opcode); | 1478 | /* This needs to return true for any variant of the trap insn */ |
1479 | return is_trap_insn(&opcode); | ||
1456 | } | 1480 | } |
1457 | 1481 | ||
1458 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) | 1482 | 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) | |||
1472 | } | 1496 | } |
1473 | 1497 | ||
1474 | if (!uprobe) | 1498 | if (!uprobe) |
1475 | *is_swbp = is_swbp_at_addr(mm, bp_vaddr); | 1499 | *is_swbp = is_trap_at_addr(mm, bp_vaddr); |
1476 | } else { | 1500 | } else { |
1477 | *is_swbp = -EFAULT; | 1501 | *is_swbp = -EFAULT; |
1478 | } | 1502 | } |