summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Moore <timoore@redhat.com>2009-12-21 17:53:06 +0100
committerTim Moore <timoore@redhat.com>2009-12-21 17:53:06 +0100
commit2e6135317db22a3c8d58776f10d75414b9685225 (patch)
tree5ee08c296fddf8f681b065ac9b3b1383866da915
parent75dfa5cb9b3584995f9e634a6e769b8a1576bc0d (diff)
parentea549ffc2915aa58861637472b12196222673fa2 (diff)
downloadsystemtap-steved-2e6135317db22a3c8d58776f10d75414b9685225.tar.gz
systemtap-steved-2e6135317db22a3c8d58776f10d75414b9685225.tar.xz
systemtap-steved-2e6135317db22a3c8d58776f10d75414b9685225.zip
Merge remote branch 'origin/master'
-rw-r--r--dwflpp.cxx6
-rw-r--r--runtime/sym.c167
-rw-r--r--runtime/sym.h7
-rw-r--r--runtime/task_finder_vma.c71
-rw-r--r--runtime/transport/symbols.c2
-rw-r--r--runtime/unwind.c31
-rw-r--r--tapset/context-symbols.stp4
-rw-r--r--tapsets.cxx2
-rw-r--r--testsuite/buildok/vm.tracepoints.stp31
-rw-r--r--testsuite/systemtap.examples/memory/vm.tracepoints.meta13
-rw-r--r--testsuite/systemtap.examples/memory/vm.tracepoints.stp18
11 files changed, 269 insertions, 83 deletions
diff --git a/dwflpp.cxx b/dwflpp.cxx
index d3cecc44..4fb0d54e 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -1523,7 +1523,7 @@ dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address)
// This gives us the module name, and section name within the
// module, for a kernel module (or other ET_REL module object).
obstack_printf (pool, "({ unsigned long addr = 0; ");
- obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
+ obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 ", NULL); ",
modname, secname, reloc_address);
obstack_printf (pool, "addr; })");
}
@@ -1537,7 +1537,7 @@ dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address)
// kernel will never move after being loaded (unlike modules and
// user-space dynamic share libraries).
obstack_printf (pool, "({ static unsigned long addr = 0; ");
- obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
+ obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 ", NULL); ",
modname, secname, address); // PR10000 NB: not reloc_address
obstack_printf (pool, "addr; })");
}
@@ -1545,7 +1545,7 @@ dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address)
{
enable_task_finder (sess);
obstack_printf (pool, "({ unsigned long addr = 0; ");
- obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
+ obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 ", current); ",
modname, ".dynamic", reloc_address);
obstack_printf (pool, "addr; })");
}
diff --git a/runtime/sym.c b/runtime/sym.c
index cd0c8a71..06691dc9 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -19,6 +19,22 @@
/* Callback that needs to be registered (in
session.unwindsyms_modules) for every user task path for which we
might need symbols or unwind info. */
+static int _stp_tf_exec_cb(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ int register_p,
+ int process_p)
+{
+#ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "tsk %d:%d , register_p: %d, process_p: %d\n",
+ tsk->pid, tsk->tgid, register_p, process_p);
+#endif
+ if (process_p && ! register_p)
+ stap_drop_vma_maps(tsk);
+
+ return 0;
+}
+
static int _stp_tf_mmap_cb(struct stap_task_finder_target *tgt,
struct task_struct *tsk,
char *path,
@@ -42,40 +58,22 @@ static int _stp_tf_mmap_cb(struct stap_task_finder_target *tgt,
if (strcmp(path, _stp_modules[i]->path) == 0)
{
#ifdef DEBUG_TASK_FINDER_VMA
- _stp_dbug(__FUNCTION__, __LINE__,
- "vm_cb: matched path %s to module\n",
- path);
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "vm_cb: matched path %s to module (for sec: %s)\n",
+ path, _stp_modules[i]->sections[0].name);
#endif
- module = _stp_modules[i];
- // cheat...
- // We are abusing the "first" section address
- // here to indicate where the module (actually
- // first segment) is loaded (which is why we
- // are ignoring the offset). It would be good
- // to redesign the stp_module/stp_section
- // data structures to better align with the
- // actual memory mappings we are interested
- // in (especially the "section" naming is
- // slightly confusing since what we really
- // seem to mean are elf segments (which can
- // contain multiple elf sections). PR11015.
- if (strcmp(".dynamic",
- module->sections[0].name) == 0)
- {
- if (module->sections[0].addr == 0)
- module->sections[0].addr = addr;
- else if (module->sections[0].addr != addr)
- _stp_error ("Reloaded module '%s'"
- " at 0x%lx, was 0x%lx\n",
- path, addr,
- module->sections[0].addr);
- }
- break;
+ module = _stp_modules[i];
+ /* XXX We really only need to register .dynamic
+ sections, but .absolute exes are also necessary
+ atm. */
+ return stap_add_vma_map_info(tsk->group_leader,
+ addr,
+ addr + length,
+ offset,
+ module);
}
}
}
- stap_add_vma_map_info(tsk->group_leader, addr, addr + length, offset,
- module);
return 0;
}
@@ -84,15 +82,25 @@ static int _stp_tf_munmap_cb(struct stap_task_finder_target *tgt,
unsigned long addr,
unsigned long length)
{
+ /* Unconditionally remove vm map info, ignore if not present. */
stap_remove_vma_map_info(tsk->group_leader, addr, addr + length, 0);
return 0;
}
-/* XXX: this needs to be address-space-specific. */
-static unsigned long _stp_module_relocate(const char *module, const char *section, unsigned long offset)
+/* Returns absolute address of offset into module/section for given task.
+ If tsk == NULL module/section is assumed to be absolute/static already
+ (e.g. kernel, kernel-modules and static executables). Returns zero when
+ module and section couldn't be found (aren't in memory yet). */
+static unsigned long _stp_module_relocate(const char *module,
+ const char *section,
+ unsigned long offset,
+ struct task_struct *tsk)
{
+ /* XXX This doesn't look thread safe XXX */
static struct _stp_module *last = NULL;
static struct _stp_section *last_sec;
+ static struct task_struct *last_tsk;
+ static unsigned long last_offset;
unsigned i, j;
/* if module is -1, we invalidate last. _stp_del_module calls this when modules are deleted. */
@@ -110,8 +118,10 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
/* Most likely our relocation is in the same section of the same module as the last. */
if (last) {
- if (!strcmp(module, last->name) && !strcmp(section, last_sec->name)) {
- offset += last_sec->addr;
+ if (!strcmp(module, last->name)
+ && !strcmp(section, last_sec->name)
+ && tsk == last_tsk) {
+ offset += last_offset;
dbug_sym(1, "cached address=%lx\n", offset);
return offset;
}
@@ -124,11 +134,33 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
for (j = 0; j < last->num_sections; j++) {
last_sec = &last->sections[j];
if (!strcmp(section, last_sec->name)) {
-
- if (last_sec->addr == 0) /* module/section not in memory */
- continue;
-
- offset += last_sec->addr;
+ /* mod and sec name match. tsk should match dynamic/static. */
+ if (last_sec->static_addr != 0) {
+ last_offset = last_sec->static_addr;
+ } else {
+ if (!tsk) { /* static section, not in memory yet? */
+ if (strcmp(".dynamic", section) == 0)
+ _stp_error("internal error, _stp_module_relocate '%s' "
+ "section '%s', should not be tsk dynamic\n",
+ module, section);
+ last = NULL;
+ return 0;
+ } else { /* dynamic section, look up through tsk vma. */
+ if (strcmp(".dynamic", last_sec->name) != 0) {
+ _stp_error("internal error, _stp_module_relocate '%s' "
+ "section '%s', should not be tsk dynamic\n",
+ module, section);
+ return 0;
+ }
+ if (stap_find_vma_map_info_user(tsk->group_leader, last,
+ &last_offset, NULL,
+ NULL) != 0) {
+ last = NULL;
+ return 0;
+ }
+ }
+ }
+ offset += last_offset;
dbug_sym(1, "address=%lx\n", offset);
return offset;
}
@@ -140,11 +172,12 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
}
/* Return module owner and, if sec != NULL, fills in closest section
- of the address if found, return NULL otherwise.
- XXX: needs to be address-space-specific. */
+ of the address if found, return NULL otherwise. Fills in rel_addr
+ (addr relative to closest section) when given. */
static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
struct task_struct *task,
- struct _stp_section **sec)
+ struct _stp_section **sec,
+ unsigned long *rel_addr)
{
void *user = NULL;
unsigned midx = 0;
@@ -160,11 +193,21 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
{
struct _stp_module *m = (struct _stp_module *)user;
if (sec)
- *sec = &m->sections[0]; // XXX check actual section and relocate
+ *sec = &m->sections[0]; // dynamic user modules have one section.
+ if (rel_addr)
+ {
+ /* XXX .absolute sections really shouldn't be here... */
+ if (strcmp(".dynamic", m->sections[0].name) == 0)
+ *rel_addr = addr - vm_start;
+ else
+ *rel_addr = addr;
+ }
dbug_sym(1, "found section %s in module %s at 0x%lx\n",
m->sections[0].name, m->name, vm_start);
return m;
}
+ /* XXX should really not fallthrough, but sometimes current is passed
+ when it shouldn't - see probefunc() for example. */
}
for (midx = 0; midx < _stp_num_modules; midx++)
@@ -174,12 +217,14 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
{
unsigned long sec_addr;
unsigned long sec_size;
- sec_addr = _stp_modules[midx]->sections[secidx].addr;
+ sec_addr = _stp_modules[midx]->sections[secidx].static_addr;
sec_size = _stp_modules[midx]->sections[secidx].size;
if (addr >= sec_addr && addr < sec_addr + sec_size)
{
if (sec)
*sec = & _stp_modules[midx]->sections[secidx];
+ if (rel_addr)
+ *rel_addr = addr - sec_addr;
return _stp_modules[midx];
}
}
@@ -188,7 +233,6 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
}
-/* XXX: needs to be address-space-specific. */
static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbolsize,
unsigned long *offset,
const char **modname,
@@ -200,13 +244,14 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo
struct _stp_section *sec = NULL;
struct _stp_symbol *s = NULL;
unsigned end, begin = 0;
+ unsigned long rel_addr = 0;
- m = _stp_mod_sec_lookup(addr, task, &sec);
+ m = _stp_mod_sec_lookup(addr, task, &sec, &rel_addr);
if (unlikely (m == NULL || sec == NULL))
return NULL;
/* NB: relativize the address to the section. */
- addr -= sec->addr;
+ addr = rel_addr;
end = sec->num_symbols;
/* binary search for symbols within the module */
@@ -268,9 +313,9 @@ static int _stp_module_check(void)
/* notes end address */
if (!strcmp(m->name, "kernel")) {
notes_addr = _stp_module_relocate("kernel",
- "_stext", m->build_id_offset);
+ "_stext", m->build_id_offset, NULL);
base_addr = _stp_module_relocate("kernel",
- "_stext", 0);
+ "_stext", 0, NULL);
} else {
notes_addr = m->notes_sect + m->build_id_offset;
base_addr = m->notes_sect;
@@ -446,14 +491,20 @@ static void _stp_sym_init(void)
static struct stap_task_finder_target vmcb = {
// NB: no .pid, no .procname filters here.
// This means that we get a system-wide mmap monitoring
- // widget while the script is running. (The system-wideness may
- // be restricted by stap -c or -x.) But this seems to
- // be necessary if we want to to stack tracebacks through arbitrary
- // shared libraries. XXX: There may be an optimization opportunity
- // for executables (for which the main task-finder callback should be
- // sufficient).
+ // widget while the script is running. (The
+ // system-wideness may be restricted by stap -c or
+ // -x.) But this seems to be necessary if we want to
+ // to stack tracebacks through arbitrary shared libraries.
+ //
+ // XXX: There may be an optimization opportunity
+ // for executables (for which the main task-finder
+ // callback should be sufficient).
+ .pid = 0,
+ .procname = NULL,
+ .callback = &_stp_tf_exec_cb,
.mmap_callback = &_stp_tf_mmap_cb,
.munmap_callback = &_stp_tf_munmap_cb,
+ .mprotect_callback = NULL
};
if (! initialized) {
int rc;
@@ -462,8 +513,10 @@ static void _stp_sym_init(void)
#ifdef DEBUG_TASK_FINDER_VMA
_stp_dbug(__FUNCTION__, __LINE__, "registered vmcb");
#endif
- (void) rc; // XXX
- initialized = 1;
+ if (rc != 0)
+ _stp_error("Couldn't register task finder target: %d\n", rc);
+ else
+ initialized = 1;
}
#endif
}
diff --git a/runtime/sym.h b/runtime/sym.h
index 9f2bdfd0..ce6ab736 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -17,7 +17,7 @@ struct _stp_symbol {
struct _stp_section {
const char *name;
- unsigned long addr; /* XXX: belongs in per-address-space tables */
+ unsigned long static_addr; /* XXX non-null if everywhere the same. */
unsigned long size; /* length of the address space module covers. */
struct _stp_symbol *symbols; /* ordered by address */
unsigned num_symbols;
@@ -70,7 +70,10 @@ static unsigned long _stp_kretprobe_trampoline;
_stp_sym_init () should track vma maps. */
static char _stp_need_vma_tracker;
-static unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset);
+static unsigned long _stp_module_relocate (const char *module,
+ const char *section,
+ unsigned long offset,
+ struct task_struct *tsk);
static struct _stp_module *_stp_get_unwind_info (unsigned long addr);
#endif /* _STP_SYM_H_ */
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index ed9c6f4f..9a32323f 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -270,6 +270,7 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
// Remove the vma entry from the vma hash table.
+// Returns -ESRCH if the entry isn't present.
static int
stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
unsigned long vm_end, unsigned long vm_pgoff)
@@ -277,6 +278,7 @@ stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
struct hlist_head *head;
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
+ int rc = -ESRCH;
// Take a write lock since we are most likely going to delete
// after reading.
@@ -286,13 +288,15 @@ stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
if (entry != NULL) {
hlist_del(&entry->hlist);
__stp_tf_vma_put_free_entry(entry);
+ rc = 0;
}
write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
- return 0;
+ return rc;
}
-// Finds vma info if the vma is present in the vma map hash table.
-// Returns ESRCH if not present. The __stp_tf_vma_lock must *not* be
+// Finds vma info if the vma is present in the vma map hash table for
+// a given task and address (between vm_start and vm_end).
+// Returns -ESRCH if not present. The __stp_tf_vma_lock must *not* be
// locked before calling this function.
static int
stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
@@ -303,7 +307,7 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
struct __stp_tf_vma_entry *found_entry = NULL;
- int rc = ESRCH;
+ int rc = -ESRCH;
unsigned long flags;
read_lock_irqsave(&__stp_tf_vma_lock, flags);
@@ -330,3 +334,62 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return rc;
}
+
+// Finds vma info if the vma is present in the vma map hash table for
+// a given task with the given user handle.
+// Returns -ESRCH if not present. The __stp_tf_vma_lock must *not* be
+// locked before calling this function.
+static int
+stap_find_vma_map_info_user(struct task_struct *tsk, void *user,
+ unsigned long *vm_start, unsigned long *vm_end,
+ unsigned long *vm_pgoff)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct __stp_tf_vma_entry *entry;
+ struct __stp_tf_vma_entry *found_entry = NULL;
+ int rc = -ESRCH;
+
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_vma_lock, flags);
+ head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
+ hlist_for_each_entry(entry, node, head, hlist) {
+ if (tsk->pid == entry->pid
+ && user == entry->user) {
+ found_entry = entry;
+ break;
+ }
+ }
+ if (found_entry != NULL) {
+ if (vm_start != NULL)
+ *vm_start = found_entry->vm_start;
+ if (vm_end != NULL)
+ *vm_end = found_entry->vm_end;
+ if (vm_pgoff != NULL)
+ *vm_pgoff = found_entry->vm_pgoff;
+ rc = 0;
+ }
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
+ return rc;
+}
+
+static int
+stap_drop_vma_maps(struct task_struct *tsk)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct hlist_node *n;
+ struct __stp_tf_vma_entry *entry;
+
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
+ head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
+ hlist_for_each_entry_safe(entry, node, n, head, hlist) {
+ if (tsk->pid == entry->pid) {
+ hlist_del(&entry->hlist);
+ __stp_tf_vma_put_free_entry(entry);
+ }
+ }
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
+ return 0;
+}
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index a214d1f2..e2f9fd65 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -61,7 +61,7 @@ static void _stp_do_relocation(const char __user *buf, size_t count)
continue;
else
{
- _stp_modules[mi]->sections[si].addr = msg.address;
+ _stp_modules[mi]->sections[si].static_addr = msg.address;
break;
}
} /* loop over sections */
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 7607770e..c8e3580d 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -496,7 +496,7 @@ static char *_stp_eh_enc_name(signed type)
// and the elfutils base relocation done during loading of the .dwarf_frame
// in translate.cxx.
static unsigned long
-adjustStartLoc (unsigned long startLoc,
+adjustStartLoc (unsigned long startLoc, struct task_struct *tsk,
struct _stp_module *m,
struct _stp_section *s,
unsigned ptrType, int is_ehframe)
@@ -521,10 +521,14 @@ adjustStartLoc (unsigned long startLoc,
return startLoc;
}
- if (strcmp (s->name, ".dynamic") == 0)
- return startLoc + s->addr;
+ if (strcmp (s->name, ".dynamic") == 0) {
+ unsigned long vm_addr;
+ if (stap_find_vma_map_info_user(tsk->group_leader, m,
+ &vm_addr, NULL, NULL) == 0)
+ return startLoc + vm_addr;
+ }
- startLoc = _stp_module_relocate (m->name, s->name, startLoc);
+ startLoc = _stp_module_relocate (m->name, s->name, startLoc, tsk);
startLoc -= m->dwarf_module_base;
return startLoc;
}
@@ -532,7 +536,7 @@ adjustStartLoc (unsigned long startLoc,
/* If we previously created an unwind header, then use it now to binary search */
/* for the FDE corresponding to pc. XXX FIXME not currently supported. */
-static u32 *_stp_search_unwind_hdr(unsigned long pc,
+static u32 *_stp_search_unwind_hdr(unsigned long pc, struct task_struct *tsk,
struct _stp_module *m,
struct _stp_section *s)
{
@@ -581,7 +585,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
do {
const u8 *cur = ptr + (num / 2) * (2 * tableSize);
startLoc = read_pointer(&cur, cur + tableSize, hdr[3]);
- startLoc = adjustStartLoc(startLoc, m, s, hdr[3], 1);
+ startLoc = adjustStartLoc(startLoc, tsk, m, s, hdr[3], 1);
if (pc < startLoc)
num /= 2;
else {
@@ -590,7 +594,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
}
} while (startLoc && num > 1);
- if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), m, s, hdr[3], 1)) != 0 && pc >= startLoc)
+ if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), tsk, m, s, hdr[3], 1)) != 0 && pc >= startLoc)
fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]);
dbug_unwind(1, "returning fde=%lx startLoc=%lx", (unsigned long) fde, startLoc);
@@ -601,6 +605,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
* number in case of an error. A positive return means unwinding is finished;
* don't try to fallback to dumping addresses on the stack. */
static int unwind_frame(struct unwind_frame_info *frame,
+ struct task_struct *tsk,
struct _stp_module *m, struct _stp_section *s,
void *table, uint32_t table_len, int is_ehframe)
{
@@ -619,7 +624,7 @@ static int unwind_frame(struct unwind_frame_info *frame,
goto err;
}
- fde = _stp_search_unwind_hdr(pc, m, s);
+ fde = _stp_search_unwind_hdr(pc, tsk, m, s);
dbug_unwind(1, "%s: fde=%lx\n", m->name, (unsigned long) fde);
/* found the fde, now set startLoc and endLoc */
@@ -629,7 +634,7 @@ static int unwind_frame(struct unwind_frame_info *frame,
ptr = (const u8 *)(fde + 2);
ptrType = fde_pointer_type(cie, table, table_len);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
+ startLoc = adjustStartLoc(startLoc, tsk, m, s, ptrType, is_ehframe);
dbug_unwind(2, "startLoc=%lx, ptrType=%s\n", startLoc, _stp_eh_enc_name(ptrType));
if (!(ptrType & DW_EH_PE_indirect))
@@ -660,7 +665,7 @@ static int unwind_frame(struct unwind_frame_info *frame,
ptr = (const u8 *)(fde + 2);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
+ startLoc = adjustStartLoc(startLoc, tsk, m, s, ptrType, is_ehframe);
dbug_unwind(2, "startLoc=%lx, ptrType=%s\n", startLoc, _stp_eh_enc_name(ptrType));
if (!startLoc)
continue;
@@ -902,18 +907,18 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = _stp_mod_sec_lookup (pc, tsk, &s);
+ m = _stp_mod_sec_lookup (pc, tsk, &s, NULL);
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
}
dbug_unwind(1, "trying debug_frame\n");
- res = unwind_frame (frame, m, s, m->debug_frame,
+ res = unwind_frame (frame, tsk, m, s, m->debug_frame,
m->debug_frame_len, 0);
if (res != 0) {
dbug_unwind(1, "debug_frame failed: %d, trying eh_frame\n", res);
- res = unwind_frame (frame, m, s, m->eh_frame,
+ res = unwind_frame (frame, tsk, m, s, m->eh_frame,
m->eh_frame_len, 1);
}
diff --git a/tapset/context-symbols.stp b/tapset/context-symbols.stp
index 6cd4dcbb..38900196 100644
--- a/tapset/context-symbols.stp
+++ b/tapset/context-symbols.stp
@@ -91,7 +91,7 @@ function probemod:string () %{ /* pure */
*dst = 0;
} else if (CONTEXT->regs) {
struct _stp_module *m;
- m = _stp_mod_sec_lookup (REG_IP(CONTEXT->regs), current, NULL);
+ m = _stp_mod_sec_lookup (REG_IP(CONTEXT->regs), current, NULL, NULL);
if (m && m->name)
strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN);
else
@@ -111,7 +111,7 @@ function probemod:string () %{ /* pure */
*/
function modname:string (addr: long) %{ /* pure */
struct _stp_module *m;
- m = _stp_mod_sec_lookup (THIS->addr, current, NULL);
+ m = _stp_mod_sec_lookup (THIS->addr, current, NULL, NULL);
if (m && m->name)
strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN);
else
diff --git a/tapsets.cxx b/tapsets.cxx
index a5e2c7a0..e14cc496 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -3429,7 +3429,7 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];";
s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];";
- s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address);";
+ s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address, NULL);";
s.op->newline() << "if (relocated_addr == 0) continue;"; // quietly; assume module is absent
s.op->newline() << "probe_point = sdp->pp;"; // for error messages
s.op->newline() << "if (sdp->return_p) {";
diff --git a/testsuite/buildok/vm.tracepoints.stp b/testsuite/buildok/vm.tracepoints.stp
new file mode 100644
index 00000000..488ca0fc
--- /dev/null
+++ b/testsuite/buildok/vm.tracepoints.stp
@@ -0,0 +1,31 @@
+#! stap -up4
+
+probe vm.kfree {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p \n", execname(), call_site, caller_function, ptr)
+}
+
+probe vm.kmalloc {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmem_cache_alloc {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmalloc_node {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmem_cache_alloc_node {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmem_cache_free {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p \n", execname(), call_site, caller_function, ptr)
+}
diff --git a/testsuite/systemtap.examples/memory/vm.tracepoints.meta b/testsuite/systemtap.examples/memory/vm.tracepoints.meta
new file mode 100644
index 00000000..9fdb73f6
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/vm.tracepoints.meta
@@ -0,0 +1,13 @@
+title: Collect slab allocation statistics
+name: vm.tracepoints.stp
+version: 1.0
+author: Rajasekhar
+keywords: memory slab allocator
+subsystem: memory
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The script will probe all memory slab/slub allocations and collects information about the size of the object (bytes requested) and user-space process in execution. When run over a period of time, it helps to correlate kernel-space memory consumption owing to user-space processes.
+test_check: stap -p4 vm.tracepoints.stp
+test_installcheck: stap vm.tracepoints.stp -c "sleep 10"
diff --git a/testsuite/systemtap.examples/memory/vm.tracepoints.stp b/testsuite/systemtap.examples/memory/vm.tracepoints.stp
new file mode 100644
index 00000000..07cee6f5
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/vm.tracepoints.stp
@@ -0,0 +1,18 @@
+global slabs
+
+probe vm.kmem_cache_alloc {
+ slabs [execname(), bytes_req]<<<1
+}
+
+probe timer.ms(10000)
+{
+ dummy = "";
+ foreach ([name, bytes] in slabs) {
+ if (dummy != name)
+ printf("\nProcess:%s\n", name);
+ printf("Slab_size:%d\tCount:%d\n", bytes, @count(slabs[name, bytes]));
+ dummy = name;
+ }
+ delete slabs
+ printf("\n-------------------------------------------------------\n\n")
+}