diff options
-rw-r--r-- | runtime/runtime.h | 14 | ||||
-rw-r--r-- | runtime/sym.c | 27 | ||||
-rw-r--r-- | runtime/sym.h | 1 | ||||
-rw-r--r-- | runtime/unwind.c | 2 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.c | 34 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.h | 6 | ||||
-rw-r--r-- | runtime/uprobes/uprobes_i386.c | 3 | ||||
-rw-r--r-- | runtime/uprobes/uprobes_x86.c | 9 | ||||
-rw-r--r-- | runtime/uprobes/uprobes_x86_64.c | 7 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 43 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 6 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes_x86.c | 9 | ||||
-rw-r--r-- | tapsets.cxx | 270 | ||||
-rw-r--r-- | testsuite/systemtap.base/labels.exp | 31 | ||||
-rw-r--r-- | translate.cxx | 58 |
15 files changed, 340 insertions, 180 deletions
diff --git a/runtime/runtime.h b/runtime/runtime.h index 0a656b78..c2e927cc 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -66,6 +66,13 @@ static struct #define MAXTRACE 20 #endif +/* dwarf unwinder only tested so far on i386 and x86_64. */ +#if (defined(__i386__) || defined(__x86_64__)) +#ifndef STP_USE_DWARF_UNWINDER +#define STP_USE_DWARF_UNWINDER +#endif +#endif + #ifdef CONFIG_FRAME_POINTER /* Just because frame pointers are available does not mean we can trust them. */ #ifndef STP_USE_DWARF_UNWINDER @@ -73,13 +80,6 @@ static struct #endif #endif -/* dwarf unwinder only tested so far on i386 and x86_64, - but globally disabled for now */ -#if 0 -// !defined(STP_USE_FRAME_BUFFER) && (defined(__i386__) || defined(__x86_64__)) -#define STP_USE_DWARF_UNWINDER -#endif - #include "alloc.c" #include "print.c" #include "string.c" diff --git a/runtime/sym.c b/runtime/sym.c index a2cdd0ff..f6f97ac2 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -136,9 +136,7 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr, struct _stp_section **sec) { void *user = NULL; - struct _stp_module *m = NULL; unsigned midx = 0; - unsigned long closest_section_offset = ~0; // Try vma matching first if task given. if (task) @@ -149,8 +147,9 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr, NULL, &user) == 0) if (user != NULL) { - m = (struct _stp_module *)user; - *sec = &m->sections[0]; // XXX check actual section and relocate + struct _stp_module *m = (struct _stp_module *)user; + if (sec) + *sec = &m->sections[0]; // XXX check actual section and relocate dbug_sym(1, "found section %s in module %s at 0x%lx\n", m->sections[0].name, m->name, vm_start); if (strcmp(".dynamic", m->sections[0].name) == 0) @@ -164,21 +163,19 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr, unsigned secidx; for (secidx = 0; secidx < _stp_modules[midx]->num_sections; secidx++) { - unsigned long this_section_addr; - unsigned long this_section_offset; - this_section_addr = _stp_modules[midx]->sections[secidx].addr; - if (addr < this_section_addr) continue; - this_section_offset = addr - this_section_addr; - if (this_section_offset < closest_section_offset) - { - closest_section_offset = this_section_offset; - m = _stp_modules[midx]; + unsigned long sec_addr; + unsigned long sec_size; + sec_addr = _stp_modules[midx]->sections[secidx].addr; + sec_size = _stp_modules[midx]->sections[secidx].size; + if (addr >= sec_addr && addr < sec_addr + sec_size) + { if (sec) - *sec = & m->sections[secidx]; + *sec = & _stp_modules[midx]->sections[secidx]; + return _stp_modules[midx]; } } } - return m; + return NULL; } diff --git a/runtime/sym.h b/runtime/sym.h index 586b10ca..80c334fb 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -18,6 +18,7 @@ struct _stp_symbol { struct _stp_section { const char *name; unsigned long addr; /* XXX: belongs in per-address-space tables */ + unsigned long size; /* length of the address space module covers. */ struct _stp_symbol *symbols; /* ordered by address */ unsigned num_symbols; }; diff --git a/runtime/unwind.c b/runtime/unwind.c index 9c704e28..f7b19def 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -581,7 +581,7 @@ static int unwind(struct unwind_frame_info *frame) if (UNW_PC(frame) == 0) return -EINVAL; - m = _stp_mod_sec_lookup (pc, &s); + m = _stp_mod_sec_lookup (pc, current, &s); if (unlikely(m == NULL)) { dbug_unwind(1, "No module found for pc=%lx", pc); return -EINVAL; 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 <linux/types.h> #include <linux/list.h> +/* 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 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 */ diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index a0e9f2fe..9ea05349 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -955,10 +955,15 @@ static int defer_registration(struct uprobe *u, int regflag, */ static struct pid *uprobe_get_tg_leader(pid_t p) { - struct pid *pid; + struct pid *pid = NULL; rcu_read_lock(); - pid = find_vpid(p); + /* + * We need this check because unmap_u[ret]probe() can be called + * from a report_death callback, where current->proxy is NULL. + */ + if (current->nsproxy) + pid = find_vpid(p); if (pid) { struct task_struct *t = pid_task(pid, PIDTYPE_PID); if (t) @@ -1138,8 +1143,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 pid *p; struct uprobe_process *uproc; @@ -1193,10 +1197,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); @@ -1221,8 +1228,20 @@ done: up_write(&uproc->rwsem); uprobe_put_process(uproc, false); } + +/* 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) { @@ -2718,6 +2737,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 the next available slot following the diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index 112e29e2..ae0692f0 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -28,6 +28,9 @@ #define utrace_attached_engine utrace_engine #endif +/* Version 2 includes unmap_u[ret]probe(). */ +#define UPROBES_API_VERSION 2 + struct pt_regs; enum uprobe_type { @@ -82,6 +85,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 diff --git a/runtime/uprobes2/uprobes_x86.c b/runtime/uprobes2/uprobes_x86.c index effb7444..8c80293d 100644 --- a/runtime/uprobes2/uprobes_x86.c +++ b/runtime/uprobes2/uprobes_x86.c @@ -50,8 +50,8 @@ static const u64 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 */ @@ -76,7 +76,7 @@ static const u64 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 */ @@ -124,7 +124,7 @@ static const u64 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: @@ -146,7 +146,6 @@ static const u64 good_2byte_insns[256 / 64] = { * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- * but 64 and 65 (fs: and gs:) seem to be used, so we support them * 67 - addr16 prefix - * 9b - wait/fwait * ce - into * f0 - lock prefix */ diff --git a/tapsets.cxx b/tapsets.cxx index c63151e1..01c838d9 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1339,102 +1339,14 @@ struct dwflpp } void - iterate_over_cu_labels (string label_val, - string function, - Dwarf_Die *cu, - vector<derived_probe *> & results, - probe_point *base_loc, - void *data, - void (* callback)(const string &, - const char *, - int, - Dwarf_Die *, - Dwarf_Addr, - dwarf_query *)) - { - dwarf_query * q __attribute__ ((unused)) = static_cast<dwarf_query *>(data) ; - - get_module_dwarf(); - - const char * sym = label_val.c_str(); - Dwarf_Die die; - int res = dwarf_child (cu, &die); - if (res != 0) - return; // die without children, bail out. - - static string function_name; - do - { - Dwarf_Attribute attr_mem; - Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem); - int tag = dwarf_tag(&die); - const char *name = dwarf_formstring (attr); - if (name == 0) - continue; - switch (tag) - { - case DW_TAG_label: - break; - case DW_TAG_subprogram: - function_name = name; - default: - if (dwarf_haschildren (&die)) - iterate_over_cu_labels (label_val, function, &die, results, base_loc, q, callback); - continue; - } - - if (strcmp(function_name.c_str(), function.c_str()) == 0 - || (name_has_wildcard(function) - && function_name_matches_pattern (function_name, function))) - { - } - else - continue; - if (strcmp(name, sym) == 0 - || (name_has_wildcard(sym) - && function_name_matches_pattern (name, sym))) - { - const char *file = dwarf_decl_file (&die); - // Get the line number for this label - Dwarf_Attribute attr; - dwarf_attr (&die,DW_AT_decl_line, &attr); - Dwarf_Sword dline; - dwarf_formsdata (&attr, &dline); - Dwarf_Addr stmt_addr; - if (dwarf_lowpc (&die, &stmt_addr) != 0) - { - // There is no lowpc so figure out the address - // Get the real die for this cu - Dwarf_Die cudie; - dwarf_diecu (cu, &cudie, NULL, NULL); - size_t nlines = 0; - // Get the line for this label - Dwarf_Line **aline; - dwarf_getsrc_file (module_dwarf, file, (int)dline, 0, &aline, &nlines); - // Get the address - for (size_t i = 0; i < nlines; i++) - { - dwarf_lineaddr (*aline, &stmt_addr); - if ((dwarf_haspc (&die, stmt_addr))) - break; - } - } - - Dwarf_Die *scopes; - int nscopes = 0; - nscopes = dwarf_getscopes_die (&die, &scopes); - if (nscopes > 1) - { - callback(function_name.c_str(), file, - (int)dline, &scopes[1], stmt_addr, q); - if (sess.listing_mode) - results.back()->locations[0]->components.push_back - (new probe_point::component(TOK_LABEL, new literal_string (name))); - } - } - } - while (dwarf_siblingof (&die, &die) == 0); - } + iterate_over_labels (Dwarf_Die *begin_die, + void *data, + void (* callback)(const string &, + const char *, + int, + Dwarf_Die *, + Dwarf_Addr, + dwarf_query *)); void collect_srcfiles_matching (string const & pattern, set<char const *> & filtered_srcfiles) @@ -3072,6 +2984,100 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * } +void +dwflpp::iterate_over_labels (Dwarf_Die *begin_die, + void *data, + void (* callback)(const string &, + const char *, + int, + Dwarf_Die *, + Dwarf_Addr, + dwarf_query *)) +{ + dwarf_query * q __attribute__ ((unused)) = static_cast<dwarf_query *>(data) ; + + get_module_dwarf(); + + const char * sym = q->label_val.c_str(); + Dwarf_Die die; + int res = dwarf_child (begin_die, &die); + if (res != 0) + return; // die without children, bail out. + + static string function_name = dwarf_diename (begin_die); + do + { + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem); + int tag = dwarf_tag(&die); + const char *name = dwarf_formstring (attr); + if (name == 0) + continue; + switch (tag) + { + case DW_TAG_label: + break; + case DW_TAG_subprogram: + function_name = name; + default: + if (dwarf_haschildren (&die)) + iterate_over_labels (&die, q, callback); + continue; + } + + if (strcmp(function_name.c_str(), q->function.c_str()) == 0 + || (name_has_wildcard(q->function) + && function_name_matches_pattern (function_name, q->function))) + { + } + else + continue; + if (strcmp(name, sym) == 0 + || (name_has_wildcard(sym) + && function_name_matches_pattern (name, sym))) + { + const char *file = dwarf_decl_file (&die); + // Get the line number for this label + Dwarf_Attribute attr; + dwarf_attr (&die,DW_AT_decl_line, &attr); + Dwarf_Sword dline; + dwarf_formsdata (&attr, &dline); + Dwarf_Addr stmt_addr; + if (dwarf_lowpc (&die, &stmt_addr) != 0) + { + // There is no lowpc so figure out the address + // Get the real die for this cu + Dwarf_Die cudie; + dwarf_diecu (q->dw.cu, &cudie, NULL, NULL); + size_t nlines = 0; + // Get the line for this label + Dwarf_Line **aline; + dwarf_getsrc_file (module_dwarf, file, (int)dline, 0, &aline, &nlines); + // Get the address + for (size_t i = 0; i < nlines; i++) + { + dwarf_lineaddr (*aline, &stmt_addr); + if ((dwarf_haspc (&die, stmt_addr))) + break; + } + } + + Dwarf_Die *scopes; + int nscopes = 0; + nscopes = dwarf_getscopes_die (&die, &scopes); + if (nscopes > 1) + { + callback(function_name.c_str(), file, + (int)dline, &scopes[1], stmt_addr, q); + if (sess.listing_mode) + q->results.back()->locations[0]->components.push_back + (new probe_point::component(TOK_LABEL, new literal_string (name))); + } + } + } + while (dwarf_siblingof (&die, &die) == 0); +} + struct dwarf_builder: public derived_probe_builder { @@ -3877,6 +3883,19 @@ query_func_info (Dwarf_Addr entrypc, static void +query_srcfile_label (const dwarf_line_t& line, void * arg) +{ + dwarf_query * q = static_cast<dwarf_query *>(arg); + + Dwarf_Addr addr = line.addr(); + + for (func_info_map_t::iterator i = q->filtered_functions.begin(); + i != q->filtered_functions.end(); ++i) + if (q->dw.die_has_pc (i->die, addr)) + q->dw.iterate_over_labels (&i->die, q, query_statement); +} + +static void query_srcfile_line (const dwarf_line_t& line, void * arg) { dwarf_query * q = static_cast<dwarf_query *>(arg); @@ -4120,7 +4139,17 @@ query_cu (Dwarf_Die * cudie, void * arg) if (! q->filtered_functions.empty()) q->dw.resolve_prologue_endings (q->filtered_functions); - if ((q->has_statement_str || q->has_function_str) + if (q->has_label) + { + if (q->line[0] == 0) // No line number specified + q->dw.iterate_over_labels (q->dw.cu, q, query_statement); + else + for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin(); + i != q->filtered_srcfiles.end(); ++i) + q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str, + q->line_type, query_srcfile_label, q); + } + else if ((q->has_statement_str || q->has_function_str) && (q->spec_type == function_file_and_line)) { // If we have a pattern string with target *line*, we @@ -4130,12 +4159,6 @@ query_cu (Dwarf_Die * cudie, void * arg) q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str, q->line_type, query_srcfile_line, q); } - else if (q->has_label) - { - // If we have a pattern string with target *label*, we - // have to look at labels in all the matched srcfiles. - q->dw.iterate_over_cu_labels (q->label_val, q->function, q->dw.cu, q->results, q->base_loc, q, query_statement); - } else { // Otherwise, simply probe all resolved functions. @@ -7590,6 +7613,9 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#else"; s.op->newline() << "#include \"uprobes/uprobes.h\""; s.op->newline() << "#endif"; + s.op->newline() << "#ifndef UPROBES_API_VERSION"; + s.op->newline() << "#define UPROBES_API_VERSION 1"; + s.op->newline() << "#endif"; s.op->newline() << "#ifndef MULTIPLE_UPROBES"; s.op->newline() << "#define MULTIPLE_UPROBES 256"; // maximum possible armed uprobes per process() probe point @@ -7701,10 +7727,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // register new uprobe s.op->newline() << "if (register_p && sup->spec_index < 0) {"; - // PR6829: we need to check that the sup we're about to reuse is really completely free. - // See PR6829 notes below. - s.op->newline(1) << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;"; + s.op->newline(1) << "#if (UPROBES_API_VERSION < 2)"; + // See PR6829 comment. + s.op->newline() << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;"; s.op->newline() << "else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue;"; + s.op->newline() << "#endif"; s.op->newline() << "sup->spec_index = spec_index;"; s.op->newline() << "slotted_p = 1;"; s.op->newline() << "break;"; @@ -7755,13 +7782,32 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "} else if (!register_p && slotted_p) {"; s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; - // NB: we need to release this slot, so we need to borrow the mutex temporarily. + s.op->newline() << "int unregistered_flag;"; + // PR6829, PR9940: + // Here we're unregistering for one of two reasons: + // 1. the process image is going away (or gone) due to exit or exec; or + // 2. the vma containing the probepoint has been unmapped. + // In case 1, it's sort of a nop, because uprobes will notice the event + // and dispose of the probes eventually, if it hasn't already. But by + // calling unmap_u[ret]probe() ourselves, we free up sup right away. + // + // In both cases, we must use unmap_u[ret]probe instead of + // unregister_u[ret]probe, so uprobes knows not to try to restore the + // original opcode. + s.op->newline() << "#if (UPROBES_API_VERSION >= 2)"; + s.op->newline() << "if (sups->return_p)"; + s.op->newline(1) << "unmap_uretprobe (& sup->urp);"; + s.op->newline(-1) << "else"; + s.op->newline(1) << "unmap_uprobe (& sup->up);"; + s.op->newline(-1) << "unregistered_flag = -1;"; + s.op->newline() << "#else"; + // Uprobes lacks unmap_u[ret]probe. Before reusing sup, we must wait + // until uprobes turns loose of the u[ret]probe on its own, as indicated + // by uprobe.kdata = NULL. + s.op->newline() << "unregistered_flag = (sups->return_p ? -2 : -1);"; + s.op->newline() << "#endif"; s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; - // NB: We must not actually uregister u[ret]probes when a target process execs or exits; - // uprobes does that by itself asynchronously. We can reuse the up/urp struct after - // uprobes clears the sup->{up,urp}->kdata pointer. PR6829. To tell the two - // cases apart, we use spec_index -2 vs -1. - s.op->newline() << "sup->spec_index = (sups->return_p ? -2 : -1);"; + s.op->newline() << "sup->spec_index = unregistered_flag;"; s.op->newline() << "mutex_unlock (& stap_uprobes_lock);"; s.op->newline() << "handled_p = 1;"; s.op->newline(-1) << "}"; // if slotted_p diff --git a/testsuite/systemtap.base/labels.exp b/testsuite/systemtap.base/labels.exp index 88ed4619..79e3f483 100644 --- a/testsuite/systemtap.base/labels.exp +++ b/testsuite/systemtap.base/labels.exp @@ -55,11 +55,42 @@ if { $res != "" } { pass "compiling labels.c -g" } +# line number error + +set ok 0 +spawn stap -l "process(\"$label_exepath\").function(\"foo@${label_srcpath}:10\").label(\"*\")" + +wait +expect { + -timeout 180 + -re {no match while resolving probe point} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} + +if {$ok == 1} { pass "$test :N .label" } { fail "$test :N .label $ok" } + +# line number + +set ok 0 +spawn stap -l "process(\"$label_exepath\").function(\"foo@${label_srcpath}:4\").label(\"*\")" + +wait +expect { + -timeout 180 + -re {process.*function.*labels.c:5...label..init_an_int} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} + +if {$ok == 1} { pass "$test :N .label" } { fail "$test :N .label $ok" } + # list of labels spawn stap -l "process(\"$label_exepath\").function(\"*\").label(\"*\")" wait +set ok 0 expect { -timeout 180 -re {process.*function.*labels.c:5...label..init_an_int.*process.*function.*labels.c:16...label..init_an_int.*process.*function.*labels.c:18...label..init_an_int_again} { incr ok; exp_continue } diff --git a/translate.cxx b/translate.cxx index 971c1498..c3c5533c 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4562,9 +4562,14 @@ dump_unwindsyms (Dwfl_Module *m, } } - // Use end as sanity check when resolving symbol addresses. - Dwarf_Addr end; - dwfl_module_info (m, NULL, NULL, &end, NULL, NULL, NULL, NULL); + // Get the canonical path of the main file for comparison at runtime. + // When given directly by the user through -d or in case of the kernel + // name and path might differ. path should be used for matching. + // Use end as sanity check when resolving symbol addresses and to + // calculate size for .dynamic and .absolute sections. + const char *mainfile; + Dwarf_Addr start, end; + dwfl_module_info (m, NULL, &start, &end, NULL, NULL, &mainfile, NULL); // Look up the relocation basis for symbols int n = dwfl_module_relocations (m); @@ -4575,7 +4580,8 @@ dump_unwindsyms (Dwfl_Module *m, // XXX: unfortunate duplication with tapsets.cxx:emit_address() typedef map<Dwarf_Addr,const char*> addrmap_t; // NB: plain map, sorted by address - vector<string> seclist; // encountered relocation bases (section names) + vector<pair<string,unsigned> > seclist; // encountered relocation bases + // (section names and sizes) map<unsigned, addrmap_t> addrmap; // per-relocation-base sorted addrmap Dwarf_Addr extra_offset = 0; @@ -4618,11 +4624,11 @@ dump_unwindsyms (Dwfl_Module *m, || sym.st_value < base)) // before first section. { Dwarf_Addr sym_addr = sym.st_value; + Dwarf_Addr save_addr = sym_addr; const char *secname = NULL; if (n > 0) // only try to relocate if there exist relocation bases { - Dwarf_Addr save_addr = sym_addr; int ki = dwfl_module_relocate_address (m, &sym_addr); dwfl_assert ("dwfl_module_relocate_address", ki >= 0); secname = dwfl_module_relocation_info (m, ki, NULL); @@ -4675,10 +4681,31 @@ dump_unwindsyms (Dwfl_Module *m, // Compute our section number unsigned secidx; for (secidx=0; secidx<seclist.size(); secidx++) - if (seclist[secidx]==secname) break; + if (seclist[secidx].first==secname) break; if (secidx == seclist.size()) // new section name - seclist.push_back (secname); + { + // absolute, dynamic or kernel have just one relocation + // section, which covers the whole module address range. + unsigned size; + if (secidx == 0 + && (n == 0 + || (n == 1 + && (strcmp(secname, ".dynamic") == 0 + || strcmp(secname, "_stext") == 0)))) + size = end - start; + else + { + Dwarf_Addr b; + Elf_Scn *scn; + GElf_Shdr *shdr, shdr_mem; + scn = dwfl_module_address_section (m, &save_addr, &b); + assert (scn != NULL); + shdr = gelf_getshdr(scn, &shdr_mem); + size = shdr->sh_size; + } + seclist.push_back (make_pair(secname,size)); + } (addrmap[secidx])[sym_addr] = name; } @@ -4739,12 +4766,17 @@ dump_unwindsyms (Dwfl_Module *m, } c->output << "static struct _stp_section _stp_module_" << stpmod_idx<< "_sections[] = {\n"; + // For the kernel, executables (ET_EXEC) or shared libraries (ET_DYN) + // there is just one section that covers the whole address space of + // the module. For kernel modules (ET_REL) there can be multiple + // sections that get relocated separately. for (unsigned secidx = 0; secidx < seclist.size(); secidx++) { c->output << "{\n" - << ".name = " << lex_cast_qstring(seclist[secidx]) << ",\n" + << ".name = " << lex_cast_qstring(seclist[secidx].first) << ",\n" + << ".size = 0x" << hex << seclist[secidx].second << dec << ",\n" << ".symbols = _stp_module_" << stpmod_idx << "_symbols_" << secidx << ",\n" - << ".num_symbols = sizeof(_stp_module_" << stpmod_idx << "_symbols_" << secidx << ")/sizeof(struct _stp_symbol)\n" + << ".num_symbols = " << addrmap[secidx].size() << "\n" << "},\n"; } c->output << "};\n"; @@ -4752,11 +4784,6 @@ dump_unwindsyms (Dwfl_Module *m, c->output << "static struct _stp_module _stp_module_" << stpmod_idx << " = {\n"; c->output << ".name = " << lex_cast_qstring (modname) << ", \n"; - // Get the canonical path of the main file for comparison at runtime. - // When given directly by the user through -d or in case of the kernel - // name and path might differ. path should be used for matching. - const char *mainfile; - dwfl_module_info (m, NULL, NULL, NULL, NULL, NULL, &mainfile, NULL); mainfile = canonicalize_file_name(mainfile); c->output << ".path = " << lex_cast_qstring (mainfile) << ",\n"; @@ -4891,7 +4918,8 @@ emit_symbol_data (systemtap_session& s) { NULL, /* dwfl_linux_kernel_find_elf, */ dwfl_standard_find_debuginfo, - dwfl_offline_section_address, + NULL, /* ET_REL not supported for user space, only ET_EXEC and ET_DYN. + dwfl_offline_section_address, */ (char **) & debuginfo_path }; |