From ea549ffc2915aa58861637472b12196222673fa2 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 21 Dec 2009 13:02:19 +0100 Subject: 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. --- runtime/sym.c | 167 +++++++++++++++++++++++++++++--------------- runtime/sym.h | 7 +- runtime/task_finder_vma.c | 71 +++++++++++++++++-- runtime/transport/symbols.c | 2 +- runtime/unwind.c | 31 ++++---- 5 files changed, 201 insertions(+), 77 deletions(-) (limited to 'runtime') 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); } -- cgit From c6fcc4c1ca5f222cf90bf3968e34a10f09b30be4 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 21 Dec 2009 12:03:15 -0500 Subject: PR10601: cleanup for i386, x86-64 * runtime/loc2c-runtime.h (usr_i386): Fix si/di ordering. Add ip. (usr_x86_64): Add rip. (u_*_register): Use kernel standard ARRAY_SIZE() instead of S(). --- runtime/loc2c-runtime.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'runtime') diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index de59f0e5..c75639ee 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -103,7 +103,11 @@ struct usr_regset_lut { unsigned pos; }; -/* DWARF register number -to- user_regset offset/bank mapping table. */ + +/* DWARF register number -to- user_regset bank/offset mapping table. + The register numbers come from the processor-specific ELF documents. + The user-regset bank/offset values come from kernel $ARCH/include/asm/user*.h + or $ARCH/kernel/ptrace.c. */ static const struct usr_regset_lut url_i386[] = { { "ax", NT_PRSTATUS, 6*4 }, { "cx", NT_PRSTATUS, 1*4 }, @@ -111,8 +115,9 @@ static const struct usr_regset_lut url_i386[] = { { "bx", NT_PRSTATUS, 0*4 }, { "sp", NT_PRSTATUS, 15*4 }, { "bp", NT_PRSTATUS, 5*4 }, - { "di", NT_PRSTATUS, 4*4 }, { "si", NT_PRSTATUS, 3*4 }, + { "di", NT_PRSTATUS, 4*4 }, + { "ip", NT_PRSTATUS, 12*4 }, }; static const struct usr_regset_lut url_x86_64[] = { @@ -132,6 +137,11 @@ static const struct usr_regset_lut url_x86_64[] = { { "r13", NT_PRSTATUS, 2*8 }, { "r14", NT_PRSTATUS, 1*8 }, { "r15", NT_PRSTATUS, 0*8 }, + { "rip", NT_PRSTATUS, 16*8 }, + /* XXX: SSE registers %xmm0-%xmm7 */ + /* XXX: SSE2 registers %xmm8-%xmm15 */ + /* XXX: FP registers %st0-%st7 */ + /* XXX: MMX registers %mm0-%mm7 */ }; /* XXX: insert other architectures here. */ @@ -277,16 +287,15 @@ static void ursl_store64 (const struct usr_regset_lut* lut,unsigned lutsize, in } -#define S(array) sizeof(array)/sizeof(array[0]) #if defined (__i386__) -#define u_fetch_register(regno) ursl_fetch32(url_i386, S(url_i386), EM_386, regno) -#define u_store_register(regno,value) ursl_store32(url_i386, S(url_i386), EM_386, regno, value) +#define u_fetch_register(regno) ursl_fetch32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno) +#define u_store_register(regno,value) ursl_store32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno, value) #elif defined (__x86_64__) -#define u_fetch_register(regno) (_stp_probing_32bit_app(c->regs) ? ursl_fetch32(url_i386, S(url_i386), EM_386, regno) : ursl_fetch64(url_x86_64, S(url_x86_64), EM_X86_64, regno)) -#define u_store_register(regno,value) (_stp_probing_32bit_app(c->regs) ? ursl_store2(url_i386, S(url_i386), EM_386, regno, value) : ursl_store64(url_x86_64, S(url_x86_64), EM_X86_64, regno, value)) +#define u_fetch_register(regno) (_stp_probing_32bit_app(c->regs) ? ursl_fetch32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno) : ursl_fetch64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno)) +#define u_store_register(regno,value) (_stp_probing_32bit_app(c->regs) ? ursl_store2(url_i386, ARRAY_SIZE(url_i386), EM_386, regno, value) : ursl_store64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno, value)) #else -- cgit From b8b815b7163b3df61a7364e404a282cb17d775db Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 21 Dec 2009 21:04:36 -0600 Subject: PR11113 fix. Support new utrace API. * tapset-utrace.cxx (utrace_derived_probe_group::emit_module_decls): Handles new utrace api. * runtime/itrace.c (usr_itrace_report_signal): Ditto. (usr_itrace_report_clone): Ditto. (usr_itrace_report_death): Ditto. * runtime/task_finder.c (__stp_utrace_task_finder_report_clone): Ditto. (__stp_utrace_task_finder_report_exec): Ditto. (__stap_utrace_task_finder_report_death): Ditto. (__stp_utrace_task_finder_target_death): Ditto. (__stp_utrace_task_finder_target_quiesce): Ditto. (__stp_utrace_task_finder_target_syscall_entry): Ditto. (__stp_utrace_task_finder_target_syscall_exit): Ditto. * runtime/uprobes2/uprobes.c (uprobe_report_signal): Ditto. (uprobe_report_quiesce): Ditto. (uprobe_report_exit): Ditto. (uprobe_report_clone): Ditto. (uprobe_report_exec): Ditto. --- runtime/itrace.c | 30 +++++++++++++++ runtime/task_finder.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ runtime/uprobes2/uprobes.c | 35 +++++++++++++++-- 3 files changed, 155 insertions(+), 4 deletions(-) (limited to 'runtime') diff --git a/runtime/itrace.c b/runtime/itrace.c index 5b2437a4..399bfde0 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -84,11 +84,17 @@ static struct itrace_info *create_itrace_info( static u32 usr_itrace_report_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 usr_itrace_report_quiesce(u32 action, + struct utrace_attached_engine *engine, + unsigned long event) +#else static u32 usr_itrace_report_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event) #endif +#endif { int status; struct itrace_info *ui; @@ -113,6 +119,14 @@ static u32 usr_itrace_report_signal( const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 usr_itrace_report_signal(u32 action, + struct utrace_attached_engine *engine, + struct pt_regs *regs, + siginfo_t *info, + const struct k_sigaction *orig_ka, + struct k_sigaction *return_ka) +#else static u32 usr_itrace_report_signal(u32 action, struct utrace_attached_engine *engine, struct task_struct *tsk, @@ -121,7 +135,11 @@ static u32 usr_itrace_report_signal(u32 action, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif struct itrace_info *ui; u32 return_flags; unsigned long data = 0; @@ -177,11 +195,18 @@ static u32 usr_itrace_report_clone( unsigned long clone_flags, struct task_struct *child) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 usr_itrace_report_clone(u32 action, + struct utrace_attached_engine *engine, + unsigned long clone_flags, + struct task_struct *child) +#else static u32 usr_itrace_report_clone(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) #endif +#endif { return UTRACE_RESUME; } @@ -190,9 +215,14 @@ static u32 usr_itrace_report_clone(enum utrace_resume_action action, static u32 usr_itrace_report_death(struct utrace_attached_engine *e, struct task_struct *tsk) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 usr_itrace_report_death(struct utrace_attached_engine *e, + bool group_dead, int signal) +#else static u32 usr_itrace_report_death(struct utrace_attached_engine *e, struct task_struct *tsk, bool group_dead, int signal) #endif +#endif { struct itrace_info *ui = rcu_dereference(e->data); WARN_ON(!ui); diff --git a/runtime/task_finder.c b/runtime/task_finder.c index e89ac8ee..b77fff87 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -107,23 +107,35 @@ static u32 __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, struct task_struct *tsk); #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, + bool group_dead, int signal); +#else static u32 __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, struct task_struct *tsk, bool group_dead, int signal); #endif +#endif #ifdef UTRACE_ORIG_VERSION static u32 __stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk); #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) static u32 +__stp_utrace_task_finder_target_quiesce(u32 action, + struct utrace_attached_engine *engine, + unsigned long event); +#else __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event); #endif +#endif #ifdef UTRACE_ORIG_VERSION static u32 @@ -131,12 +143,19 @@ __stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *eng struct task_struct *tsk, struct pt_regs *regs); #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_syscall_entry(u32 action, + struct utrace_attached_engine *engine, + struct pt_regs *regs); +#else static u32 __stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs); #endif +#endif #ifdef UTRACE_ORIG_VERSION static u32 @@ -144,12 +163,19 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi struct task_struct *tsk, struct pt_regs *regs); #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_syscall_exit(u32 action, + struct utrace_attached_engine *engine, + struct pt_regs *regs); +#else static u32 __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs); #endif +#endif static int stap_register_task_finder_target(struct stap_task_finder_target *new_tgt) @@ -857,6 +883,13 @@ __stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine, unsigned long clone_flags, struct task_struct *child) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_report_clone(u32 action, + struct utrace_attached_engine *engine, + unsigned long clone_flags, + struct task_struct *child) +#else static u32 __stp_utrace_task_finder_report_clone(enum utrace_resume_action action, struct utrace_attached_engine *engine, @@ -864,7 +897,11 @@ __stp_utrace_task_finder_report_clone(enum utrace_resume_action action, unsigned long clone_flags, struct task_struct *child) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *parent = current; +#endif int rc; struct mm_struct *mm; char *mmpath_buf; @@ -898,6 +935,14 @@ __stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine, const struct linux_binprm *bprm, struct pt_regs *regs) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_report_exec(u32 action, + struct utrace_attached_engine *engine, + const struct linux_binfmt *fmt, + const struct linux_binprm *bprm, + struct pt_regs *regs) +#else static u32 __stp_utrace_task_finder_report_exec(enum utrace_resume_action action, struct utrace_attached_engine *engine, @@ -906,7 +951,11 @@ __stp_utrace_task_finder_report_exec(enum utrace_resume_action action, const struct linux_binprm *bprm, struct pt_regs *regs) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif size_t filelen; struct list_head *tgt_node; struct stap_task_finder_target *tgt; @@ -949,11 +998,17 @@ static u32 stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine, struct task_struct *tsk) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine, + bool group_dead, int signal) +#else static u32 stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine, struct task_struct *tsk, bool group_dead, int signal) #endif +#endif { debug_task_finder_detach(); return UTRACE_DETACH; @@ -964,12 +1019,21 @@ static u32 __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, struct task_struct *tsk) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, + bool group_dead, int signal) +#else static u32 __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, struct task_struct *tsk, bool group_dead, int signal) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif struct stap_task_finder_target *tgt = engine->data; if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { @@ -1132,13 +1196,23 @@ static u32 __stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_quiesce(u32 action, + struct utrace_attached_engine *engine, + unsigned long event) +#else static u32 __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, unsigned long event) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif struct stap_task_finder_target *tgt = engine->data; int rc; @@ -1201,13 +1275,23 @@ __stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *eng struct task_struct *tsk, struct pt_regs *regs) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_syscall_entry(u32 action, + struct utrace_attached_engine *engine, + struct pt_regs *regs) +#else static u32 __stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif struct stap_task_finder_target *tgt = engine->data; long syscall_no; unsigned long args[3] = { 0L }; @@ -1271,13 +1355,23 @@ __stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engi struct task_struct *tsk, struct pt_regs *regs) #else +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) +static u32 +__stp_utrace_task_finder_target_syscall_exit(u32 action, + struct utrace_attached_engine *engine, + struct pt_regs *regs) +#else static u32 __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) #endif +#endif { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif struct stap_task_finder_target *tgt = engine->data; unsigned long rv; struct __stp_tf_map_entry *entry; diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index 4c3a9c9c..02941e26 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -1881,7 +1881,9 @@ static void uprobe_inject_delayed_signals(struct list_head *delayed_signals) */ static u32 uprobe_report_signal(u32 action, struct utrace_attached_engine *engine, +#if !(defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)) struct task_struct *tsk, +#endif struct pt_regs *regs, siginfo_t *info, const struct k_sigaction *orig_ka, @@ -2129,9 +2131,15 @@ static int utask_quiesce_pending_sigtrap(struct uprobe_task *utask) * insertions or removals pending. If we're the last thread in this * process to quiesce, do the insertion(s) and/or removal(s). */ -static u32 uprobe_report_quiesce(enum utrace_resume_action action, +static u32 uprobe_report_quiesce( +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + u32 action, + struct utrace_attached_engine *engine, +#else + enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, +#endif unsigned long event) { struct uprobe_task *utask; @@ -2140,7 +2148,9 @@ static u32 uprobe_report_quiesce(enum utrace_resume_action action, utask = (struct uprobe_task *)rcu_dereference(engine->data); BUG_ON(!utask); +#if !(defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)) BUG_ON(tsk != current); // guaranteed by utrace 2008 +#endif if (utask->state == UPTASK_SSTEP) /* @@ -2243,8 +2253,14 @@ static void uprobe_cleanup_process(struct uprobe_process *uproc) */ static u32 uprobe_report_exit(enum utrace_resume_action action, struct utrace_attached_engine *engine, - struct task_struct *tsk, long orig_code, long *code) +#if !(defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)) + struct task_struct *tsk, +#endif + long orig_code, long *code) { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *tsk = current; +#endif struct uprobe_task *utask; struct uprobe_process *uproc; struct uprobe_probept *ppt; @@ -2449,10 +2465,15 @@ static int uprobe_fork_uproc(struct uprobe_process *parent_uproc, */ static u32 uprobe_report_clone(enum utrace_resume_action action, struct utrace_attached_engine *engine, +#if !(defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216)) struct task_struct *parent, +#endif unsigned long clone_flags, struct task_struct *child) { +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + struct task_struct *parent = current; +#endif int len; struct uprobe_process *uproc; struct uprobe_task *ptask, *ctask; @@ -2554,9 +2575,15 @@ done: * - We have to free up uprobe resources associated with * this process. */ -static u32 uprobe_report_exec(enum utrace_resume_action action, +static u32 uprobe_report_exec( +#if defined(UTRACE_API_VERSION) && (UTRACE_API_VERSION >= 20091216) + u32 action, struct utrace_attached_engine *engine, - struct task_struct *tsk, +#else + enum utrace_resume_action action, + struct utrace_attached_engine *engine, + struct task_struct *parent, +#endif const struct linux_binfmt *fmt, const struct linux_binprm *bprm, struct pt_regs *regs) -- cgit From 21b6dfed5aefcc09d1445df203627844586e6fda Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 21 Dec 2009 21:29:48 -0600 Subject: Fixed compilation on f11. * runtime/task_finder.c: Fixed last checkin. --- runtime/task_finder.c | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index b77fff87..deccfa76 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -130,6 +130,7 @@ __stp_utrace_task_finder_target_quiesce(u32 action, struct utrace_attached_engine *engine, unsigned long event); #else +static u32 __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, -- cgit From 1d11f54fcd6ee07b5541a464859ed3366c3642e4 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 22 Dec 2009 09:32:36 -0600 Subject: Fixed ia64 compile problem with runtime/stack-ia64.c. * runtime/stack-ia64.c (__stp_stack_print): Added new 'ri' parameter. --- runtime/stack-ia64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime') diff --git a/runtime/stack-ia64.c b/runtime/stack-ia64.c index a04355fa..c416d14d 100644 --- a/runtime/stack-ia64.c +++ b/runtime/stack-ia64.c @@ -49,7 +49,8 @@ static void __stp_show_stack_addr(struct unw_frame_info *info, void *arg) } static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, - struct task_struct *tsk) + struct task_struct *tsk, + struct uretprobe_instance *ri) { unsigned long *stack = (unsigned long *)®_SP(regs); struct dump_para para; -- cgit From 0ee3adb42f2f6d8bffe177e77a415b3a74f3a777 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 22 Dec 2009 12:53:17 -0500 Subject: ppc stack: transcribe portions of modern kernel ppc/.../asm/ptrace.h * runtime/stack-ppc.c (__stp_stack_print): Define STACK_FRAME_LR_SAVE, STACK_FRAME_REGS_MARKER,STACK_FRAME_MARKER, etc. --- runtime/stack-ppc.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'runtime') diff --git a/runtime/stack-ppc.c b/runtime/stack-ppc.c index 9670d06f..a9ff26ac 100644 --- a/runtime/stack-ppc.c +++ b/runtime/stack-ppc.c @@ -21,6 +21,24 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, return; _sp = (unsigned long *) sp; newsp = _sp[0]; +#ifndef STACK_FRAME_LR_SAVE /* from arch/powerpc/include/asm/ptrace.h */ +#ifdef __powerpc64__ +#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ +#define STACK_FRAME_LR_SAVE 2 /* Location of LR in stack frame */ +#define STACK_FRAME_REGS_MARKER ASM_CONST(0x7265677368657265) +#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD + 288) +#define STACK_FRAME_MARKER 12 +#define __SIGNAL_FRAMESIZE 128 +#define __SIGNAL_FRAMESIZE32 64 +#else /* __powerpc64__ */ +#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */ +#define STACK_FRAME_LR_SAVE 1 /* Location of LR in stack frame */ +#define STACK_FRAME_REGS_MARKER ASM_CONST(0x72656773) +#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD) +#define STACK_FRAME_MARKER 2 +#define __SIGNAL_FRAMESIZE 64 +#endif +#endif ip = _sp[STACK_FRAME_LR_SAVE]; if (!firstframe || ip != lr) { if (verbose) { -- cgit