return tail - str;
}
-#define SYMBOL_A 0
-#define SYMBOL_B 1
+int __weak arch__choose_best_symbol(struct symbol *syma,
+ struct symbol *symb __maybe_unused)
+{
+ /* Avoid "SyS" kernel syscall aliases */
+ if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
+ return SYMBOL_B;
+ if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
+ return SYMBOL_B;
+
+ return SYMBOL_A;
+}
static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
{
else if (na < nb)
return SYMBOL_B;
- /* Avoid "SyS" kernel syscall aliases */
- if (na >= 3 && !strncmp(syma->name, "SyS", 3))
- return SYMBOL_B;
- if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
- return SYMBOL_B;
-
- return SYMBOL_A;
+ return arch__choose_best_symbol(syma, symb);
}
void symbols__fixup_duplicate(struct rb_root *symbols)
struct rb_node *nd;
struct symbol *curr, *next;
+ if (symbol_conf.allow_aliases)
+ return;
+
nd = rb_first(symbols);
while (nd) {
void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
{
- struct map *prev, *curr;
- struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
+ struct maps *maps = &mg->maps[type];
+ struct map *next, *curr;
- if (prevnd == NULL)
- return;
+ pthread_rwlock_wrlock(&maps->lock);
- curr = rb_entry(prevnd, struct map, rb_node);
+ curr = maps__first(maps);
+ if (curr == NULL)
+ goto out_unlock;
- for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
- prev = curr;
- curr = rb_entry(nd, struct map, rb_node);
- prev->end = curr->start;
+ for (next = map__next(curr); next; next = map__next(curr)) {
+ curr->end = next->start;
+ curr = next;
}
/*
* last map final address.
*/
curr->end = ~0ULL;
+
+out_unlock:
+ pthread_rwlock_unlock(&maps->lock);
}
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
const char *name)
{
struct rb_node *n;
- struct symbol_name_rb_node *s;
+ struct symbol_name_rb_node *s = NULL;
if (symbols == NULL)
return NULL;
int cmp;
s = rb_entry(n, struct symbol_name_rb_node, rb_node);
- cmp = strcmp(name, s->sym.name);
+ cmp = arch__compare_symbol_names(name, s->sym.name);
if (cmp < 0)
n = n->rb_left;
struct symbol_name_rb_node *tmp;
tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
- if (strcmp(tmp->sym.name, s->sym.name))
+ if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
break;
s = tmp;
return &s->sym;
}
+void dso__reset_find_symbol_cache(struct dso *dso)
+{
+ enum map_type type;
+
+ for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) {
+ dso->last_find_result[type].addr = 0;
+ dso->last_find_result[type].symbol = NULL;
+ }
+}
+
struct symbol *dso__find_symbol(struct dso *dso,
enum map_type type, u64 addr)
{
- return symbols__find(&dso->symbols[type], addr);
+ if (dso->last_find_result[type].addr != addr) {
+ dso->last_find_result[type].addr = addr;
+ dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
+ }
+
+ return dso->last_find_result[type].symbol;
}
struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
* symbols, setting length to 0, and rely on
* symbols__fixup_end() to fix it up.
*/
- sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
+ sym = symbol__new(start, 0, kallsyms2elf_binding(type), name);
if (sym == NULL)
return -ENOMEM;
/*
struct map_groups *kmaps = map__kmaps(map);
struct map *curr_map;
struct symbol *pos;
- int count = 0, moved = 0;
+ int count = 0;
+ struct rb_root old_root = dso->symbols[map->type];
struct rb_root *root = &dso->symbols[map->type];
struct rb_node *next = rb_first(root);
if (!kmaps)
return -1;
+ *root = RB_ROOT;
+
while (next) {
char *module;
pos = rb_entry(next, struct symbol, rb_node);
next = rb_next(&pos->rb_node);
+ rb_erase_init(&pos->rb_node, &old_root);
+
module = strchr(pos->name, '\t');
if (module)
*module = '\0';
curr_map = map_groups__find(kmaps, map->type, pos->start);
if (!curr_map || (filter && filter(curr_map, pos))) {
- rb_erase(&pos->rb_node, root);
symbol__delete(pos);
- } else {
- pos->start -= curr_map->start - curr_map->pgoff;
- if (pos->end)
- pos->end -= curr_map->start - curr_map->pgoff;
- if (curr_map != map) {
- rb_erase(&pos->rb_node, root);
- symbols__insert(
- &curr_map->dso->symbols[curr_map->type],
- pos);
- ++moved;
- } else {
- ++count;
- }
+ continue;
}
+
+ pos->start -= curr_map->start - curr_map->pgoff;
+ if (pos->end)
+ pos->end -= curr_map->start - curr_map->pgoff;
+ symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
+ ++count;
}
/* Symbols have been adjusted */
dso->adjust_symbols = 1;
- return count + moved;
+ return count;
}
/*
curr_map = map__new2(pos->start, ndso, map->type);
if (curr_map == NULL) {
- dso__delete(ndso);
+ dso__put(ndso);
return -1;
}
INIT_LIST_HEAD(&md.maps);
fd = open(kcore_filename, O_RDONLY);
- if (fd < 0)
+ if (fd < 0) {
+ pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n",
+ kcore_filename);
return -EINVAL;
+ }
/* Read new maps into temporary lists */
err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
/* Add new maps */
while (!list_empty(&md.maps)) {
new_map = list_entry(md.maps.next, struct map, node);
- list_del(&new_map->node);
+ list_del_init(&new_map->node);
if (new_map == replacement_map) {
map->start = new_map->start;
map->end = new_map->end;
map->pgoff = new_map->pgoff;
map->map_ip = new_map->map_ip;
map->unmap_ip = new_map->unmap_ip;
- map__delete(new_map);
/* Ensure maps are correctly ordered */
+ map__get(map);
map_groups__remove(kmaps, map);
map_groups__insert(kmaps, map);
+ map__put(map);
} else {
map_groups__insert(kmaps, new_map);
}
+
+ map__put(new_map);
}
/*
out_err:
while (!list_empty(&md.maps)) {
map = list_entry(md.maps.next, struct map, node);
- list_del(&map->node);
- map__delete(map);
+ list_del_init(&map->node);
+ map__put(map);
}
close(fd);
return -EINVAL;
if (kallsyms__delta(map, filename, &delta))
return -1;
- symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]);
+ symbols__fixup_duplicate(&dso->symbols[map->type]);
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
/*
* kernel modules know their symtab type - it's set when
- * creating a module dso in machine__new_module().
+ * creating a module dso in machine__findnew_module_map().
*/
return kmod && dso->symtab_type == type;
struct symsrc ss_[2];
struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
bool kmod;
+ unsigned char build_id[BUILD_ID_SIZE];
- dso__set_loaded(dso, map->type);
+ pthread_mutex_lock(&dso->lock);
+
+ /* check again under the dso->lock */
+ if (dso__loaded(dso, map->type)) {
+ ret = 1;
+ goto out;
+ }
- if (dso->kernel == DSO_TYPE_KERNEL)
- return dso__load_kernel_sym(dso, map, filter);
- else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
- return dso__load_guest_kernel_sym(dso, map, filter);
+ if (dso->kernel) {
+ if (dso->kernel == DSO_TYPE_KERNEL)
+ ret = dso__load_kernel_sym(dso, map, filter);
+ else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
+ ret = dso__load_guest_kernel_sym(dso, map, filter);
+
+ goto out;
+ }
if (map->groups && map->groups->machine)
machine = map->groups->machine;
struct stat st;
if (lstat(dso->name, &st) < 0)
- return -1;
+ goto out;
- if (st.st_uid && (st.st_uid != geteuid())) {
+ if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
pr_warning("File %s not owned by current user or root, "
- "ignoring it.\n", dso->name);
- return -1;
+ "ignoring it (use -f to override).\n", dso->name);
+ goto out;
}
ret = dso__load_perf_map(dso, map, filter);
dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
DSO_BINARY_TYPE__NOT_FOUND;
- return ret;
+ goto out;
}
if (machine)
name = malloc(PATH_MAX);
if (!name)
- return -1;
+ goto out;
kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+
+ /*
+ * Read the build id if possible. This is required for
+ * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
+ */
+ if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0)
+ dso__set_build_id(dso, build_id);
+
/*
* Iterate over candidate debug images.
* Keep track of "interesting" ones (those which have a symtab, dynsym,
out_free:
free(name);
if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
- return 0;
+ ret = 0;
+out:
+ dso__set_loaded(dso, map->type);
+ pthread_mutex_unlock(&dso->lock);
+
return ret;
}
struct map *map_groups__find_by_name(struct map_groups *mg,
enum map_type type, const char *name)
{
- struct rb_node *nd;
+ struct maps *maps = &mg->maps[type];
+ struct map *map;
- for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
- struct map *map = rb_entry(nd, struct map, rb_node);
+ pthread_rwlock_rdlock(&maps->lock);
+ for (map = maps__first(maps); map; map = map__next(map)) {
if (map->dso && strcmp(map->dso->short_name, name) == 0)
- return map;
+ goto out_unlock;
}
- return NULL;
+ map = NULL;
+
+out_unlock:
+ pthread_rwlock_unlock(&maps->lock);
+ return map;
}
int dso__load_vmlinux(struct dso *dso, struct map *map,
int i, err = 0;
char *filename = NULL;
+ pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+ vmlinux_path__nr_entries + 1);
+
+ for (i = 0; i < vmlinux_path__nr_entries; ++i) {
+ err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
+ if (err > 0)
+ goto out;
+ }
+
if (!symbol_conf.ignore_vmlinux_buildid)
filename = dso__build_id_filename(dso, NULL, 0);
if (filename != NULL) {
goto out;
free(filename);
}
-
- pr_debug("Looking at the vmlinux_path (%d entries long)\n",
- vmlinux_path__nr_entries + 1);
-
- for (i = 0; i < vmlinux_path__nr_entries; ++i) {
- err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
- if (err > 0)
- break;
- }
out:
return err;
}
{
while (--vmlinux_path__nr_entries >= 0)
zfree(&vmlinux_path[vmlinux_path__nr_entries]);
+ vmlinux_path__nr_entries = 0;
zfree(&vmlinux_path);
}
-static int vmlinux_path__init(struct perf_session_env *env)
+static int vmlinux_path__init(struct perf_env *env)
{
struct utsname uts;
char bf[PATH_MAX];
if (list_str == NULL)
return 0;
- *list = strlist__new(true, list_str);
+ *list = strlist__new(list_str, NULL);
if (!*list) {
pr_err("problems parsing %s list\n", list_name);
return -1;
}
+
+ symbol_conf.has_filter = true;
return 0;
}
return value;
}
-int symbol__init(struct perf_session_env *env)
+int symbol__init(struct perf_env *env)
{
const char *symfs;