Release 4.10 tools/perf/util/symbol.c
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include "annotate.h"
#include "build-id.h"
#include "util.h"
#include "debug.h"
#include "machine.h"
#include "symbol.h"
#include "strlist.h"
#include "intlist.h"
#include "header.h"
#include <elf.h>
#include <limits.h>
#include <symbol/kallsyms.h>
#include <sys/utsname.h>
static int dso__load_kernel_sym(struct dso *dso, struct map *map);
static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map);
static bool symbol__is_idle(const char *name);
int vmlinux_path__nr_entries;
char **vmlinux_path;
struct symbol_conf symbol_conf = {
.use_modules = true,
.try_vmlinux_path = true,
.annotate_src = true,
.demangle = true,
.demangle_kernel = false,
.cumulate_callchain = true,
.show_hist_headers = true,
.symfs = "",
.event_group = true,
};
static enum dso_binary_type binary_type_symtab[] = {
DSO_BINARY_TYPE__KALLSYMS,
DSO_BINARY_TYPE__GUEST_KALLSYMS,
DSO_BINARY_TYPE__JAVA_JIT,
DSO_BINARY_TYPE__DEBUGLINK,
DSO_BINARY_TYPE__BUILD_ID_CACHE,
DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE,
DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
DSO_BINARY_TYPE__NOT_FOUND,
};
#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
bool symbol_type__is_a(char symbol_type, enum map_type map_type)
{
symbol_type = toupper(symbol_type);
switch (map_type) {
case MAP__FUNCTION:
return symbol_type == 'T' || symbol_type == 'W';
case MAP__VARIABLE:
return symbol_type == 'D';
default:
return false;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 42 | 85.71% | 2 | 66.67% |
anton blanchard | anton blanchard | 7 | 14.29% | 1 | 33.33% |
| Total | 49 | 100.00% | 3 | 100.00% |
static int prefix_underscores_count(const char *str)
{
const char *tail = str;
while (*tail == '_')
tail++;
return tail - str;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton blanchard | anton blanchard | 33 | 100.00% | 1 | 100.00% |
| Total | 33 | 100.00% | 1 | 100.00% |
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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
naveen n. rao | naveen n. rao | 72 | 98.63% | 1 | 50.00% |
anton blanchard | anton blanchard | 1 | 1.37% | 1 | 50.00% |
| Total | 73 | 100.00% | 2 | 100.00% |
static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
{
s64 a;
s64 b;
size_t na, nb;
/* Prefer a symbol with non zero length */
a = syma->end - syma->start;
b = symb->end - symb->start;
if ((b == 0) && (a > 0))
return SYMBOL_A;
else if ((a == 0) && (b > 0))
return SYMBOL_B;
/* Prefer a non weak symbol over a weak one */
a = syma->binding == STB_WEAK;
b = symb->binding == STB_WEAK;
if (b && !a)
return SYMBOL_A;
if (a && !b)
return SYMBOL_B;
/* Prefer a global symbol over a non global one */
a = syma->binding == STB_GLOBAL;
b = symb->binding == STB_GLOBAL;
if (a && !b)
return SYMBOL_A;
if (b && !a)
return SYMBOL_B;
/* Prefer a symbol with less underscores */
a = prefix_underscores_count(syma->name);
b = prefix_underscores_count(symb->name);
if (b > a)
return SYMBOL_A;
else if (a > b)
return SYMBOL_B;
/* Choose the symbol with the longest name */
na = strlen(syma->name);
nb = strlen(symb->name);
if (na > nb)
return SYMBOL_A;
else if (na < nb)
return SYMBOL_B;
return arch__choose_best_symbol(syma, symb);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton blanchard | anton blanchard | 209 | 86.72% | 1 | 33.33% |
adrian hunter | adrian hunter | 30 | 12.45% | 1 | 33.33% |
naveen n. rao | naveen n. rao | 2 | 0.83% | 1 | 33.33% |
| Total | 241 | 100.00% | 3 | 100.00% |
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) {
curr = rb_entry(nd, struct symbol, rb_node);
again:
nd = rb_next(&curr->rb_node);
next = rb_entry(nd, struct symbol, rb_node);
if (!nd)
break;
if (curr->start != next->start)
continue;
if (choose_best_symbol(curr, next) == SYMBOL_A) {
rb_erase(&next->rb_node, symbols);
symbol__delete(next);
goto again;
} else {
nd = rb_next(&curr->rb_node);
rb_erase(&curr->rb_node, symbols);
symbol__delete(curr);
}
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton blanchard | anton blanchard | 134 | 86.45% | 1 | 25.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 11 | 7.10% | 2 | 50.00% |
chenggang qin | chenggang qin | 10 | 6.45% | 1 | 25.00% |
| Total | 155 | 100.00% | 4 | 100.00% |
void symbols__fixup_end(struct rb_root *symbols)
{
struct rb_node *nd, *prevnd = rb_first(symbols);
struct symbol *curr, *prev;
if (prevnd == NULL)
return;
curr = rb_entry(prevnd, struct symbol, rb_node);
for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
prev = curr;
curr = rb_entry(nd, struct symbol, rb_node);
if (prev->end == prev->start && prev->end != curr->start)
prev->end = curr->start;
}
/* Last entry */
if (curr->end == curr->start)
curr->end = roundup(curr->start, 4096);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 136 | 100.00% | 5 | 100.00% |
| Total | 136 | 100.00% | 5 | 100.00% |
void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
{
struct maps *maps = &mg->maps[type];
struct map *next, *curr;
pthread_rwlock_wrlock(&maps->lock);
curr = maps__first(maps);
if (curr == NULL)
goto out_unlock;
for (next = map__next(curr); next; next = map__next(curr)) {
curr->end = next->start;
curr = next;
}
/*
* We still haven't the actual symbols, so guess the
* last map final address.
*/
curr->end = ~0ULL;
out_unlock:
pthread_rwlock_unlock(&maps->lock);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 108 | 99.08% | 10 | 90.91% |
ian munsie | ian munsie | 1 | 0.92% | 1 | 9.09% |
| Total | 109 | 100.00% | 11 | 100.00% |
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
{
size_t namelen = strlen(name) + 1;
struct symbol *sym = calloc(1, (symbol_conf.priv_size +
sizeof(*sym) + namelen));
if (sym == NULL)
return NULL;
if (symbol_conf.priv_size) {
if (symbol_conf.init_annotation) {
struct annotation *notes = (void *)sym;
pthread_mutex_init(¬es->lock, NULL);
}
sym = ((void *)sym) + symbol_conf.priv_size;
}
sym->start = start;
sym->end = len ? start + len : start;
sym->binding = binding;
sym->namelen = namelen - 1;
pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
__func__, name, start, sym->end);
memcpy(sym->name, name, namelen);
return sym;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 169 | 93.89% | 12 | 80.00% |
ingo molnar | ingo molnar | 5 | 2.78% | 1 | 6.67% |
mike galbraith | mike galbraith | 4 | 2.22% | 1 | 6.67% |
paul mackerras | paul mackerras | 2 | 1.11% | 1 | 6.67% |
| Total | 180 | 100.00% | 15 | 100.00% |
void symbol__delete(struct symbol *sym)
{
free(((void *)sym) - symbol_conf.priv_size);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 25 | 100.00% | 4 | 100.00% |
| Total | 25 | 100.00% | 4 | 100.00% |
void symbols__delete(struct rb_root *symbols)
{
struct symbol *pos;
struct rb_node *next = rb_first(symbols);
while (next) {
pos = rb_entry(next, struct symbol, rb_node);
next = rb_next(&pos->rb_node);
rb_erase(&pos->rb_node, symbols);
symbol__delete(pos);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 48 | 70.59% | 1 | 25.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 20 | 29.41% | 3 | 75.00% |
| Total | 68 | 100.00% | 4 | 100.00% |
void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel)
{
struct rb_node **p = &symbols->rb_node;
struct rb_node *parent = NULL;
const u64 ip = sym->start;
struct symbol *s;
if (kernel) {
const char *name = sym->name;
/*
* ppc64 uses function descriptors and appends a '.' to the
* start of every instruction address. Remove it.
*/
if (name[0] == '.')
name++;
sym->idle = symbol__is_idle(name);
}
while (*p != NULL) {
parent = *p;
s = rb_entry(parent, struct symbol, rb_node);
if (ip < s->start)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&sym->rb_node, parent, p);
rb_insert_color(&sym->rb_node, symbols);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 85 | 52.15% | 3 | 21.43% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 71 | 43.56% | 9 | 64.29% |
masami hiramatsu | masami hiramatsu | 5 | 3.07% | 1 | 7.14% |
yanmin zhang | yanmin zhang | 2 | 1.23% | 1 | 7.14% |
| Total | 163 | 100.00% | 14 | 100.00% |
void symbols__insert(struct rb_root *symbols, struct symbol *sym)
{
__symbols__insert(symbols, sym, false);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 24 | 100.00% | 1 | 100.00% |
| Total | 24 | 100.00% | 1 | 100.00% |
static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
{
struct rb_node *n;
if (symbols == NULL)
return NULL;
n = symbols->rb_node;
while (n) {
struct symbol *s = rb_entry(n, struct symbol, rb_node);
if (ip < s->start)
n = n->rb_left;
else if (ip > s->end || (ip == s->end && ip != s->start))
n = n->rb_right;
else
return s;
}
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 55 | 51.40% | 2 | 22.22% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 37 | 34.58% | 6 | 66.67% |
chris phlipot | chris phlipot | 15 | 14.02% | 1 | 11.11% |
| Total | 107 | 100.00% | 9 | 100.00% |
static struct symbol *symbols__first(struct rb_root *symbols)
{
struct rb_node *n = rb_first(symbols);
if (n)
return rb_entry(n, struct symbol, rb_node);
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 41 | 100.00% | 1 | 100.00% |
| Total | 41 | 100.00% | 1 | 100.00% |
static struct symbol *symbols__last(struct rb_root *symbols)
{
struct rb_node *n = rb_last(symbols);
if (n)
return rb_entry(n, struct symbol, rb_node);
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 41 | 100.00% | 1 | 100.00% |
| Total | 41 | 100.00% | 1 | 100.00% |
static struct symbol *symbols__next(struct symbol *sym)
{
struct rb_node *n = rb_next(&sym->rb_node);
if (n)
return rb_entry(n, struct symbol, rb_node);
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 44 | 100.00% | 1 | 100.00% |
| Total | 44 | 100.00% | 1 | 100.00% |
static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
{
struct rb_node **p = &symbols->rb_node;
struct rb_node *parent = NULL;
struct symbol_name_rb_node *symn, *s;
symn = container_of(sym, struct symbol_name_rb_node, sym);
while (*p != NULL) {
parent = *p;
s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
if (strcmp(sym->name, s->sym.name) < 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&symn->rb_node, parent, p);
rb_insert_color(&symn->rb_node, symbols);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 107 | 76.43% | 3 | 75.00% |
jiri olsa | jiri olsa | 33 | 23.57% | 1 | 25.00% |
| Total | 140 | 100.00% | 4 | 100.00% |
static void symbols__sort_by_name(struct rb_root *symbols,
struct rb_root *source)
{
struct rb_node *nd;
for (nd = rb_first(source); nd; nd = rb_next(nd)) {
struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
symbols__insert_by_name(symbols, pos);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 53 | 84.13% | 4 | 80.00% |
jiri olsa | jiri olsa | 10 | 15.87% | 1 | 20.00% |
| Total | 63 | 100.00% | 5 | 100.00% |
static struct symbol *symbols__find_by_name(struct rb_root *symbols,
const char *name)
{
struct rb_node *n;
struct symbol_name_rb_node *s = NULL;
if (symbols == NULL)
return NULL;
n = symbols->rb_node;
while (n) {
int cmp;
s = rb_entry(n, struct symbol_name_rb_node, rb_node);
cmp = arch__compare_symbol_names(name, s->sym.name);
if (cmp < 0)
n = n->rb_left;
else if (cmp > 0)
n = n->rb_right;
else
break;
}
if (n == NULL)
return NULL;
/* return first symbol that has same name (if any) */
for (n = rb_prev(n); n; n = rb_prev(n)) {
struct symbol_name_rb_node *tmp;
tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
break;
s = tmp;
}
return &s->sym;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 103 | 56.91% | 2 | 40.00% |
namhyung kim | namhyung kim | 74 | 40.88% | 1 | 20.00% |
martin liska | martin liska | 2 | 1.10% | 1 | 20.00% |
naveen n. rao | naveen n. rao | 2 | 1.10% | 1 | 20.00% |
| Total | 181 | 100.00% | 5 | 100.00% |
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;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 51 | 100.00% | 1 | 100.00% |
| Total | 51 | 100.00% | 1 | 100.00% |
void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
{
__symbols__insert(&dso->symbols[type], sym, dso->kernel);
/* update the symbol cache if necessary */
if (dso->last_find_result[type].addr >= sym->start &&
(dso->last_find_result[type].addr < sym->end ||
sym->start == sym->end)) {
dso->last_find_result[type].symbol = sym;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
chris phlipot | chris phlipot | 83 | 94.32% | 1 | 50.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 5 | 5.68% | 1 | 50.00% |
| Total | 88 | 100.00% | 2 | 100.00% |
struct symbol *dso__find_symbol(struct dso *dso,
enum map_type type, u64 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;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 77 | 100.00% | 4 | 100.00% |
| Total | 77 | 100.00% | 4 | 100.00% |
struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
{
return symbols__first(&dso->symbols[type]);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 28 | 100.00% | 2 | 100.00% |
| Total | 28 | 100.00% | 2 | 100.00% |
struct symbol *dso__last_symbol(struct dso *dso, enum map_type type)
{
return symbols__last(&dso->symbols[type]);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 28 | 100.00% | 2 | 100.00% |
| Total | 28 | 100.00% | 2 | 100.00% |
struct symbol *dso__next_symbol(struct symbol *sym)
{
return symbols__next(sym);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 18 | 100.00% | 1 | 100.00% |
| Total | 18 | 100.00% | 1 | 100.00% |
struct symbol *symbol__next_by_name(struct symbol *sym)
{
struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
struct rb_node *n = rb_next(&s->rb_node);
return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 58 | 100.00% | 1 | 100.00% |
| Total | 58 | 100.00% | 1 | 100.00% |
/*
* Teturns first symbol that matched with @name.
*/
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
const char *name)
{
return symbols__find_by_name(&dso->symbol_names[type], name);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 35 | 100.00% | 2 | 100.00% |
| Total | 35 | 100.00% | 2 | 100.00% |
void dso__sort_by_name(struct dso *dso, enum map_type type)
{
dso__set_sorted_by_name(dso, type);
return symbols__sort_by_name(&dso->symbol_names[type],
&dso->symbols[type]);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 41 | 100.00% | 2 | 100.00% |
| Total | 41 | 100.00% | 2 | 100.00% |
int modules__parse(const char *filename, void *arg,
int (*process_module)(void *arg, const char *name,
u64 start))
{
char *line = NULL;
size_t n;
FILE *file;
int err = 0;
file = fopen(filename, "r");
if (file == NULL)
return -1;
while (1) {
char name[PATH_MAX];
u64 start;
char *sep;
ssize_t line_len;
line_len = getline(&line, &n, file);
if (line_len < 0) {
if (feof(file))
break;
err = -1;
goto out;
}
if (!line) {
err = -1;
goto out;
}
line[--line_len] = '\0'; /* \n */
sep = strrchr(line, 'x');
if (sep == NULL)
continue;
hex2u64(sep + 1, &start);
sep = strchr(line, ' ');
if (sep == NULL)
continue;
*sep = '\0';
scnprintf(name, sizeof(name), "[%s]", line);
err = process_module(arg, name, start);
if (err)
break;
}
out:
free(line);
fclose(file);
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
adrian hunter | adrian hunter | 245 | 100.00% | 1 | 100.00% |
| Total | 245 | 100.00% | 1 | 100.00% |
struct process_kallsyms_args {
struct map *map;
struct dso *dso;