aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/uprobes.c
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2013-03-22 11:16:27 -0400
committerOleg Nesterov <oleg@redhat.com>2013-04-04 07:57:04 -0400
commit0908ad6e56b5a6e86745680bc324bdbfac64d0b6 (patch)
treedc403ef4b7ee5b912e7c097b2b8bb2e5260bc8ed /kernel/events/uprobes.c
parentf281769e81b49840f1857f6dfac049350e678350 (diff)
uprobes: Add trap variant helper
Some architectures like powerpc have multiple variants of the trap instruction. Introduce an additional helper is_trap_insn() for run-time handling of non-uprobe traps on such architectures. While there, change is_swbp_at_addr() to is_trap_at_addr() for reading clarity. With this change, the uprobe registration path will supercede any trap instruction inserted at the requested location, while taking care of delivering the SIGTRAP for cases where the trap notification came in for an address without a uprobe. See [1] for a more detailed explanation. [1] https://lists.ozlabs.org/pipermail/linuxppc-dev/2013-March/104771.html This change was suggested by Oleg Nesterov. Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'kernel/events/uprobes.c')
-rw-r--r--kernel/events/uprobes.c34
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 */
185bool __weak is_trap_insn(uprobe_opcode_t *insn)
186{
187 return is_swbp_insn(insn);
188}
189
176static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode) 190static 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
1434static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) 1457static 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
1458static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) 1482static 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 }