summaryrefslogtreecommitdiffstats
path: root/runtime/task_finder_vma.c
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2009-12-21 13:02:19 +0100
committerTim Moore <timoore@redhat.com>2009-12-22 23:44:29 +0100
commit2d0ddea123e8d5d1113b80692689a80f37d46e6f (patch)
tree5ee08c296fddf8f681b065ac9b3b1383866da915 /runtime/task_finder_vma.c
parent7f24dd744bc6dbef16024c2ec3cbb0ee8e0d4ee5 (diff)
downloadsystemtap-steved-2d0ddea123e8d5d1113b80692689a80f37d46e6f.tar.gz
systemtap-steved-2d0ddea123e8d5d1113b80692689a80f37d46e6f.tar.xz
systemtap-steved-2d0ddea123e8d5d1113b80692689a80f37d46e6f.zip
PR11015 Support shared library reloading (in different processes)
* runtime/task_finder_vma.c (stap_remove_vma_map_info): Return negative status on failure. (stap_find_vma_map_info): Likewise. (stap_find_vma_map_info_user): New function. (stap_drop_vma_maps): New function. * runtime/sym.h (addr): Renamed to static_addr, to store addresses for sections which are always mapped at the same address. (_stp_module_relocate): Add extra struct task_struct *tsk argument. * runtime/sym.c (_stp_tf_exec_cb): New callback, calls stap_drop_vma_maps. (_stp_tf_mmap_cb): Don't store address in module.section, but call stap_add_vma_map_info() per tsk->group_leader for matched module. Don't register empty/null modules. (_stp_module_relocate): Take extra struct task_struct *tsk argument, cache last tsk used. Only use section->static_addr for none dynamic modules. Use stap_find_vma_map_info_user() to locate dynamic modules. (_stp_mod_sec_lookup): Add extra argument unsigned long *rel_addr to optionally store relative address when module/section found. (_stp_kallsyms_lookup): Use _stp_mod_sec_lookup to find relative address. (_stp_sym_init): Register _stp_tf_exec_cb in stap_task_finder_target. Add error check to see if task finder could be initialized. * dwflpp.cxx (emit_address): Pass NULL for kernel/modules and current for user tasks to _stp_module_relocate. * runtime/transport/symbols.c (_stp_do_relocation): Set new static_addr _stp_section field. * runtime/unwind.c (adjustStartLoc): Take new struct task_struct *tsk argument and pass to stap_find_vma_map_info_user and _stp_module_relocate to find adjusted addr. (_stp_search_unwind_hdr): Pass through struct task_struct *tsk. (unwind_frame): Likewise. * tapset/context-symbols.stp (probemod): Add NULL to _stp_mod_sec_lookup call to indicate we aren't interested in relative address. * tapsets.cxx (dwarf_derived_probe_group::emit_module_init): Pass NULL to _stp_module_relocate to indicate kernel/module address.
Diffstat (limited to 'runtime/task_finder_vma.c')
-rw-r--r--runtime/task_finder_vma.c71
1 files changed, 67 insertions, 4 deletions
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;
+}