static unsigned long _stp_umodule_relocate(const char *path, unsigned long offset, struct task_struct *tsk) { unsigned i; unsigned long vm_start = 0; dbug_sym(1, "[%d] %s, %lx\n", tsk->pid, path, offset); for (i = 0; i < _stp_num_modules; i++) { struct _stp_module *m = _stp_modules[i]; if (strcmp(path, m->path) || m->num_sections != 1) continue; if (!strcmp(m->sections[0].name, ".absolute")) return offset; if (strcmp(m->sections[0].name, ".dynamic")) continue; if (stap_find_vma_map_info_user(tsk->group_leader, m, &vm_start, NULL, NULL) == 0) { offset += vm_start; dbug_sym(1, "address=%lx\n", offset); return offset; } } return 0; }
/* mmap callback, will match new vma with _stp_module or register vma name. */ static int _stp_vma_mmap_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, char *path, struct dentry *dentry, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags) { int i, res; struct _stp_module *module = NULL; const char *name = ((dentry != NULL) ? (char *)dentry->d_name.name : NULL); if (path == NULL || *path == '\0') /* unknown? */ path = (char *)name; /* we'll copy this soon, in ..._add_vma_... */ dbug_task_vma(1, "mmap_cb: tsk %d:%d path %s, addr 0x%08lx, length 0x%08lx, offset 0x%lx, flags 0x%lx\n", tsk->pid, tsk->tgid, path, addr, length, offset, vm_flags); // We are only interested in the first load of the whole module that // is executable. We register whether or not we know the module, // so we can later lookup the name given an address for this task. if (path != NULL && offset == 0 && (vm_flags & VM_EXEC) && stap_find_vma_map_info(tsk, addr, NULL, NULL, NULL, NULL) != 0) { for (i = 0; i < _stp_num_modules; i++) { if (strcmp(path, _stp_modules[i]->path) == 0) { unsigned long vm_start = 0; unsigned long vm_end = 0; dbug_task_vma(1, "vm_cb: matched path %s to module (sec: %s)\n", path, _stp_modules[i]->sections[0].name); module = _stp_modules[i]; /* Make sure we really don't know about this module yet. If we do know, we might want to extend the coverage. */ res = stap_find_vma_map_info_user(tsk->group_leader, module, &vm_start, &vm_end, NULL); if (res == -ESRCH) res = stap_add_vma_map_info(tsk->group_leader, addr, addr + length, path, module); else if (res == 0 && vm_end + 1 == addr) res = stap_extend_vma_map_info(tsk->group_leader, vm_start, addr + length); /* VMA entries are allocated dynamically, this is fine, * since we are in a task_finder callback, which is in * user context. */ if (res != 0) { _stp_error ("Couldn't register module '%s' for pid %d (%d)\n", _stp_modules[i]->path, tsk->group_leader->pid, res); } return 0; } } /* None of the tracked modules matched, register without, * to make sure we can lookup the name later. Ignore errors, * we will just report unknown when asked and tables were * full. Restrict to target process when given to preserve * vma_map entry slots. */ if (_stp_target == 0 || _stp_target == tsk->group_leader->pid) { res = stap_add_vma_map_info(tsk->group_leader, addr, addr + length, path, NULL); dbug_task_vma(1, "registered '%s' for %d (res:%d) [%lx-%lx]\n", path, tsk->group_leader->pid, res, addr, addr + length); } } else if (path != NULL) { // Once registered, we may want to extend an earlier // registered region. A segment might be mapped with // different flags for different offsets. If so we want // to record the extended range so we can address more // precisely to module names and symbols. res = stap_extend_vma_map_info(tsk->group_leader, addr, addr + length); dbug_task_vma(1, "extended '%s' for %d (res:%d) [%lx-%lx]\n", path, tsk->group_leader->pid, res, addr, addr + length); } return 0; }