mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-28 12:25:31 +00:00
perf/core improvements and fixes:
User visible: - Callchain improvements from Andi Kleen including: * Enable printing the srcline in the history * Make get_srcline fall back to sym+offset - Allow to force redirect pr_debug to stderr. (Andi Kleen) - TUI hist_entry browser fixes, including showing missing overhead value for first level callchain. Detected comparing the output of --stdio/--gui (that matched) with --tui, that had this problem. (Namhyung Kim) - Fix segfault due to invalid kernel dso access (Namhyung Kim) Infrastructure: - Move bfd_demangle stubbing to its only user (Arnaldo Carvalho de Melo) - 'perf stat' refactorings, moving stuff from it to evsel.c to use in per-pkg/snapshot format changes (Jiri Olsa) - Add per-pkg format file parsing (Matt Fleming) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJUdIHdAAoJEBpxZoYYoA71PA8IANT95oaF7pkBzWDseY9IoOE5 Ac8iINdtqj0gWspuImXqgjWqLfw55i7lCOgDNbNM3D0NpknhCr3tZ+azwYWFARQ0 TDm9LHpL6tlQTc9fshbPngMXbt60vptZ+m+FlG7wiMQHN1OFm2SMjDtbIo9FRkiJ QhJ8Mh3ztQLYXgr1GWD9+ULhqm9CHUEoyX8gOKsK7JyOaj9yycUq5znPmgzIXr6J knKlKio/sg+G/PqhIYmE5IFvhCkZ0k7cl0XAeK0WQeJFad9Af5DakmGwyg1CaBMW zq4QDtD9MgU4a96jmmjv6RCgQGazv4i9Kp42ILbkA+8I+e7HpuKuNy1m47tWDW0= =N5HI -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Callchain improvements from Andi Kleen including: * Enable printing the srcline in the history * Make get_srcline fall back to sym+offset - Allow to force redirect pr_debug to stderr. (Andi Kleen) - TUI hist_entry browser fixes, including showing missing overhead value for first level callchain. Detected comparing the output of --stdio/--gui (that matched) with --tui, that had this problem. (Namhyung Kim) - Fix segfault due to invalid kernel dso access (Namhyung Kim) Infrastructure changes: - Move bfd_demangle stubbing to its only user (Arnaldo Carvalho de Melo) - 'perf stat' refactorings, moving stuff from it to evsel.c to use in per-pkg/snapshot format changes (Jiri Olsa) - Add per-pkg format file parsing (Matt Fleming) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
e460bfdcf3
@ -227,10 +227,14 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *no
|
||||
}
|
||||
}
|
||||
|
||||
static void callchain_node__init_have_children(struct callchain_node *node)
|
||||
static void callchain_node__init_have_children(struct callchain_node *node,
|
||||
bool has_sibling)
|
||||
{
|
||||
struct callchain_list *chain;
|
||||
|
||||
chain = list_entry(node->val.next, struct callchain_list, list);
|
||||
chain->ms.has_children = has_sibling;
|
||||
|
||||
if (!list_empty(&node->val)) {
|
||||
chain = list_entry(node->val.prev, struct callchain_list, list);
|
||||
chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
|
||||
@ -241,11 +245,12 @@ static void callchain_node__init_have_children(struct callchain_node *node)
|
||||
|
||||
static void callchain__init_have_children(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
struct rb_node *nd = rb_first(root);
|
||||
bool has_sibling = nd && rb_next(nd);
|
||||
|
||||
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
|
||||
struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
|
||||
callchain_node__init_have_children(node);
|
||||
callchain_node__init_have_children(node, has_sibling);
|
||||
}
|
||||
}
|
||||
|
||||
@ -542,8 +547,11 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
|
||||
struct rb_node *node;
|
||||
int first_row = row, offset = level * LEVEL_OFFSET_STEP;
|
||||
u64 new_total;
|
||||
bool need_percent;
|
||||
|
||||
node = rb_first(root);
|
||||
need_percent = !!rb_next(node);
|
||||
|
||||
while (node) {
|
||||
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
|
||||
struct rb_node *next = rb_next(node);
|
||||
@ -560,7 +568,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else if (level > 1)
|
||||
else if (need_percent)
|
||||
extra_offset = LEVEL_OFFSET_STEP;
|
||||
|
||||
folded_sign = callchain_list__folded(chain);
|
||||
@ -573,7 +581,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
|
||||
str = callchain_list__sym_name(chain, bf, sizeof(bf),
|
||||
browser->show_dso);
|
||||
|
||||
if (was_first && level > 1) {
|
||||
if (was_first && need_percent) {
|
||||
double percent = cumul * 100.0 / total;
|
||||
|
||||
if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
|
||||
@ -790,6 +798,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
||||
.is_current_entry = current_entry,
|
||||
};
|
||||
|
||||
if (callchain_param.mode == CHAIN_GRAPH_REL) {
|
||||
if (symbol_conf.cumulate_callchain)
|
||||
total = entry->stat_acc->period;
|
||||
else
|
||||
total = entry->stat.period;
|
||||
}
|
||||
|
||||
printed += hist_browser__show_callchain(browser,
|
||||
&entry->sorted_chain, 1, row, total,
|
||||
hist_browser__show_callchain_entry, &arg,
|
||||
|
@ -1192,7 +1192,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
|
||||
goto next;
|
||||
|
||||
offset = start + i;
|
||||
src_line->path = get_srcline(map->dso, offset);
|
||||
src_line->path = get_srcline(map->dso, offset, NULL, false);
|
||||
insert_source_line(&tmp_root, src_line);
|
||||
|
||||
next:
|
||||
|
@ -815,7 +815,17 @@ char *callchain_list__sym_name(struct callchain_list *cl,
|
||||
int printed;
|
||||
|
||||
if (cl->ms.sym) {
|
||||
printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
|
||||
if (callchain_param.key == CCKEY_ADDRESS &&
|
||||
cl->ms.map && !cl->srcline)
|
||||
cl->srcline = get_srcline(cl->ms.map->dso,
|
||||
map__rip_2objdump(cl->ms.map,
|
||||
cl->ip),
|
||||
cl->ms.sym, false);
|
||||
if (cl->srcline)
|
||||
printed = scnprintf(bf, bfsize, "%s %s",
|
||||
cl->ms.sym->name, cl->srcline);
|
||||
else
|
||||
printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
|
||||
} else
|
||||
printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
|
||||
|
||||
|
@ -70,6 +70,7 @@ extern struct callchain_param callchain_param;
|
||||
struct callchain_list {
|
||||
u64 ip;
|
||||
struct map_symbol ms;
|
||||
char *srcline;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -19,13 +19,14 @@
|
||||
int verbose;
|
||||
bool dump_trace = false, quiet = false;
|
||||
int debug_ordered_events;
|
||||
static int redirect_to_stderr;
|
||||
|
||||
static int _eprintf(int level, int var, const char *fmt, va_list args)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (var >= level) {
|
||||
if (use_browser >= 1)
|
||||
if (use_browser >= 1 && !redirect_to_stderr)
|
||||
ui_helpline__vshow(fmt, args);
|
||||
else
|
||||
ret = vfprintf(stderr, fmt, args);
|
||||
@ -145,6 +146,7 @@ static struct debug_variable {
|
||||
} debug_variables[] = {
|
||||
{ .name = "verbose", .ptr = &verbose },
|
||||
{ .name = "ordered-events", .ptr = &debug_ordered_events},
|
||||
{ .name = "stderr", .ptr = &redirect_to_stderr},
|
||||
{ .name = NULL, }
|
||||
};
|
||||
|
||||
|
@ -876,9 +876,8 @@ void perf_evsel__delete(struct perf_evsel *evsel)
|
||||
free(evsel);
|
||||
}
|
||||
|
||||
static inline void compute_deltas(struct perf_evsel *evsel,
|
||||
int cpu,
|
||||
struct perf_counts_values *count)
|
||||
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
|
||||
struct perf_counts_values *count)
|
||||
{
|
||||
struct perf_counts_values tmp;
|
||||
|
||||
@ -898,6 +897,42 @@ static inline void compute_deltas(struct perf_evsel *evsel,
|
||||
count->run = count->run - tmp.run;
|
||||
}
|
||||
|
||||
void perf_counts_values__scale(struct perf_counts_values *count,
|
||||
bool scale, s8 *pscaled)
|
||||
{
|
||||
s8 scaled = 0;
|
||||
|
||||
if (scale) {
|
||||
if (count->run == 0) {
|
||||
scaled = -1;
|
||||
count->val = 0;
|
||||
} else if (count->run < count->ena) {
|
||||
scaled = 1;
|
||||
count->val = (u64)((double) count->val * count->ena / count->run + 0.5);
|
||||
}
|
||||
} else
|
||||
count->ena = count->run = 0;
|
||||
|
||||
if (pscaled)
|
||||
*pscaled = scaled;
|
||||
}
|
||||
|
||||
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
|
||||
perf_evsel__read_cb_t cb)
|
||||
{
|
||||
struct perf_counts_values count;
|
||||
|
||||
memset(&count, 0, sizeof(count));
|
||||
|
||||
if (FD(evsel, cpu, thread) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0)
|
||||
return -errno;
|
||||
|
||||
return cb(evsel, cpu, thread, &count);
|
||||
}
|
||||
|
||||
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
|
||||
int cpu, int thread, bool scale)
|
||||
{
|
||||
@ -913,16 +948,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
|
||||
if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
|
||||
return -errno;
|
||||
|
||||
compute_deltas(evsel, cpu, &count);
|
||||
|
||||
if (scale) {
|
||||
if (count.run == 0)
|
||||
count.val = 0;
|
||||
else if (count.run < count.ena)
|
||||
count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
|
||||
} else
|
||||
count.ena = count.run = 0;
|
||||
|
||||
perf_evsel__compute_deltas(evsel, cpu, &count);
|
||||
perf_counts_values__scale(&count, scale, NULL);
|
||||
evsel->counts->cpu[cpu] = count;
|
||||
return 0;
|
||||
}
|
||||
@ -956,23 +983,8 @@ int __perf_evsel__read(struct perf_evsel *evsel,
|
||||
}
|
||||
}
|
||||
|
||||
compute_deltas(evsel, -1, aggr);
|
||||
|
||||
evsel->counts->scaled = 0;
|
||||
if (scale) {
|
||||
if (aggr->run == 0) {
|
||||
evsel->counts->scaled = -1;
|
||||
aggr->val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aggr->run < aggr->ena) {
|
||||
evsel->counts->scaled = 1;
|
||||
aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
|
||||
}
|
||||
} else
|
||||
aggr->ena = aggr->run = 0;
|
||||
|
||||
perf_evsel__compute_deltas(evsel, -1, aggr);
|
||||
perf_counts_values__scale(aggr, scale, &evsel->counts->scaled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ struct perf_evsel {
|
||||
char *name;
|
||||
double scale;
|
||||
const char *unit;
|
||||
bool snapshot;
|
||||
struct event_format *tp_format;
|
||||
union {
|
||||
void *priv;
|
||||
@ -91,6 +92,7 @@ struct perf_evsel {
|
||||
bool immediate;
|
||||
bool system_wide;
|
||||
bool tracking;
|
||||
bool per_pkg;
|
||||
/* parse modifier helper */
|
||||
int exclude_GH;
|
||||
int nr_members;
|
||||
@ -110,6 +112,12 @@ struct thread_map;
|
||||
struct perf_evlist;
|
||||
struct record_opts;
|
||||
|
||||
void perf_counts_values__scale(struct perf_counts_values *count,
|
||||
bool scale, s8 *pscaled);
|
||||
|
||||
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
|
||||
struct perf_counts_values *count);
|
||||
|
||||
int perf_evsel__object_config(size_t object_size,
|
||||
int (*init)(struct perf_evsel *evsel),
|
||||
void (*fini)(struct perf_evsel *evsel));
|
||||
@ -227,6 +235,13 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
|
||||
(a)->attr.type == (b)->attr.type && \
|
||||
(a)->attr.config == (b)->attr.config)
|
||||
|
||||
typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel,
|
||||
int cpu, int thread,
|
||||
struct perf_counts_values *count);
|
||||
|
||||
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
|
||||
perf_evsel__read_cb_t cb);
|
||||
|
||||
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
|
||||
int cpu, int thread, bool scale);
|
||||
|
||||
|
@ -1106,8 +1106,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
|
||||
if (__machine__create_kernel_maps(machine, kernel) < 0)
|
||||
goto out_problem;
|
||||
|
||||
if (strstr(dso->long_name, "vmlinux"))
|
||||
dso__set_short_name(dso, "[kernel.vmlinux]", false);
|
||||
if (strstr(kernel->long_name, "vmlinux"))
|
||||
dso__set_short_name(kernel, "[kernel.vmlinux]", false);
|
||||
|
||||
machine__set_kernel_mmap_len(machine, event);
|
||||
|
||||
|
@ -360,7 +360,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
|
||||
|
||||
if (map && map->dso) {
|
||||
srcline = get_srcline(map->dso,
|
||||
map__rip_2objdump(map, addr));
|
||||
map__rip_2objdump(map, addr), NULL, true);
|
||||
if (srcline != SRCLINE_UNKNOWN)
|
||||
ret = fprintf(fp, "%s%s", prefix, srcline);
|
||||
free_srcline(srcline);
|
||||
|
@ -681,6 +681,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
|
||||
if (evsel) {
|
||||
evsel->unit = info.unit;
|
||||
evsel->scale = info.scale;
|
||||
evsel->per_pkg = info.per_pkg;
|
||||
evsel->snapshot = info.snapshot;
|
||||
}
|
||||
|
||||
return evsel ? 0 : -ENOMEM;
|
||||
|
@ -163,6 +163,41 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int fd;
|
||||
|
||||
snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name);
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
close(fd);
|
||||
|
||||
alias->per_pkg = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
|
||||
char *dir, char *name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int fd;
|
||||
|
||||
snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name);
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
alias->snapshot = true;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
|
||||
{
|
||||
struct perf_pmu_alias *alias;
|
||||
@ -181,6 +216,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
|
||||
INIT_LIST_HEAD(&alias->terms);
|
||||
alias->scale = 1.0;
|
||||
alias->unit[0] = '\0';
|
||||
alias->per_pkg = false;
|
||||
|
||||
ret = parse_events_terms(&alias->terms, buf);
|
||||
if (ret) {
|
||||
@ -194,6 +230,8 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
|
||||
*/
|
||||
perf_pmu__parse_unit(alias, dir, name);
|
||||
perf_pmu__parse_scale(alias, dir, name);
|
||||
perf_pmu__parse_per_pkg(alias, dir, name);
|
||||
perf_pmu__parse_snapshot(alias, dir, name);
|
||||
|
||||
list_add_tail(&alias->list, list);
|
||||
|
||||
@ -209,6 +247,10 @@ static inline bool pmu_alias_info_file(char *name)
|
||||
return true;
|
||||
if (len > 6 && !strcmp(name + len - 6, ".scale"))
|
||||
return true;
|
||||
if (len > 8 && !strcmp(name + len - 8, ".per-pkg"))
|
||||
return true;
|
||||
if (len > 9 && !strcmp(name + len - 9, ".snapshot"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -617,23 +659,27 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
|
||||
}
|
||||
|
||||
|
||||
static int check_unit_scale(struct perf_pmu_alias *alias,
|
||||
const char **unit, double *scale)
|
||||
static int check_info_data(struct perf_pmu_alias *alias,
|
||||
struct perf_pmu_info *info)
|
||||
{
|
||||
/*
|
||||
* Only one term in event definition can
|
||||
* define unit and scale, fail if there's
|
||||
* more than one.
|
||||
* define unit, scale and snapshot, fail
|
||||
* if there's more than one.
|
||||
*/
|
||||
if ((*unit && alias->unit) ||
|
||||
(*scale && alias->scale))
|
||||
if ((info->unit && alias->unit) ||
|
||||
(info->scale && alias->scale) ||
|
||||
(info->snapshot && alias->snapshot))
|
||||
return -EINVAL;
|
||||
|
||||
if (alias->unit)
|
||||
*unit = alias->unit;
|
||||
info->unit = alias->unit;
|
||||
|
||||
if (alias->scale)
|
||||
*scale = alias->scale;
|
||||
info->scale = alias->scale;
|
||||
|
||||
if (alias->snapshot)
|
||||
info->snapshot = alias->snapshot;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -649,12 +695,15 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
|
||||
struct perf_pmu_alias *alias;
|
||||
int ret;
|
||||
|
||||
info->per_pkg = false;
|
||||
|
||||
/*
|
||||
* Mark unit and scale as not set
|
||||
* (different from default values, see below)
|
||||
*/
|
||||
info->unit = NULL;
|
||||
info->scale = 0.0;
|
||||
info->unit = NULL;
|
||||
info->scale = 0.0;
|
||||
info->snapshot = false;
|
||||
|
||||
list_for_each_entry_safe(term, h, head_terms, list) {
|
||||
alias = pmu_find_alias(pmu, term);
|
||||
@ -664,10 +713,13 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = check_unit_scale(alias, &info->unit, &info->scale);
|
||||
ret = check_info_data(alias, info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (alias->per_pkg)
|
||||
info->per_pkg = true;
|
||||
|
||||
list_del(&term->list);
|
||||
free(term);
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ struct perf_pmu {
|
||||
struct perf_pmu_info {
|
||||
const char *unit;
|
||||
double scale;
|
||||
bool per_pkg;
|
||||
bool snapshot;
|
||||
};
|
||||
|
||||
#define UNIT_MAX_LEN 31 /* max length for event unit name */
|
||||
@ -39,6 +41,8 @@ struct perf_pmu_alias {
|
||||
struct list_head list; /* ELEM */
|
||||
char unit[UNIT_MAX_LEN+1];
|
||||
double scale;
|
||||
bool per_pkg;
|
||||
bool snapshot;
|
||||
};
|
||||
|
||||
struct perf_pmu *perf_pmu__find(const char *name);
|
||||
|
@ -291,7 +291,8 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
|
||||
else {
|
||||
struct map *map = left->ms.map;
|
||||
left->srcline = get_srcline(map->dso,
|
||||
map__rip_2objdump(map, left->ip));
|
||||
map__rip_2objdump(map, left->ip),
|
||||
left->ms.sym, true);
|
||||
}
|
||||
}
|
||||
if (!right->srcline) {
|
||||
@ -300,7 +301,8 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
|
||||
else {
|
||||
struct map *map = right->ms.map;
|
||||
right->srcline = get_srcline(map->dso,
|
||||
map__rip_2objdump(map, right->ip));
|
||||
map__rip_2objdump(map, right->ip),
|
||||
right->ms.sym, true);
|
||||
}
|
||||
}
|
||||
return strcmp(right->srcline, left->srcline);
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "util/util.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include "symbol.h"
|
||||
|
||||
#ifdef HAVE_LIBBFD_SUPPORT
|
||||
|
||||
/*
|
||||
@ -250,7 +252,8 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
|
||||
*/
|
||||
#define A2L_FAIL_LIMIT 123
|
||||
|
||||
char *get_srcline(struct dso *dso, unsigned long addr)
|
||||
char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym,
|
||||
bool show_sym)
|
||||
{
|
||||
char *file = NULL;
|
||||
unsigned line = 0;
|
||||
@ -258,7 +261,7 @@ char *get_srcline(struct dso *dso, unsigned long addr)
|
||||
const char *dso_name;
|
||||
|
||||
if (!dso->has_srcline)
|
||||
return SRCLINE_UNKNOWN;
|
||||
goto out;
|
||||
|
||||
if (dso->symsrc_filename)
|
||||
dso_name = dso->symsrc_filename;
|
||||
@ -289,7 +292,13 @@ out:
|
||||
dso->has_srcline = 0;
|
||||
dso__free_a2l(dso);
|
||||
}
|
||||
return SRCLINE_UNKNOWN;
|
||||
if (sym) {
|
||||
if (asprintf(&srcline, "%s+%ld", show_sym ? sym->name : "",
|
||||
addr - sym->start) < 0)
|
||||
return SRCLINE_UNKNOWN;
|
||||
} else if (asprintf(&srcline, "%s[%lx]", dso->short_name, addr) < 0)
|
||||
return SRCLINE_UNKNOWN;
|
||||
return srcline;
|
||||
}
|
||||
|
||||
void free_srcline(char *srcline)
|
||||
|
@ -11,6 +11,27 @@
|
||||
#include <symbol/kallsyms.h>
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
|
||||
extern char *cplus_demangle(const char *, int);
|
||||
|
||||
static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
|
||||
{
|
||||
return cplus_demangle(c, i);
|
||||
}
|
||||
#else
|
||||
#ifdef NO_DEMANGLE
|
||||
static inline char *bfd_demangle(void __maybe_unused *v,
|
||||
const char __maybe_unused *c,
|
||||
int __maybe_unused i)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#define PACKAGE 'perf'
|
||||
#include <bfd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
|
||||
static int elf_getphdrnum(Elf *elf, size_t *dst)
|
||||
{
|
||||
|
@ -23,27 +23,6 @@
|
||||
|
||||
#include "dso.h"
|
||||
|
||||
#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
|
||||
extern char *cplus_demangle(const char *, int);
|
||||
|
||||
static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
|
||||
{
|
||||
return cplus_demangle(c, i);
|
||||
}
|
||||
#else
|
||||
#ifdef NO_DEMANGLE
|
||||
static inline char *bfd_demangle(void __maybe_unused *v,
|
||||
const char __maybe_unused *c,
|
||||
int __maybe_unused i)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#define PACKAGE 'perf'
|
||||
#include <bfd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
|
||||
* for newer versions we can use mmap to reduce memory usage:
|
||||
|
@ -337,8 +337,10 @@ static inline int path__join3(char *bf, size_t size,
|
||||
}
|
||||
|
||||
struct dso;
|
||||
struct symbol;
|
||||
|
||||
char *get_srcline(struct dso *dso, unsigned long addr);
|
||||
char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym,
|
||||
bool show_sym);
|
||||
void free_srcline(char *srcline);
|
||||
|
||||
int filename__read_int(const char *filename, int *value);
|
||||
|
Loading…
Reference in New Issue
Block a user