summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/runtime.h14
-rw-r--r--runtime/sym.c27
-rw-r--r--runtime/sym.h1
-rw-r--r--runtime/unwind.c2
-rw-r--r--runtime/uprobes/uprobes.c34
-rw-r--r--runtime/uprobes/uprobes.h6
-rw-r--r--runtime/uprobes/uprobes_i386.c3
-rw-r--r--runtime/uprobes/uprobes_x86.c9
-rw-r--r--runtime/uprobes/uprobes_x86_64.c7
-rw-r--r--runtime/uprobes2/uprobes.c43
-rw-r--r--runtime/uprobes2/uprobes.h6
-rw-r--r--runtime/uprobes2/uprobes_x86.c9
-rw-r--r--tapsets.cxx270
-rw-r--r--testsuite/systemtap.base/labels.exp31
-rw-r--r--translate.cxx58
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
};