node = cursor->first;
for (k = 0; k < cursor->nr && i < PERF_MAX_STACK_DEPTH; k++) {
- if (machine->single_address_space &&
- machine__kernel_ip(machine, node->ip))
- /* kernel IPs were added already */;
- else if (node->ms.sym && node->ms.sym->inlined)
- /* we can't handle inlined callchains */;
- else
+ if (!(machine->single_address_space &&
+ machine__kernel_ip(machine, node->ip)) &&
+ !(node->ms.sym && symbol__inlined(node->ms.sym))) {
inject->raw_callchain->ips[i++] = node->ip;
+ }
node = node->next;
}
if (sym) {
if (!strcmp(sym->name, "__softirqentry_text_start") ||
!strcmp(sym->name, "__do_softirq"))
- sym->ignore = 1;
+ symbol__set_ignore(sym, true);
}
callchain_cursor_advance(cursor);
struct report *rep = arg;
struct symbol *sym = he->ms.sym;
- if (rep->symbol_ipc && sym && !sym->annotate2) {
+ if (rep->symbol_ipc && sym && !symbol__is_annotate2(sym)) {
struct evsel *evsel = hists_to_evsel(he->hists);
symbol__annotate2(&he->ms, evsel, NULL);
if (!strcmp(sym->name, "schedule") ||
!strcmp(sym->name, "__schedule") ||
!strcmp(sym->name, "preempt_schedule"))
- sym->ignore = 1;
+ symbol__set_ignore(sym, true);
}
callchain_cursor_advance(cursor);
list_for_each_entry(chain, &node->val, list) {
if (chain->ip >= PERF_CONTEXT_MAX)
continue;
- if (chain->ms.sym && chain->ms.sym->ignore)
+ if (chain->ms.sym && symbol__ignore(chain->ms.sym))
continue;
ret += fprintf(fp, "%s%s", first ? "" : sep,
callchain_list__sym_name(chain, bf, sizeof(bf),
"Please report to linux-kernel@vger.kernel.org\n",
ip, dso__long_name(dso), dso__symtab_origin(dso),
map__start(map), map__end(map), sym->start, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w', sym->name,
+ symbol__binding(sym) == STB_GLOBAL ? 'g' :
+ symbol__binding(sym) == STB_LOCAL ? 'l' : 'w', sym->name,
err ? "[unknown]" : uts.machine,
err ? "[unknown]" : uts.release, perf_version_string);
if (use_browser <= 0)
}
}
- if (al.sym == NULL || !al.sym->idle) {
+ if (al.sym == NULL ||
+ !symbol__is_idle(al.sym, al.map ? map__dso(al.map) : NULL, machine->env)) {
struct hists *hists = evsel__hists(sample->evsel);
struct hist_entry_iter iter = {
.sample = sample,
for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) {
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
- if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC)
+ if (symbol__type(sym) != STT_FUNC && symbol__type(sym) != STT_GNU_IFUNC)
continue;
/* Check for overlapping function symbols */
* such as __indirect_thunk_end.
*/
continue;
- } else if (is_ignored_symbol(sym->name, sym->type)) {
+ } else if (is_ignored_symbol(sym->name, symbol__type(sym))) {
/*
* Ignore hidden symbols, see scripts/kallsyms.c for the details
*/
if (dso__annotate_warned(dso))
return -1;
- if (not_annotated || !sym->annotate2) {
+ if (not_annotated || !symbol__is_annotate2(sym)) {
err = symbol__annotate2(ms, evsel, &browser.arch);
if (err) {
annotate_browser__symbol_annotate_error(&browser, err);
ui_browser__set_percent_color(browser, 0, current_entry);
ui_browser__printf(browser, "%*" PRIx64 " %*" PRIx64 " %c ",
mb->addrlen, sym->start, mb->addrlen, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w');
+ symbol__binding(sym) == STB_GLOBAL ? 'g' :
+ symbol__binding(sym) == STB_LOCAL ? 'l' : 'w');
width = browser->width - ((mb->addrlen * 2) + 4);
if (width > 0)
ui_browser__write_nstring(browser, sym->name, width);
h = annotated_source__histogram(src, evsel);
if (h == NULL) {
pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
- __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
+ __func__, __LINE__, sym->name, sym->start, addr, sym->end,
+ symbol__type(sym) == STT_FUNC);
return -ENOMEM;
}
annotation__init_column_widths(notes, sym);
annotation__update_column_widths(notes);
- sym->annotate2 = 1;
+ symbol__set_annotate2(sym, true);
return 0;
}
{
/* Same name, and global or the n'th found or any */
return !arch__compare_symbol_names(name, sym->name) &&
- ((!idx && sym->binding == STB_GLOBAL) ||
+ ((!idx && symbol__binding(sym) == STB_GLOBAL) ||
(idx > 0 && ++*cnt == idx) ||
idx < 0);
}
if (dso_sym_match(sym, sym_name, &cnt, -1)) {
pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
++cnt, sym->start,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w',
+ symbol__binding(sym) == STB_GLOBAL ? 'g' :
+ symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
sym->name);
near = true;
} else if (near) {
* symbol start. Otherwise do a faster comparison based
* on the symbol start address.
*/
- if (cnode->ms.sym->inlined || node->ms.sym->inlined) {
+ if (symbol__inlined(cnode->ms.sym) || symbol__inlined(node->ms.sym)) {
match = match_chain_strings(cnode->ms.sym->name,
node->ms.sym->name);
if (match != MATCH_ERROR)
int printed;
if (cl->ms.sym) {
- const char *inlined = cl->ms.sym->inlined ? " (inlined)" : "";
+ const char *inlined = symbol__inlined(cl->ms.sym) ? " (inlined)" : "";
if (show_srcline && cl->srcline)
printed = scnprintf(bf, bfsize, "%s %s%s",
d_al->symoff = al->addr - map__start(al->map) - sym->start;
else
d_al->symoff = 0;
- d_al->sym_binding = sym->binding;
+ d_al->sym_binding = symbol__binding(sym);
} else {
d_al->sym = NULL;
d_al->sym_start = 0;
sym = node->ms.sym;
map = node->ms.map;
- if (sym && sym->ignore && print_skip_ignored)
+ if (sym && symbol__ignore(sym) && print_skip_ignored)
goto next;
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
addr_location__exit(&node_al);
}
- if (print_dso && (!sym || !sym->inlined))
+ if (print_dso && (!sym || !symbol__inlined(sym)))
printed += map__fprintf_dsoname_dsoff(map, print_dsoff, addr, fp);
if (print_srcline) {
printed += map__fprintf_srcline(map, addr, "\n ", fp);
}
- if (sym && sym->inlined)
+ if (sym && symbol__inlined(sym))
printed += fprintf(fp, " (inlined)");
if (!print_oneline)
start = dso__first_symbol(map__dso(map));
for (sym = start; sym; sym = dso__next_symbol(sym)) {
- if (sym->binding == STB_GLOBAL &&
+ if (symbol__binding(sym) == STB_GLOBAL &&
!strcmp(sym->name, "__switch_to")) {
ip = map__unmap_ip(map, sym->start);
if (ip >= map__start(map) && ip < map__end(map)) {
return 0;
abort_delete_sym:
- if (inline_sym->inlined)
+ if (symbol__inlined(inline_sym))
symbol__delete(inline_sym);
abort_enomem:
args->err = -ENOMEM;
unsigned int i;
for (; sym; sym = dso__next_symbol(sym)) {
- if (sym->binding != STB_GLOBAL)
+ if (symbol__binding(sym) != STB_GLOBAL)
continue;
for (i = 0; i < ARRAY_SIZE(syms); i++) {
if (!strcmp(sym->name, syms[i]))
map__for_each_symbol_by_name(map, pp->function, sym, idx) {
if (uprobes) {
address = sym->start;
- if (sym->type == STT_GNU_IFUNC)
+ if (symbol__type(sym) == STT_GNU_IFUNC)
pr_warning("Warning: The probe function (%s) is a GNU indirect function.\n"
"Consider identifying the final function used at run time and set the probe directly on that.\n",
pp->function);
for (j = 0; j < num_matched_functions; j++) {
sym = syms[j];
- if (sym->type != STT_FUNC)
+ if (symbol__type(sym) != STT_FUNC)
continue;
/* There can be duplicated symbols in the map */
}
if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) ||
!hv_stores(sym, "end", newSVuv(node->ms.sym->end)) ||
- !hv_stores(sym, "binding", newSVuv(node->ms.sym->binding)) ||
+ !hv_stores(sym, "binding", newSVuv(symbol__binding(node->ms.sym))) ||
!hv_stores(sym, "name", newSVpvn(node->ms.sym->name,
node->ms.sym->namelen)) ||
!hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
pydict_set_item_string_decref(pysym, "end",
PyLong_FromUnsignedLongLong(node->ms.sym->end));
pydict_set_item_string_decref(pysym, "binding",
- _PyLong_FromLong(node->ms.sym->binding));
+ _PyLong_FromLong(symbol__binding(node->ms.sym)));
pydict_set_item_string_decref(pysym, "name",
_PyUnicode_FromStringAndSize(node->ms.sym->name,
node->ms.sym->namelen));
tuple_set_d64(t, 1, dso__db_id(dso));
tuple_set_d64(t, 2, sym->start);
tuple_set_d64(t, 3, sym->end);
- tuple_set_s32(t, 4, sym->binding);
+ tuple_set_s32(t, 4, symbol__binding(sym));
tuple_set_string(t, 5, sym->name);
call_object(tables->symbol_handler, t, "symbol_table");
if (sym_l == sym_r)
return 0;
- if (sym_l->inlined || sym_r->inlined) {
+ if (symbol__inlined(sym_l) || symbol__inlined(sym_r)) {
int ret = strcmp(sym_l->name, sym_r->name);
if (ret)
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
if (sym && map) {
- if (sym->type == STT_OBJECT) {
+ if (symbol__type(sym) == STT_OBJECT) {
ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
ip - map__unmap_ip(map, sym->start));
ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
width - ret,
sym->name);
- if (sym->inlined)
+ if (symbol__inlined(sym))
ret += repsep_snprintf(bf + ret, size - ret,
" (inlined)");
}
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
if (sym && map) {
- if (sym->type == STT_OBJECT) {
+ if (symbol__type(sym) == STT_OBJECT) {
ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
ip - map__unmap_ip(map, sym->start));
/* ensure that we don't alias an inlined symbol, which could
* lead to double frees in inline_node__delete
*/
- assert(!base_sym->inlined);
+ assert(!symbol__inlined(base_sym));
} else {
/* create a fake symbol for the inline frame */
inline_sym = symbol__new(base_sym ? base_sym->start : 0,
base_sym ? (base_sym->end - base_sym->start) : 0,
- base_sym ? base_sym->binding : 0,
- base_sym ? base_sym->type : 0,
+ base_sym ? symbol__binding(base_sym) : 0,
+ base_sym ? symbol__type(base_sym) : 0,
funcname);
if (inline_sym)
- inline_sym->inlined = 1;
+ symbol__set_inlined(inline_sym, true);
}
free(demangled);
list_del_init(&ilist->list);
zfree_srcline(&ilist->srcline);
/* only the inlined symbols are owned by the list */
- if (ilist->symbol && ilist->symbol->inlined)
+ if (ilist->symbol && symbol__inlined(ilist->symbol))
symbol__delete(ilist->symbol);
free(ilist);
}
sym = dso__find_symbol_nocache(dso, addr);
/* Expecting the address to be an IFUNC or IFUNC alias */
- if (!sym || sym->start != addr || (sym->type != STT_GNU_IFUNC && !sym->ifunc_alias))
+ if (!sym || sym->start != addr ||
+ (symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym)))
return false;
snprintf(buf, buf_sz, "%s@plt", sym->name);
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);
+static bool symbol__compute_is_idle(const char *name);
int vmlinux_path__nr_entries;
char **vmlinux_path;
else if ((a == 0) && (b > 0))
return SYMBOL_B;
- if (syma->type != symb->type) {
- if (syma->type == STT_NOTYPE)
+ if (symbol__type(syma) != symbol__type(symb)) {
+ if (symbol__type(syma) == STT_NOTYPE)
return SYMBOL_B;
- if (symb->type == STT_NOTYPE)
+ if (symbol__type(symb) == STT_NOTYPE)
return SYMBOL_A;
}
/* Prefer a non weak symbol over a weak one */
- a = syma->binding == STB_WEAK;
- b = symb->binding == STB_WEAK;
+ a = symbol__binding(syma) == STB_WEAK;
+ b = symbol__binding(symb) == 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;
+ a = symbol__binding(syma) == STB_GLOBAL;
+ b = symbol__binding(symb) == STB_GLOBAL;
if (a && !b)
return SYMBOL_A;
if (b && !a)
continue;
if (choose_best_symbol(curr, next) == SYMBOL_A) {
- if (next->type == STT_GNU_IFUNC)
- curr->ifunc_alias = true;
+ if (symbol__type(next) == STT_GNU_IFUNC)
+ symbol__set_ifunc_alias(curr, true);
rb_erase_cached(&next->rb_node, symbols);
symbol__delete(next);
goto again;
} else {
- if (curr->type == STT_GNU_IFUNC)
- next->ifunc_alias = true;
+ if (symbol__type(curr) == STT_GNU_IFUNC)
+ symbol__set_ifunc_alias(next, true);
nd = rb_next(&curr->rb_node);
rb_erase_cached(&curr->rb_node, symbols);
symbol__delete(curr);
sym->start = start;
sym->end = len ? start + len : start;
- sym->type = type;
- sym->binding = binding;
+ atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
+ (binding << SYMBOL_FLAG_BINDING_SHIFT));
sym->namelen = namelen - 1;
pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
free(((void *)sym) - symbol_conf.priv_size);
}
+void symbol__set_ignore(struct symbol *sym, bool ignore)
+{
+ if (ignore)
+ atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IGNORE);
+ else
+ atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IGNORE);
+}
+
+void symbol__set_annotate2(struct symbol *sym, bool annotate2)
+{
+ if (annotate2)
+ atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATE2);
+ else
+ atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATE2);
+}
+
+void symbol__set_inlined(struct symbol *sym, bool inlined)
+{
+ if (inlined)
+ atomic_fetch_or(&sym->flags, SYMBOL_FLAG_INLINED);
+ else
+ atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_INLINED);
+}
+
+void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias)
+{
+ if (ifunc_alias)
+ atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IFUNC_ALIAS);
+ else
+ atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
+}
+
+static void symbol__set_idle(struct symbol *sym, bool idle)
+{
+ uint16_t old_flags = atomic_load(&sym->flags);
+ uint16_t new_flags;
+ uint16_t idle_val = idle ? SYMBOL_IDLE__IDLE : SYMBOL_IDLE__NOT_IDLE;
+
+ do {
+ new_flags = old_flags & ~SYMBOL_FLAG_IDLE_MASK;
+ new_flags |= (idle_val << SYMBOL_FLAG_IDLE_SHIFT);
+ } while (!atomic_compare_exchange_weak(&sym->flags, &old_flags, new_flags));
+}
void symbols__delete(struct rb_root_cached *symbols)
{
struct symbol *pos;
*/
if (name[0] == '.')
name++;
- sym->idle = symbol__is_idle(name);
+ symbol__set_idle(sym, symbol__compute_is_idle(name));
}
while (*p != NULL) {
return err;
}
+bool symbol__is_idle(struct symbol *sym,
+ const struct dso *dso __maybe_unused,
+ struct perf_env *env __maybe_unused)
+{
+ uint16_t flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
+ uint16_t idle_val = (flags & SYMBOL_FLAG_IDLE_MASK) >> SYMBOL_FLAG_IDLE_SHIFT;
+
+ return idle_val == SYMBOL_IDLE__IDLE;
+}
+
/*
* These are symbols in the kernel image, so make sure that
* sym is from a kernel DSO.
*/
-static bool symbol__is_idle(const char *name)
+static bool symbol__compute_is_idle(const char *name)
{
const char * const idle_symbols[] = {
"acpi_idle_do_entry",
{
if (!symbol_conf.initialized)
return;
+
strlist__delete(symbol_conf.bt_stop_list);
strlist__delete(symbol_conf.sym_list);
strlist__delete(symbol_conf.dso_list);
#include <linux/refcount.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdatomic.h>
#include <linux/list.h>
#include <linux/rbtree.h>
#include <stdio.h>
struct maps;
struct option;
struct build_id;
+struct perf_env;
/*
* Ignore kernel mapping symbols, matching kernel is_mapping_symbol() logic.
GElf_Shdr *shp, const char *name, size_t *idx);
#endif
+enum symbol_idle_kind {
+ SYMBOL_IDLE__UNKNOWN = 0,
+ SYMBOL_IDLE__NOT_IDLE = 1,
+ SYMBOL_IDLE__IDLE = 2,
+};
+
+#define SYMBOL_FLAG_TYPE_SHIFT 0
+#define SYMBOL_FLAG_TYPE_MASK (0xF << SYMBOL_FLAG_TYPE_SHIFT)
+#define SYMBOL_FLAG_BINDING_SHIFT 4
+#define SYMBOL_FLAG_BINDING_MASK (0xF << SYMBOL_FLAG_BINDING_SHIFT)
+#define SYMBOL_FLAG_IDLE_SHIFT 8
+#define SYMBOL_FLAG_IDLE_MASK (0x3 << SYMBOL_FLAG_IDLE_SHIFT)
+#define SYMBOL_FLAG_IGNORE (1 << 10)
+#define SYMBOL_FLAG_INLINED (1 << 11)
+#define SYMBOL_FLAG_ANNOTATE2 (1 << 12)
+#define SYMBOL_FLAG_IFUNC_ALIAS (1 << 13)
+
/**
* A symtab entry. When allocated this may be preceded by an annotation (see
* symbol__annotation) and/or a browser_index (see symbol__browser_index).
u64 end;
/** Length of the string name. */
u16 namelen;
- /** ELF symbol type as defined for st_info. E.g STT_OBJECT or STT_FUNC. */
- u8 type:4;
- /** ELF binding type as defined for st_info. E.g. STB_WEAK or STB_GLOBAL. */
- u8 binding:4;
- /** Set true for kernel symbols of idle routines. */
- u8 idle:1;
- /** Resolvable but tools ignore it (e.g. idle routines). */
- u8 ignore:1;
- /** Symbol for an inlined function. */
- u8 inlined:1;
- /** Has symbol__annotate2 been performed. */
- u8 annotate2:1;
- /** Symbol is an alias of an STT_GNU_IFUNC */
- u8 ifunc_alias:1;
+ _Atomic uint16_t flags;
/** Architecture specific. Unused except on PPC where it holds st_other. */
u8 arch_sym;
/** The name of length namelen associated with the symbol. */
void symbol__delete(struct symbol *sym);
void symbols__delete(struct rb_root_cached *symbols);
+static inline u8 symbol__type(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_TYPE_MASK) >> SYMBOL_FLAG_TYPE_SHIFT;
+}
+
+static inline u8 symbol__binding(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_BINDING_MASK) >> SYMBOL_FLAG_BINDING_SHIFT;
+}
+
+static inline bool symbol__ignore(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_IGNORE) != 0;
+}
+
+static inline bool symbol__inlined(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_INLINED) != 0;
+}
+
+static inline bool symbol__is_annotate2(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_ANNOTATE2) != 0;
+}
+
+static inline bool symbol__ifunc_alias(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_IFUNC_ALIAS) != 0;
+}
+
+bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env *env);
+
+void symbol__set_ignore(struct symbol *sym, bool ignore);
+void symbol__set_annotate2(struct symbol *sym, bool annotate2);
+void symbol__set_inlined(struct symbol *sym, bool inlined);
+void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias);
+
/* symbols__for_each_entry - iterate over symbols (rb_root)
*
* @symbols: the rb_root of symbols
size_t size);
bool filename__has_section(const char *filename, const char *sec);
-struct perf_env;
int symbol__init(struct perf_env *env);
void symbol__exit(void);
void symbol__elf_init(void);
{
return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
sym->start, sym->end,
- sym->binding == STB_GLOBAL ? 'g' :
- sym->binding == STB_LOCAL ? 'l' : 'w',
+ symbol__binding(sym) == STB_GLOBAL ? 'g' :
+ symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
sym->name);
}