From d8b7418ba4cf2bf2571f66a42517b9bced1b9132 Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Wed, 11 Mar 2009 14:42:29 -0700 Subject: Don't reject opcode 0x9b -- fwait, which is also the first byte of pseudo-instructions like fclex, finit, fstsw, and fstcw. Do reject opcode 0x82 in 64-bit mode. --- runtime/uprobes/uprobes_i386.c | 3 +-- runtime/uprobes/uprobes_x86.c | 9 ++++----- runtime/uprobes/uprobes_x86_64.c | 7 +++---- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'runtime/uprobes') diff --git a/runtime/uprobes/uprobes_i386.c b/runtime/uprobes/uprobes_i386.c index ffa088ed..c43f87bf 100644 --- a/runtime/uprobes/uprobes_i386.c +++ b/runtime/uprobes/uprobes_i386.c @@ -44,7 +44,7 @@ W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1), /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -114,7 +114,6 @@ * 26, 2e, 36, 3e, - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seems to be used, so we support them. * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix * f2, f3 - repnz, repz prefixes diff --git a/runtime/uprobes/uprobes_x86.c b/runtime/uprobes/uprobes_x86.c index e3bdf8ff..404c9518 100644 --- a/runtime/uprobes/uprobes_x86.c +++ b/runtime/uprobes/uprobes_x86.c @@ -45,8 +45,8 @@ static const unsigned long long good_insns_64[256 / 64] = { W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */ W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ - W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -71,7 +71,7 @@ static const unsigned long long good_insns_32[256 / 64] = { W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -119,7 +119,7 @@ static const unsigned long long good_2byte_insns[256 / 64] = { * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 * * invalid opcodes in 64-bit mode: - * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, c4-c5, d4-d5 + * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 * * 63 - we support this opcode in x86_64 but not in i386. * opcodes we may need to refine support for: @@ -141,7 +141,6 @@ static const unsigned long long good_2byte_insns[256 / 64] = { * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seems to be used, so we support them. * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix */ diff --git a/runtime/uprobes/uprobes_x86_64.c b/runtime/uprobes/uprobes_x86_64.c index 8cf36623..56ebe2e1 100644 --- a/runtime/uprobes/uprobes_x86_64.c +++ b/runtime/uprobes/uprobes_x86_64.c @@ -45,8 +45,8 @@ static const unsigned long good_insns_64[256 / 64] = { W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */ W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ - W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -71,7 +71,7 @@ static const unsigned long good_insns_32[256 / 64] = { W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */ W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ - W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */ + W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */ W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */ @@ -141,7 +141,6 @@ static const unsigned long good_2byte_insns[256 / 64] = { * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seems to be used, so we support them. * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix */ -- cgit From 85cd50d2a532d78ae1b0281c4baea3c4af396e2b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 2 Apr 2009 22:41:18 -0700 Subject: Add a .gitignore for uprobes --- runtime/uprobes/.gitignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 runtime/uprobes/.gitignore (limited to 'runtime/uprobes') diff --git a/runtime/uprobes/.gitignore b/runtime/uprobes/.gitignore new file mode 100644 index 00000000..c8172c41 --- /dev/null +++ b/runtime/uprobes/.gitignore @@ -0,0 +1,7 @@ +/*.o +/*.cmd +/.tmp_versions +/Module.* +/modules.order +/uprobes.ko +/uprobes.mod.c -- cgit From 9d4518784bedd11e8563c999658f307c5c01b3a3 Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Wed, 15 Apr 2009 16:11:17 -0700 Subject: PR9940: add/use unmap_u[ret]probe For uprobes 1 and 2, add unmap_u[ret]probe() and define UPROBES_API_VERSION=2. Adapt tapsets.cxx accordingly. --- runtime/uprobes/uprobes.c | 34 ++++++++++++++++++++++++++++------ runtime/uprobes/uprobes.h | 6 ++++++ 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'runtime/uprobes') diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 9dfb82b9..27e923b8 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -1049,8 +1049,7 @@ fail_tsk: } EXPORT_SYMBOL_GPL(register_uprobe); -/* See Documentation/uprobes.txt. */ -void unregister_uprobe(struct uprobe *u) +void __unregister_uprobe(struct uprobe *u, bool remove_bkpt) { struct task_struct *p; struct uprobe_process *uproc; @@ -1104,10 +1103,13 @@ void unregister_uprobe(struct uprobe *u) if (!list_empty(&ppt->uprobe_list)) goto done; - /* - * The last uprobe at ppt's probepoint is being unregistered. - * Queue the breakpoint for removal. - */ + /* The last uprobe at ppt's probepoint is being unregistered. */ + if (!remove_bkpt) { + uprobe_free_probept(ppt); + goto done; + } + + /* Queue the breakpoint for removal. */ ppt->state = UPROBE_REMOVING; list_add_tail(&ppt->pd_node, &uproc->pending_uprobes); @@ -1132,8 +1134,20 @@ done: up_write(&uproc->rwsem); uprobe_put_process(uproc); } + +/* See Documentation/uprobes.txt. */ +void unregister_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, true); +} EXPORT_SYMBOL_GPL(unregister_uprobe); +void unmap_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, false); +} +EXPORT_SYMBOL_GPL(unmap_uprobe); + /* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */ static struct task_struct *find_surviving_thread(struct uprobe_process *uproc) { @@ -2540,6 +2554,14 @@ void unregister_uretprobe(struct uretprobe *rp) } EXPORT_SYMBOL_GPL(unregister_uretprobe); +void unmap_uretprobe(struct uretprobe *rp) +{ + if (!rp) + return; + unmap_uprobe(&rp->u); +} +EXPORT_SYMBOL_GPL(unmap_uretprobe); + /* * uproc->ssol_area has been successfully set up. Establish the * uretprobe trampoline in slot 0. diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h index 0266cb7d..d542420d 100644 --- a/runtime/uprobes/uprobes.h +++ b/runtime/uprobes/uprobes.h @@ -35,6 +35,9 @@ #include #include +/* Version 2 includes unmap_u[ret]probe(). */ +#define UPROBES_API_VERSION 2 + struct pt_regs; enum uprobe_type { @@ -89,6 +92,9 @@ extern void unregister_uprobe(struct uprobe *u); /* For runtime, assume uprobes support includes uretprobes. */ extern int register_uretprobe(struct uretprobe *rp); extern void unregister_uretprobe(struct uretprobe *rp); +/* For PRs 9940, 6852... */ +extern void unmap_uprobe(struct uprobe *u); +extern void unmap_uretprobe(struct uretprobe *rp); #ifdef UPROBES_IMPLEMENTATION -- cgit From 436e5bf634020bcb9f98967891508db21f9e6cbd Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Mon, 20 Apr 2009 16:39:26 -0700 Subject: PR10078: uretprobes on functions returning structs/unions arch_predict_sp_at_ret() for x86_32 now accommodates ret $4. Added bz10078 regression test. --- runtime/uprobes/uprobes_i386.c | 13 ++++++++++++- runtime/uprobes/uprobes_x86.c | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'runtime/uprobes') diff --git a/runtime/uprobes/uprobes_i386.c b/runtime/uprobes/uprobes_i386.c index c43f87bf..7743f400 100644 --- a/runtime/uprobes/uprobes_i386.c +++ b/runtime/uprobes/uprobes_i386.c @@ -301,9 +301,20 @@ unsigned long arch_hijack_uret_addr(unsigned long trampoline_address, return orig_ret_addr; } +/* + * On x86_32, if a function returns a struct or union, the return + * value is copied into an area created by the caller. The address + * of this area is passed on the stack as a "hidden" first argument. + * When such a function returns, it uses a "ret $4" instruction to pop + * not only the return address but also the hidden arg. To accommodate + * such functions, we add 4 bytes of slop when predicting the return + * address. See PR #10078. + */ +#define STRUCT_RETURN_SLOP 4 + static unsigned long arch_predict_sp_at_ret(struct pt_regs *regs, struct task_struct *tsk) { - return (unsigned long) (regs->esp + 4); + return (unsigned long) (regs->esp + 4 + STRUCT_RETURN_SLOP); } diff --git a/runtime/uprobes/uprobes_x86.c b/runtime/uprobes/uprobes_x86.c index 404c9518..93331715 100644 --- a/runtime/uprobes/uprobes_x86.c +++ b/runtime/uprobes/uprobes_x86.c @@ -716,12 +716,23 @@ unsigned long arch_hijack_uret_addr(unsigned long trampoline_address, return orig_ret_addr; } +/* + * On x86_32, if a function returns a struct or union, the return + * value is copied into an area created by the caller. The address + * of this area is passed on the stack as a "hidden" first argument. + * When such a function returns, it uses a "ret $4" instruction to pop + * not only the return address but also the hidden arg. To accommodate + * such functions, we add 4 bytes of slop when predicting the return + * address. See PR #10078. + */ +#define STRUCT_RETURN_SLOP 4 + static unsigned long arch_predict_sp_at_ret(struct pt_regs *regs, struct task_struct *tsk) { if (test_tsk_thread_flag(tsk, TIF_IA32)) - return (unsigned long) (REGS_SP + 4); + return (unsigned long) (REGS_SP + 4 + STRUCT_RETURN_SLOP); else return (unsigned long) (REGS_SP + 8); } -- cgit From 0cd571c33e70fee4777622a49f50e9122335432d Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Thu, 23 Apr 2009 14:19:58 -0700 Subject: i386 uprobes1: enable the 0x0f 0x1_ row of opcodes to make sdt.exp pass --- runtime/uprobes/uprobes_i386.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/uprobes') diff --git a/runtime/uprobes/uprobes_i386.c b/runtime/uprobes/uprobes_i386.c index 7743f400..35d112fa 100644 --- a/runtime/uprobes/uprobes_i386.c +++ b/runtime/uprobes/uprobes_i386.c @@ -59,7 +59,7 @@ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /* ------------------------------- */ W(0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 00 */ - W(0x10, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 10 */ + W(0x10, 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1), /* 10 */ W(0x20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 20 */ W(0x30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 30 */ W(0x40, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 40 */ -- cgit From af6b0601a7b65842fd639d1d712d77fa69b18065 Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Fri, 24 Apr 2009 13:46:46 -0700 Subject: PR5273: uprobes_i386.c instruction table Resynch uprobes1 2-byte-opcode table with uprobes2 x86. Mostly changes a bunch of mmx instructions from rejected to accepted. --- runtime/uprobes/uprobes_i386.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'runtime/uprobes') diff --git a/runtime/uprobes/uprobes_i386.c b/runtime/uprobes/uprobes_i386.c index 35d112fa..008f32de 100644 --- a/runtime/uprobes/uprobes_i386.c +++ b/runtime/uprobes/uprobes_i386.c @@ -58,22 +58,22 @@ static const unsigned long good_2byte_insns[256 / 32] = { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /* ------------------------------- */ - W(0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 00 */ + W(0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1)| /* 00 */ W(0x10, 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1), /* 10 */ - W(0x20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 20 */ - W(0x30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 30 */ - W(0x40, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 40 */ - W(0x50, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 50 */ - W(0x60, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 60 */ - W(0x70, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 70 */ + W(0x20, 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1)| /* 20 */ + W(0x30, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0), /* 30 */ + W(0x40, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 40 */ + W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 50 */ + W(0x60, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 60 */ + W(0x70, 1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1), /* 70 */ W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 90 */ W(0xa0, 1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1)| /* a0 */ W(0xb0, 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1), /* b0 */ - W(0xc0, 1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1)| /* c0 */ - W(0xd0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* d0 */ - W(0xe0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* e0 */ - W(0xf0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) /* f0 */ + W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* c0 */ + W(0xd0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* d0 */ + W(0xe0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* e0 */ + W(0xf0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0) /* f0 */ /* ------------------------------- */ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; -- cgit