perf addr_location: Add init/exit/copy functions
struct addr_location holds references to multiple reference counted objects. Add init/exit functions to make maintenance of those more consistent with the rest of the code and to try to avoid leaks. Modification of thread reference counts isn't included in this change. Committer notes: I needed to initialize result to sample->ip to make sure is set to something, fixing a compile time error, mostly keeping the previous logic as build_alloc_func_list() already does debugging/error prints about what went wrong if it takes the 'goto out'. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ali Saidi <alisaidi@amazon.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Brian Robbins <brianrob@linux.microsoft.com> Cc: Changbin Du <changbin.du@huawei.com> Cc: Dmitrii Dolgov <9erthalion6@gmail.com> Cc: Fangrui Song <maskray@google.com> Cc: German Gomez <german.gomez@arm.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Ivan Babrou <ivan@cloudflare.com> Cc: James Clark <james.clark@arm.com> Cc: Jing Zhang <renyu.zj@linux.alibaba.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.g.garry@oracle.com> Cc: K Prateek Nayak <kprateek.nayak@amd.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Miguel Ojeda <ojeda@kernel.org> Cc: Mike Leach <mike.leach@linaro.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Steinar H. Gunderson <sesse@google.com> Cc: Suzuki Poulouse <suzuki.poulose@arm.com> Cc: Wenyu Liu <liuwenyu7@huawei.com> Cc: Will Deacon <will@kernel.org> Cc: Yang Jihong <yangjihong1@huawei.com> Cc: Ye Xingchen <ye.xingchen@zte.com.cn> Cc: Yuan Can <yuancan@huawei.com> Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230608232823.4027869-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
620be847f4
commit
0dd5041c9a
@ -184,7 +184,7 @@ out:
|
|||||||
|
|
||||||
static int process_branch_callback(struct evsel *evsel,
|
static int process_branch_callback(struct evsel *evsel,
|
||||||
struct perf_sample *sample,
|
struct perf_sample *sample,
|
||||||
struct addr_location *al __maybe_unused,
|
struct addr_location *al,
|
||||||
struct perf_annotate *ann,
|
struct perf_annotate *ann,
|
||||||
struct machine *machine)
|
struct machine *machine)
|
||||||
{
|
{
|
||||||
@ -195,21 +195,29 @@ static int process_branch_callback(struct evsel *evsel,
|
|||||||
.hide_unresolved = symbol_conf.hide_unresolved,
|
.hide_unresolved = symbol_conf.hide_unresolved,
|
||||||
.ops = &hist_iter_branch,
|
.ops = &hist_iter_branch,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct addr_location a;
|
struct addr_location a;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (machine__resolve(machine, &a, sample) < 0)
|
addr_location__init(&a);
|
||||||
return -1;
|
if (machine__resolve(machine, &a, sample) < 0) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (a.sym == NULL)
|
if (a.sym == NULL) {
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (a.map != NULL)
|
if (a.map != NULL)
|
||||||
map__dso(a.map)->hit = 1;
|
map__dso(a.map)->hit = 1;
|
||||||
|
|
||||||
hist__account_cycles(sample->branch_stack, al, sample, false, NULL);
|
hist__account_cycles(sample->branch_stack, al, sample, false, NULL);
|
||||||
|
|
||||||
return hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann);
|
ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann);
|
||||||
|
out:
|
||||||
|
addr_location__exit(&a);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_annotation(struct perf_annotate *ann)
|
static bool has_annotation(struct perf_annotate *ann)
|
||||||
@ -272,10 +280,12 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_warning("problem processing %d event, skipping it.\n",
|
pr_warning("problem processing %d event, skipping it.\n",
|
||||||
event->header.type);
|
event->header.type);
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
|
if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
|
||||||
@ -288,7 +298,7 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
out_put:
|
out_put:
|
||||||
addr_location__put(&al);
|
addr_location__exit(&al);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,10 +286,12 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
|||||||
struct mem_info *mi, *mi_dup;
|
struct mem_info *mi, *mi_dup;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_debug("problem processing %d event, skipping it.\n",
|
pr_debug("problem processing %d event, skipping it.\n",
|
||||||
event->header.type);
|
event->header.type);
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c2c.stitch_lbr)
|
if (c2c.stitch_lbr)
|
||||||
@ -301,8 +303,10 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
mi = sample__resolve_mem(sample, &al);
|
mi = sample__resolve_mem(sample, &al);
|
||||||
if (mi == NULL)
|
if (mi == NULL) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The mi object is released in hists__add_entry_ops,
|
* The mi object is released in hists__add_entry_ops,
|
||||||
@ -368,7 +372,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
addr_location__put(&al);
|
addr_location__exit(&al);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
free_mi:
|
free_mi:
|
||||||
|
@ -409,15 +409,17 @@ static int diff__process_sample_event(struct perf_tool *tool,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_warning("problem processing %d event, skipping it.\n",
|
pr_warning("problem processing %d event, skipping it.\n",
|
||||||
event->header.type);
|
event->header.type);
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
|
if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out_put;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (compute) {
|
switch (compute) {
|
||||||
@ -426,7 +428,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
|
|||||||
NULL, NULL, NULL, sample, true)) {
|
NULL, NULL, NULL, sample, true)) {
|
||||||
pr_warning("problem incrementing symbol period, "
|
pr_warning("problem incrementing symbol period, "
|
||||||
"skipping event\n");
|
"skipping event\n");
|
||||||
goto out_put;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
hist__account_cycles(sample->branch_stack, &al, sample, false,
|
hist__account_cycles(sample->branch_stack, &al, sample, false,
|
||||||
@ -437,7 +439,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
|
|||||||
if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
|
if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
pr_debug("problem adding hist entry, skipping event\n");
|
pr_debug("problem adding hist entry, skipping event\n");
|
||||||
goto out_put;
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -446,7 +448,7 @@ static int diff__process_sample_event(struct perf_tool *tool,
|
|||||||
true)) {
|
true)) {
|
||||||
pr_warning("problem incrementing symbol period, "
|
pr_warning("problem incrementing symbol period, "
|
||||||
"skipping event\n");
|
"skipping event\n");
|
||||||
goto out_put;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +462,8 @@ static int diff__process_sample_event(struct perf_tool *tool,
|
|||||||
if (!al.filtered)
|
if (!al.filtered)
|
||||||
hists->stats.total_non_filtered_period += sample->period;
|
hists->stats.total_non_filtered_period += sample->period;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out_put:
|
out:
|
||||||
addr_location__put(&al);
|
addr_location__exit(&al);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,6 +743,7 @@ int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
thread = machine__findnew_thread(machine, sample->pid, sample->tid);
|
thread = machine__findnew_thread(machine, sample->pid, sample->tid);
|
||||||
if (thread == NULL) {
|
if (thread == NULL) {
|
||||||
pr_err("problem processing %d event, skipping it.\n",
|
pr_err("problem processing %d event, skipping it.\n",
|
||||||
@ -763,6 +764,7 @@ int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
|
|||||||
thread__put(thread);
|
thread__put(thread);
|
||||||
repipe:
|
repipe:
|
||||||
perf_event__repipe(tool, event, sample, machine);
|
perf_event__repipe(tool, event, sample, machine);
|
||||||
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +399,9 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
struct machine *machine = &kmem_session->machines.host;
|
struct machine *machine = &kmem_session->machines.host;
|
||||||
struct callchain_cursor_node *node;
|
struct callchain_cursor_node *node;
|
||||||
|
u64 result = sample->ip;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (alloc_func_list == NULL) {
|
if (alloc_func_list == NULL) {
|
||||||
if (build_alloc_func_list() < 0)
|
if (build_alloc_func_list() < 0)
|
||||||
goto out;
|
goto out;
|
||||||
@ -427,16 +429,18 @@ static u64 find_callsite(struct evsel *evsel, struct perf_sample *sample)
|
|||||||
else
|
else
|
||||||
addr = node->ip;
|
addr = node->ip;
|
||||||
|
|
||||||
return addr;
|
result = addr;
|
||||||
|
goto out;
|
||||||
} else
|
} else
|
||||||
pr_debug3("skipping alloc function: %s\n", caller->name);
|
pr_debug3("skipping alloc function: %s\n", caller->name);
|
||||||
|
|
||||||
callchain_cursor_advance(&callchain_cursor);
|
callchain_cursor_advance(&callchain_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
|
pr_debug2("unknown callsite: %"PRIx64 "\n", sample->ip);
|
||||||
return sample->ip;
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sort_dimension {
|
struct sort_dimension {
|
||||||
|
@ -739,17 +739,22 @@ static int timehist_exit_event(struct perf_kwork *kwork,
|
|||||||
struct kwork_atom *atom = NULL;
|
struct kwork_atom *atom = NULL;
|
||||||
struct kwork_work *work = NULL;
|
struct kwork_work *work = NULL;
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_debug("Problem processing event, skipping it\n");
|
pr_debug("Problem processing event, skipping it\n");
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
atom = work_pop_atom(kwork, class, KWORK_TRACE_EXIT,
|
atom = work_pop_atom(kwork, class, KWORK_TRACE_EXIT,
|
||||||
KWORK_TRACE_ENTRY, evsel, sample,
|
KWORK_TRACE_ENTRY, evsel, sample,
|
||||||
machine, &work);
|
machine, &work);
|
||||||
if (work == NULL)
|
if (work == NULL) {
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (atom != NULL) {
|
if (atom != NULL) {
|
||||||
work->nr_atoms++;
|
work->nr_atoms++;
|
||||||
@ -757,7 +762,9 @@ static int timehist_exit_event(struct perf_kwork *kwork,
|
|||||||
atom_del(atom);
|
atom_del(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kwork_class kwork_irq;
|
static struct kwork_class kwork_irq;
|
||||||
|
@ -199,9 +199,11 @@ dump_raw_samples(struct perf_tool *tool,
|
|||||||
char str[PAGE_SIZE_NAME_LEN];
|
char str[PAGE_SIZE_NAME_LEN];
|
||||||
struct dso *dso = NULL;
|
struct dso *dso = NULL;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
fprintf(stderr, "problem processing %d event, skipping it.\n",
|
fprintf(stderr, "problem processing %d event, skipping it.\n",
|
||||||
event->header.type);
|
event->header.type);
|
||||||
|
addr_location__exit(&al);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +258,7 @@ dump_raw_samples(struct perf_tool *tool,
|
|||||||
dso ? dso->long_name : "???",
|
dso ? dso->long_name : "???",
|
||||||
al.sym ? al.sym->name : "???");
|
al.sym ? al.sym->name : "???");
|
||||||
out_put:
|
out_put:
|
||||||
addr_location__put(&al);
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,10 +285,12 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
if (evswitch__discard(&rep->evswitch, evsel))
|
if (evswitch__discard(&rep->evswitch, evsel))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_debug("problem processing %d event, skipping it.\n",
|
pr_debug("problem processing %d event, skipping it.\n",
|
||||||
event->header.type);
|
event->header.type);
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep->stitch_lbr)
|
if (rep->stitch_lbr)
|
||||||
@ -331,7 +333,7 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
pr_debug("problem adding hist entry, skipping event\n");
|
pr_debug("problem adding hist entry, skipping event\n");
|
||||||
out_put:
|
out_put:
|
||||||
addr_location__put(&al);
|
addr_location__exit(&al);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2584,6 +2584,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
int state = evsel__intval(evsel, sample, "prev_state");
|
int state = evsel__intval(evsel, sample, "prev_state");
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_err("problem processing %d event. skipping it\n",
|
pr_err("problem processing %d event. skipping it\n",
|
||||||
event->header.type);
|
event->header.type);
|
||||||
@ -2692,6 +2693,7 @@ out:
|
|||||||
|
|
||||||
evsel__save_time(evsel, sample->time, sample->cpu);
|
evsel__save_time(evsel, sample->time, sample->cpu);
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,7 +919,6 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
|
|||||||
{
|
{
|
||||||
struct branch_stack *br = sample->branch_stack;
|
struct branch_stack *br = sample->branch_stack;
|
||||||
struct branch_entry *entries = perf_sample__branch_entries(sample);
|
struct branch_entry *entries = perf_sample__branch_entries(sample);
|
||||||
struct addr_location alf, alt;
|
|
||||||
u64 i, from, to;
|
u64 i, from, to;
|
||||||
int printed = 0;
|
int printed = 0;
|
||||||
|
|
||||||
@ -930,20 +929,22 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
|
|||||||
from = entries[i].from;
|
from = entries[i].from;
|
||||||
to = entries[i].to;
|
to = entries[i].to;
|
||||||
|
|
||||||
|
printed += fprintf(fp, " 0x%"PRIx64, from);
|
||||||
if (PRINT_FIELD(DSO)) {
|
if (PRINT_FIELD(DSO)) {
|
||||||
memset(&alf, 0, sizeof(alf));
|
struct addr_location alf, alt;
|
||||||
memset(&alt, 0, sizeof(alt));
|
|
||||||
|
addr_location__init(&alf);
|
||||||
|
addr_location__init(&alt);
|
||||||
thread__find_map_fb(thread, sample->cpumode, from, &alf);
|
thread__find_map_fb(thread, sample->cpumode, from, &alf);
|
||||||
thread__find_map_fb(thread, sample->cpumode, to, &alt);
|
thread__find_map_fb(thread, sample->cpumode, to, &alt);
|
||||||
}
|
|
||||||
|
|
||||||
printed += fprintf(fp, " 0x%"PRIx64, from);
|
|
||||||
if (PRINT_FIELD(DSO))
|
|
||||||
printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
|
printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
|
||||||
|
printed += fprintf(fp, "/0x%"PRIx64, to);
|
||||||
printed += fprintf(fp, "/0x%"PRIx64, to);
|
|
||||||
if (PRINT_FIELD(DSO))
|
|
||||||
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
|
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
|
||||||
|
addr_location__exit(&alt);
|
||||||
|
addr_location__exit(&alf);
|
||||||
|
} else
|
||||||
|
printed += fprintf(fp, "/0x%"PRIx64, to);
|
||||||
|
|
||||||
printed += print_bstack_flags(fp, entries + i);
|
printed += print_bstack_flags(fp, entries + i);
|
||||||
}
|
}
|
||||||
@ -957,7 +958,6 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
|
|||||||
{
|
{
|
||||||
struct branch_stack *br = sample->branch_stack;
|
struct branch_stack *br = sample->branch_stack;
|
||||||
struct branch_entry *entries = perf_sample__branch_entries(sample);
|
struct branch_entry *entries = perf_sample__branch_entries(sample);
|
||||||
struct addr_location alf, alt;
|
|
||||||
u64 i, from, to;
|
u64 i, from, to;
|
||||||
int printed = 0;
|
int printed = 0;
|
||||||
|
|
||||||
@ -965,9 +965,10 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < br->nr; i++) {
|
for (i = 0; i < br->nr; i++) {
|
||||||
|
struct addr_location alf, alt;
|
||||||
|
|
||||||
memset(&alf, 0, sizeof(alf));
|
addr_location__init(&alf);
|
||||||
memset(&alt, 0, sizeof(alt));
|
addr_location__init(&alt);
|
||||||
from = entries[i].from;
|
from = entries[i].from;
|
||||||
to = entries[i].to;
|
to = entries[i].to;
|
||||||
|
|
||||||
@ -982,6 +983,8 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
|
|||||||
if (PRINT_FIELD(DSO))
|
if (PRINT_FIELD(DSO))
|
||||||
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
|
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
|
||||||
printed += print_bstack_flags(fp, entries + i);
|
printed += print_bstack_flags(fp, entries + i);
|
||||||
|
addr_location__exit(&alt);
|
||||||
|
addr_location__exit(&alf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return printed;
|
return printed;
|
||||||
@ -993,7 +996,6 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
|
|||||||
{
|
{
|
||||||
struct branch_stack *br = sample->branch_stack;
|
struct branch_stack *br = sample->branch_stack;
|
||||||
struct branch_entry *entries = perf_sample__branch_entries(sample);
|
struct branch_entry *entries = perf_sample__branch_entries(sample);
|
||||||
struct addr_location alf, alt;
|
|
||||||
u64 i, from, to;
|
u64 i, from, to;
|
||||||
int printed = 0;
|
int printed = 0;
|
||||||
|
|
||||||
@ -1001,9 +1003,10 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < br->nr; i++) {
|
for (i = 0; i < br->nr; i++) {
|
||||||
|
struct addr_location alf, alt;
|
||||||
|
|
||||||
memset(&alf, 0, sizeof(alf));
|
addr_location__init(&alf);
|
||||||
memset(&alt, 0, sizeof(alt));
|
addr_location__init(&alt);
|
||||||
from = entries[i].from;
|
from = entries[i].from;
|
||||||
to = entries[i].to;
|
to = entries[i].to;
|
||||||
|
|
||||||
@ -1022,6 +1025,8 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
|
|||||||
if (PRINT_FIELD(DSO))
|
if (PRINT_FIELD(DSO))
|
||||||
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
|
printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
|
||||||
printed += print_bstack_flags(fp, entries + i);
|
printed += print_bstack_flags(fp, entries + i);
|
||||||
|
addr_location__exit(&alt);
|
||||||
|
addr_location__exit(&alf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return printed;
|
return printed;
|
||||||
@ -1036,6 +1041,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
bool kernel;
|
bool kernel;
|
||||||
struct dso *dso;
|
struct dso *dso;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!start || !end)
|
if (!start || !end)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1057,7 +1063,6 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
|
|||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&al, 0, sizeof(al));
|
|
||||||
if (end - start > MAXBB - MAXINSN) {
|
if (end - start > MAXBB - MAXINSN) {
|
||||||
if (last)
|
if (last)
|
||||||
pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
|
pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
|
||||||
@ -1066,13 +1071,14 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!thread__find_map(thread, *cpumode, start, &al) || (dso = map__dso(al.map)) == NULL) {
|
if (!thread__find_map(thread, *cpumode, start, &al) || (dso = map__dso(al.map)) == NULL) {
|
||||||
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
|
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
if (dso->data.status == DSO_DATA_STATUS_ERROR) {
|
if (dso->data.status == DSO_DATA_STATUS_ERROR) {
|
||||||
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
|
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load maps to ensure dso->is_64_bit has been updated */
|
/* Load maps to ensure dso->is_64_bit has been updated */
|
||||||
@ -1086,7 +1092,10 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
|
|||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
|
pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
|
||||||
start, end);
|
start, end);
|
||||||
return len;
|
ret = len;
|
||||||
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srccode_state *state)
|
static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srccode_state *state)
|
||||||
@ -1137,14 +1146,16 @@ static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr)
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
memset(&al, 0, sizeof(al));
|
addr_location__init(&al);
|
||||||
thread__find_map(thread, cpumode, addr, &al);
|
thread__find_map(thread, cpumode, addr, &al);
|
||||||
if (!al.map)
|
if (!al.map)
|
||||||
return 0;
|
goto out;
|
||||||
ret = map__fprintf_srccode(al.map, al.addr, stdout,
|
ret = map__fprintf_srccode(al.map, al.addr, stdout,
|
||||||
thread__srccode_state(thread));
|
thread__srccode_state(thread));
|
||||||
if (ret)
|
if (ret)
|
||||||
ret += printf("\n");
|
ret += printf("\n");
|
||||||
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1179,14 +1190,13 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
|
|||||||
struct perf_event_attr *attr, FILE *fp)
|
struct perf_event_attr *attr, FILE *fp)
|
||||||
{
|
{
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
int off, printed = 0;
|
int off, printed = 0, ret = 0;
|
||||||
|
|
||||||
memset(&al, 0, sizeof(al));
|
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
thread__find_map(thread, cpumode, addr, &al);
|
thread__find_map(thread, cpumode, addr, &al);
|
||||||
|
|
||||||
if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
|
if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
al.cpu = cpu;
|
al.cpu = cpu;
|
||||||
al.sym = NULL;
|
al.sym = NULL;
|
||||||
@ -1194,7 +1204,7 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
|
|||||||
al.sym = map__find_symbol(al.map, al.addr);
|
al.sym = map__find_symbol(al.map, al.addr);
|
||||||
|
|
||||||
if (!al.sym)
|
if (!al.sym)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
if (al.addr < al.sym->end)
|
if (al.addr < al.sym->end)
|
||||||
off = al.addr - al.sym->start;
|
off = al.addr - al.sym->start;
|
||||||
@ -1209,7 +1219,10 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
|
|||||||
printed += fprintf(fp, "\n");
|
printed += fprintf(fp, "\n");
|
||||||
*lastsym = al.sym;
|
*lastsym = al.sym;
|
||||||
|
|
||||||
return printed;
|
ret = printed;
|
||||||
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
|
static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
|
||||||
@ -1371,6 +1384,7 @@ static int perf_sample__fprintf_addr(struct perf_sample *sample,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
int printed = fprintf(fp, "%16" PRIx64, sample->addr);
|
int printed = fprintf(fp, "%16" PRIx64, sample->addr);
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!sample_addr_correlates_sym(attr))
|
if (!sample_addr_correlates_sym(attr))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -1387,6 +1401,7 @@ static int perf_sample__fprintf_addr(struct perf_sample *sample,
|
|||||||
if (PRINT_FIELD(DSO))
|
if (PRINT_FIELD(DSO))
|
||||||
printed += map__fprintf_dsoname_dsoff(al.map, PRINT_FIELD(DSOFF), al.addr, fp);
|
printed += map__fprintf_dsoname_dsoff(al.map, PRINT_FIELD(DSOFF), al.addr, fp);
|
||||||
out:
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
return printed;
|
return printed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2338,8 +2353,8 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Set thread to NULL to indicate addr_al and al are not initialized */
|
/* Set thread to NULL to indicate addr_al and al are not initialized */
|
||||||
addr_al.thread = NULL;
|
addr_location__init(&al);
|
||||||
al.thread = NULL;
|
addr_location__init(&addr_al);
|
||||||
|
|
||||||
ret = dlfilter__filter_event_early(dlfilter, event, sample, evsel, machine, &al, &addr_al);
|
ret = dlfilter__filter_event_early(dlfilter, event, sample, evsel, machine, &al, &addr_al);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -2405,8 +2420,8 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out_put:
|
out_put:
|
||||||
if (al.thread)
|
addr_location__exit(&addr_al);
|
||||||
addr_location__put(&al);
|
addr_location__exit(&al);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +498,6 @@ static const char *cat_backtrace(union perf_event *event,
|
|||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
size_t p_len;
|
size_t p_len;
|
||||||
u8 cpumode = PERF_RECORD_MISC_USER;
|
u8 cpumode = PERF_RECORD_MISC_USER;
|
||||||
struct addr_location tal;
|
|
||||||
struct ip_callchain *chain = sample->callchain;
|
struct ip_callchain *chain = sample->callchain;
|
||||||
FILE *f = open_memstream(&p, &p_len);
|
FILE *f = open_memstream(&p, &p_len);
|
||||||
|
|
||||||
@ -507,6 +506,7 @@ static const char *cat_backtrace(union perf_event *event,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!chain)
|
if (!chain)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
@ -518,6 +518,7 @@ static const char *cat_backtrace(union perf_event *event,
|
|||||||
|
|
||||||
for (i = 0; i < chain->nr; i++) {
|
for (i = 0; i < chain->nr; i++) {
|
||||||
u64 ip;
|
u64 ip;
|
||||||
|
struct addr_location tal;
|
||||||
|
|
||||||
if (callchain_param.order == ORDER_CALLEE)
|
if (callchain_param.order == ORDER_CALLEE)
|
||||||
ip = chain->ips[i];
|
ip = chain->ips[i];
|
||||||
@ -544,20 +545,22 @@ static const char *cat_backtrace(union perf_event *event,
|
|||||||
* Discard all.
|
* Discard all.
|
||||||
*/
|
*/
|
||||||
zfree(&p);
|
zfree(&p);
|
||||||
goto exit_put;
|
goto exit;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__init(&tal);
|
||||||
tal.filtered = 0;
|
tal.filtered = 0;
|
||||||
if (thread__find_symbol(al.thread, cpumode, ip, &tal))
|
if (thread__find_symbol(al.thread, cpumode, ip, &tal))
|
||||||
fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name);
|
fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name);
|
||||||
else
|
else
|
||||||
fprintf(f, "..... %016" PRIx64 "\n", ip);
|
fprintf(f, "..... %016" PRIx64 "\n", ip);
|
||||||
|
|
||||||
|
addr_location__exit(&tal);
|
||||||
}
|
}
|
||||||
exit_put:
|
|
||||||
addr_location__put(&al);
|
|
||||||
exit:
|
exit:
|
||||||
|
addr_location__exit(&al);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
@ -773,8 +773,9 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
|||||||
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
|
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
|
||||||
top->exact_samples++;
|
top->exact_samples++;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0)
|
if (machine__resolve(machine, &al, sample) < 0)
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
if (top->stitch_lbr)
|
if (top->stitch_lbr)
|
||||||
thread__set_lbr_stitch_enable(al.thread, true);
|
thread__set_lbr_stitch_enable(al.thread, true);
|
||||||
@ -848,7 +849,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
|||||||
mutex_unlock(&hists->lock);
|
mutex_unlock(&hists->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_location__put(&al);
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2418,13 +2418,15 @@ static int trace__resolve_callchain(struct trace *trace, struct evsel *evsel,
|
|||||||
int max_stack = evsel->core.attr.sample_max_stack ?
|
int max_stack = evsel->core.attr.sample_max_stack ?
|
||||||
evsel->core.attr.sample_max_stack :
|
evsel->core.attr.sample_max_stack :
|
||||||
trace->max_stack;
|
trace->max_stack;
|
||||||
int err;
|
int err = -1;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(trace->host, &al, sample) < 0)
|
if (machine__resolve(trace->host, &al, sample) < 0)
|
||||||
return -1;
|
goto out;
|
||||||
|
|
||||||
err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack);
|
err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack);
|
||||||
addr_location__put(&al);
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2893,6 +2895,7 @@ static int trace__pgfault(struct trace *trace,
|
|||||||
int err = -1;
|
int err = -1;
|
||||||
int callchain_ret = 0;
|
int callchain_ret = 0;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
|
||||||
|
|
||||||
if (sample->callchain) {
|
if (sample->callchain) {
|
||||||
@ -2953,6 +2956,7 @@ out:
|
|||||||
err = 0;
|
err = 0;
|
||||||
out_put:
|
out_put:
|
||||||
thread__put(thread);
|
thread__put(thread);
|
||||||
|
addr_location__exit(&al);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +241,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
|
|||||||
|
|
||||||
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
|
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) {
|
if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) {
|
||||||
if (cpumode == PERF_RECORD_MISC_HYPERVISOR) {
|
if (cpumode == PERF_RECORD_MISC_HYPERVISOR) {
|
||||||
pr_debug("Hypervisor address can not be resolved - skipping\n");
|
pr_debug("Hypervisor address can not be resolved - skipping\n");
|
||||||
@ -366,7 +367,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
|
|||||||
}
|
}
|
||||||
pr_debug("Bytes read match those read by objdump\n");
|
pr_debug("Bytes read match those read by objdump\n");
|
||||||
out:
|
out:
|
||||||
map__put(al.map);
|
addr_location__exit(&al);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#include "util/evsel.h"
|
#include "util/evsel.h"
|
||||||
#include "util/evlist.h"
|
#include "util/evlist.h"
|
||||||
#include "util/machine.h"
|
#include "util/machine.h"
|
||||||
#include "util/thread.h"
|
|
||||||
#include "util/parse-events.h"
|
#include "util/parse-events.h"
|
||||||
|
#include "util/thread.h"
|
||||||
#include "tests/tests.h"
|
#include "tests/tests.h"
|
||||||
#include "tests/hists_common.h"
|
#include "tests/hists_common.h"
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@ -84,6 +84,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
|
|||||||
struct perf_sample sample = { .period = 1000, };
|
struct perf_sample sample = { .period = 1000, };
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
|
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
|
||||||
struct hist_entry_iter iter = {
|
struct hist_entry_iter iter = {
|
||||||
.evsel = evsel,
|
.evsel = evsel,
|
||||||
@ -107,20 +108,22 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
|
|||||||
|
|
||||||
if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
|
if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
|
||||||
NULL) < 0) {
|
NULL) < 0) {
|
||||||
addr_location__put(&al);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fake_samples[i].thread = al.thread;
|
thread__put(fake_samples[i].thread);
|
||||||
|
fake_samples[i].thread = thread__get(al.thread);
|
||||||
map__put(fake_samples[i].map);
|
map__put(fake_samples[i].map);
|
||||||
fake_samples[i].map = al.map;
|
fake_samples[i].map = map__get(al.map);
|
||||||
fake_samples[i].sym = al.sym;
|
fake_samples[i].sym = al.sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
return TEST_OK;
|
return TEST_OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
pr_debug("Not enough memory for adding a hist entry\n");
|
pr_debug("Not enough memory for adding a hist entry\n");
|
||||||
|
addr_location__exit(&al);
|
||||||
return TEST_FAIL;
|
return TEST_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +155,10 @@ static void put_fake_samples(void)
|
|||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fake_samples); i++)
|
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
|
||||||
map__put(fake_samples[i].map);
|
map__zput(fake_samples[i].map);
|
||||||
|
thread__zput(fake_samples[i].thread);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef int (*test_fn_t)(struct evsel *, struct machine *);
|
typedef int (*test_fn_t)(struct evsel *, struct machine *);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "util/evlist.h"
|
#include "util/evlist.h"
|
||||||
#include "util/machine.h"
|
#include "util/machine.h"
|
||||||
#include "util/parse-events.h"
|
#include "util/parse-events.h"
|
||||||
|
#include "util/thread.h"
|
||||||
#include "tests/tests.h"
|
#include "tests/tests.h"
|
||||||
#include "tests/hists_common.h"
|
#include "tests/hists_common.h"
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@ -53,6 +54,7 @@ static int add_hist_entries(struct evlist *evlist,
|
|||||||
struct perf_sample sample = { .period = 100, };
|
struct perf_sample sample = { .period = 100, };
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
/*
|
/*
|
||||||
* each evsel will have 10 samples but the 4th sample
|
* each evsel will have 10 samples but the 4th sample
|
||||||
* (perf [perf] main) will be collapsed to an existing entry
|
* (perf [perf] main) will be collapsed to an existing entry
|
||||||
@ -84,21 +86,22 @@ static int add_hist_entries(struct evlist *evlist,
|
|||||||
al.socket = fake_samples[i].socket;
|
al.socket = fake_samples[i].socket;
|
||||||
if (hist_entry_iter__add(&iter, &al,
|
if (hist_entry_iter__add(&iter, &al,
|
||||||
sysctl_perf_event_max_stack, NULL) < 0) {
|
sysctl_perf_event_max_stack, NULL) < 0) {
|
||||||
addr_location__put(&al);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fake_samples[i].thread = al.thread;
|
thread__put(fake_samples[i].thread);
|
||||||
|
fake_samples[i].thread = thread__get(al.thread);
|
||||||
map__put(fake_samples[i].map);
|
map__put(fake_samples[i].map);
|
||||||
fake_samples[i].map = al.map;
|
fake_samples[i].map = map__get(al.map);
|
||||||
fake_samples[i].sym = al.sym;
|
fake_samples[i].sym = al.sym;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
pr_debug("Not enough memory for adding a hist entry\n");
|
pr_debug("Not enough memory for adding a hist entry\n");
|
||||||
|
addr_location__exit(&al);
|
||||||
return TEST_FAIL;
|
return TEST_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
|
#include "thread.h"
|
||||||
#include "hists_common.h"
|
#include "hists_common.h"
|
||||||
#include "util/mmap.h"
|
#include "util/mmap.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -70,6 +71,7 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
|
|||||||
struct perf_sample sample = { .period = 1, .weight = 1, };
|
struct perf_sample sample = { .period = 1, .weight = 1, };
|
||||||
size_t i = 0, k;
|
size_t i = 0, k;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
/*
|
/*
|
||||||
* each evsel will have 10 samples - 5 common and 5 distinct.
|
* each evsel will have 10 samples - 5 common and 5 distinct.
|
||||||
* However the second evsel also has a collapsed entry for
|
* However the second evsel also has a collapsed entry for
|
||||||
@ -90,13 +92,13 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
|
|||||||
he = hists__add_entry(hists, &al, NULL,
|
he = hists__add_entry(hists, &al, NULL,
|
||||||
NULL, NULL, NULL, &sample, true);
|
NULL, NULL, NULL, &sample, true);
|
||||||
if (he == NULL) {
|
if (he == NULL) {
|
||||||
addr_location__put(&al);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fake_common_samples[k].thread = al.thread;
|
thread__put(fake_common_samples[k].thread);
|
||||||
|
fake_common_samples[k].thread = thread__get(al.thread);
|
||||||
map__put(fake_common_samples[k].map);
|
map__put(fake_common_samples[k].map);
|
||||||
fake_common_samples[k].map = al.map;
|
fake_common_samples[k].map = map__get(al.map);
|
||||||
fake_common_samples[k].sym = al.sym;
|
fake_common_samples[k].sym = al.sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,20 +112,22 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
|
|||||||
he = hists__add_entry(hists, &al, NULL,
|
he = hists__add_entry(hists, &al, NULL,
|
||||||
NULL, NULL, NULL, &sample, true);
|
NULL, NULL, NULL, &sample, true);
|
||||||
if (he == NULL) {
|
if (he == NULL) {
|
||||||
addr_location__put(&al);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fake_samples[i][k].thread = al.thread;
|
thread__put(fake_samples[i][k].thread);
|
||||||
fake_samples[i][k].map = al.map;
|
fake_samples[i][k].thread = thread__get(al.thread);
|
||||||
|
map__put(fake_samples[i][k].map);
|
||||||
|
fake_samples[i][k].map = map__get(al.map);
|
||||||
fake_samples[i][k].sym = al.sym;
|
fake_samples[i][k].sym = al.sym;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
pr_debug("Not enough memory for adding a hist entry\n");
|
pr_debug("Not enough memory for adding a hist entry\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
|
|||||||
struct perf_sample sample = { .period = 100, };
|
struct perf_sample sample = { .period = 100, };
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
|
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
|
||||||
struct hist_entry_iter iter = {
|
struct hist_entry_iter iter = {
|
||||||
.evsel = evsel,
|
.evsel = evsel,
|
||||||
@ -73,20 +74,21 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
|
|||||||
|
|
||||||
if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
|
if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
|
||||||
NULL) < 0) {
|
NULL) < 0) {
|
||||||
addr_location__put(&al);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fake_samples[i].thread = al.thread;
|
fake_samples[i].thread = al.thread;
|
||||||
map__put(fake_samples[i].map);
|
map__put(fake_samples[i].map);
|
||||||
fake_samples[i].map = al.map;
|
fake_samples[i].map = map__get(al.map);
|
||||||
fake_samples[i].sym = al.sym;
|
fake_samples[i].sym = al.sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
return TEST_OK;
|
return TEST_OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
pr_debug("Not enough memory for adding a hist entry\n");
|
pr_debug("Not enough memory for adding a hist entry\n");
|
||||||
|
addr_location__exit(&al);
|
||||||
return TEST_FAIL;
|
return TEST_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +120,10 @@ static void put_fake_samples(void)
|
|||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fake_samples); i++)
|
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
|
||||||
map__put(fake_samples[i].map);
|
map__put(fake_samples[i].map);
|
||||||
|
fake_samples[i].map = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef int (*test_fn_t)(struct evsel *, struct machine *);
|
typedef int (*test_fn_t)(struct evsel *, struct machine *);
|
||||||
|
@ -187,6 +187,7 @@ static int mmap_events(synth_cb synth)
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
thread = machine__findnew_thread(machine, getpid(), td->tid);
|
thread = machine__findnew_thread(machine, getpid(), td->tid);
|
||||||
|
|
||||||
pr_debug("looking for map %p\n", td->map);
|
pr_debug("looking for map %p\n", td->map);
|
||||||
@ -199,11 +200,12 @@ static int mmap_events(synth_cb synth)
|
|||||||
if (!al.map) {
|
if (!al.map) {
|
||||||
pr_debug("failed, couldn't find map\n");
|
pr_debug("failed, couldn't find map\n");
|
||||||
err = -1;
|
err = -1;
|
||||||
|
addr_location__exit(&al);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("map %p, addr %" PRIx64 "\n", al.map, map__start(al.map));
|
pr_debug("map %p, addr %" PRIx64 "\n", al.map, map__start(al.map));
|
||||||
map__put(al.map);
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
|
|
||||||
machine__delete_threads(machine);
|
machine__delete_threads(machine);
|
||||||
|
@ -1,16 +1,44 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include "addr_location.h"
|
#include "addr_location.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
#include "maps.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
|
void addr_location__init(struct addr_location *al)
|
||||||
|
{
|
||||||
|
al->thread = NULL;
|
||||||
|
al->maps = NULL;
|
||||||
|
al->map = NULL;
|
||||||
|
al->sym = NULL;
|
||||||
|
al->srcline = NULL;
|
||||||
|
al->addr = 0;
|
||||||
|
al->level = 0;
|
||||||
|
al->filtered = 0;
|
||||||
|
al->cpumode = 0;
|
||||||
|
al->cpu = 0;
|
||||||
|
al->socket = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The preprocess_sample method will return with reference counts for the
|
* The preprocess_sample method will return with reference counts for the
|
||||||
* in it, when done using (and perhaps getting ref counts if needing to
|
* in it, when done using (and perhaps getting ref counts if needing to
|
||||||
* keep a pointer to one of those entries) it must be paired with
|
* keep a pointer to one of those entries) it must be paired with
|
||||||
* addr_location__put(), so that the refcounts can be decremented.
|
* addr_location__put(), so that the refcounts can be decremented.
|
||||||
*/
|
*/
|
||||||
void addr_location__put(struct addr_location *al)
|
void addr_location__exit(struct addr_location *al)
|
||||||
{
|
{
|
||||||
map__zput(al->map);
|
map__zput(al->map);
|
||||||
thread__zput(al->thread);
|
thread__zput(al->thread);
|
||||||
|
maps__zput(al->maps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addr_location__copy(struct addr_location *dst, struct addr_location *src)
|
||||||
|
{
|
||||||
|
thread__put(dst->thread);
|
||||||
|
maps__put(dst->maps);
|
||||||
|
map__put(dst->map);
|
||||||
|
*dst = *src;
|
||||||
|
dst->thread = thread__get(src->thread);
|
||||||
|
dst->maps = maps__get(src->maps);
|
||||||
|
dst->map = map__get(src->map);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,9 @@ struct addr_location {
|
|||||||
s32 socket;
|
s32 socket;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addr_location__put(struct addr_location *al);
|
void addr_location__init(struct addr_location *al);
|
||||||
|
void addr_location__exit(struct addr_location *al);
|
||||||
|
|
||||||
|
void addr_location__copy(struct addr_location *dst, struct addr_location *src);
|
||||||
|
|
||||||
#endif /* __PERF_ADDR_LOCATION */
|
#endif /* __PERF_ADDR_LOCATION */
|
||||||
|
@ -58,9 +58,11 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (thread__find_map(thread, sample->cpumode, sample->ip, &al))
|
if (thread__find_map(thread, sample->cpumode, sample->ip, &al))
|
||||||
map__dso(al.map)->hit = 1;
|
map__dso(al.map)->hit = 1;
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
thread__put(thread);
|
thread__put(thread);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -910,33 +910,35 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
struct dso *dso;
|
struct dso *dso;
|
||||||
struct cs_etm_traceid_queue *tidq;
|
struct cs_etm_traceid_queue *tidq;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!etmq)
|
if (!etmq)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
machine = etmq->etm->machine;
|
machine = etmq->etm->machine;
|
||||||
cpumode = cs_etm__cpu_mode(etmq, address);
|
cpumode = cs_etm__cpu_mode(etmq, address);
|
||||||
tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
|
tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
|
||||||
if (!tidq)
|
if (!tidq)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
thread = tidq->thread;
|
thread = tidq->thread;
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
if (cpumode != PERF_RECORD_MISC_KERNEL)
|
if (cpumode != PERF_RECORD_MISC_KERNEL)
|
||||||
return 0;
|
goto out;
|
||||||
thread = etmq->etm->unknown_thread;
|
thread = etmq->etm->unknown_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!thread__find_map(thread, cpumode, address, &al))
|
if (!thread__find_map(thread, cpumode, address, &al))
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
dso = map__dso(al.map);
|
dso = map__dso(al.map);
|
||||||
if (!dso)
|
if (!dso)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
if (dso->data.status == DSO_DATA_STATUS_ERROR &&
|
if (dso->data.status == DSO_DATA_STATUS_ERROR &&
|
||||||
dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE))
|
dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE))
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
offset = map__map_ip(al.map, address);
|
offset = map__map_ip(al.map, address);
|
||||||
|
|
||||||
@ -953,10 +955,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
|
|||||||
dso->long_name ? dso->long_name : "Unknown");
|
dso->long_name ? dso->long_name : "Unknown");
|
||||||
dso->auxtrace_warned = true;
|
dso->auxtrace_warned = true;
|
||||||
}
|
}
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
ret = len;
|
||||||
return len;
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
|
static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
|
||||||
|
@ -154,12 +154,14 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
{
|
{
|
||||||
struct convert_json *c = container_of(tool, struct convert_json, tool);
|
struct convert_json *c = container_of(tool, struct convert_json, tool);
|
||||||
FILE *out = c->out;
|
FILE *out = c->out;
|
||||||
struct addr_location al, tal;
|
struct addr_location al;
|
||||||
u64 sample_type = __evlist__combined_sample_type(evsel->evlist);
|
u64 sample_type = __evlist__combined_sample_type(evsel->evlist);
|
||||||
u8 cpumode = PERF_RECORD_MISC_USER;
|
u8 cpumode = PERF_RECORD_MISC_USER;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (machine__resolve(machine, &al, sample) < 0) {
|
if (machine__resolve(machine, &al, sample) < 0) {
|
||||||
pr_err("Sample resolution failed!\n");
|
pr_err("Sample resolution failed!\n");
|
||||||
|
addr_location__exit(&al);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +192,7 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
|
|
||||||
for (i = 0; i < sample->callchain->nr; ++i) {
|
for (i = 0; i < sample->callchain->nr; ++i) {
|
||||||
u64 ip = sample->callchain->ips[i];
|
u64 ip = sample->callchain->ips[i];
|
||||||
|
struct addr_location tal;
|
||||||
|
|
||||||
if (ip >= PERF_CONTEXT_MAX) {
|
if (ip >= PERF_CONTEXT_MAX) {
|
||||||
switch (ip) {
|
switch (ip) {
|
||||||
@ -215,8 +218,10 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
else
|
else
|
||||||
fputc(',', out);
|
fputc(',', out);
|
||||||
|
|
||||||
|
addr_location__init(&tal);
|
||||||
ok = thread__find_symbol(al.thread, cpumode, ip, &tal);
|
ok = thread__find_symbol(al.thread, cpumode, ip, &tal);
|
||||||
output_sample_callchain_entry(tool, ip, ok ? &tal : NULL);
|
output_sample_callchain_entry(tool, ip, ok ? &tal : NULL);
|
||||||
|
addr_location__exit(&tal);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
output_sample_callchain_entry(tool, sample->ip, &al);
|
output_sample_callchain_entry(tool, sample->ip, &al);
|
||||||
@ -245,6 +250,7 @@ static int process_sample_event(struct perf_tool *tool,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
output_json_format(out, false, 2, "}");
|
output_json_format(out, false, 2, "}");
|
||||||
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,16 +239,17 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
|
u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
|
||||||
|
|
||||||
memset(&al, 0, sizeof(al));
|
|
||||||
|
|
||||||
node = callchain_cursor_current(&callchain_cursor);
|
node = callchain_cursor_current(&callchain_cursor);
|
||||||
if (!node)
|
if (!node)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle export of symbol and dso for this node by
|
* Handle export of symbol and dso for this node by
|
||||||
* constructing an addr_location struct and then passing it to
|
* constructing an addr_location struct and then passing it to
|
||||||
* db_ids_from_al() to perform the export.
|
* db_ids_from_al() to perform the export.
|
||||||
*/
|
*/
|
||||||
|
addr_location__init(&al);
|
||||||
al.sym = node->ms.sym;
|
al.sym = node->ms.sym;
|
||||||
al.map = node->ms.map;
|
al.map = node->ms.map;
|
||||||
al.maps = thread__maps(thread);
|
al.maps = thread__maps(thread);
|
||||||
@ -265,6 +266,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
|||||||
kernel_start);
|
kernel_start);
|
||||||
|
|
||||||
callchain_cursor_advance(&callchain_cursor);
|
callchain_cursor_advance(&callchain_cursor);
|
||||||
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the callchain order to its prior value. */
|
/* Reset the callchain order to its prior value. */
|
||||||
|
@ -258,6 +258,7 @@ static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len)
|
|||||||
struct addr_location a;
|
struct addr_location a;
|
||||||
struct map *map;
|
struct map *map;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
|
__s32 ret;
|
||||||
|
|
||||||
if (!d->ctx_valid)
|
if (!d->ctx_valid)
|
||||||
return -1;
|
return -1;
|
||||||
@ -272,16 +273,22 @@ static __s32 dlfilter__object_code(void *ctx, __u64 ip, void *buf, __u32 len)
|
|||||||
machine__kernel_ip(d->machine, ip) == machine__kernel_ip(d->machine, d->sample->ip))
|
machine__kernel_ip(d->machine, ip) == machine__kernel_ip(d->machine, d->sample->ip))
|
||||||
goto have_map;
|
goto have_map;
|
||||||
|
|
||||||
|
addr_location__init(&a);
|
||||||
thread__find_map_fb(al->thread, d->sample->cpumode, ip, &a);
|
thread__find_map_fb(al->thread, d->sample->cpumode, ip, &a);
|
||||||
if (!a.map)
|
if (!a.map) {
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
map = a.map;
|
map = a.map;
|
||||||
have_map:
|
have_map:
|
||||||
offset = map__map_ip(map, ip);
|
offset = map__map_ip(map, ip);
|
||||||
if (ip + len >= map__end(map))
|
if (ip + len >= map__end(map))
|
||||||
len = map__end(map) - ip;
|
len = map__end(map) - ip;
|
||||||
return dso__data_read_offset(map__dso(map), d->machine, offset, buf, len);
|
ret = dso__data_read_offset(map__dso(map), d->machine, offset, buf, len);
|
||||||
|
out:
|
||||||
|
addr_location__exit(&a);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct perf_dlfilter_fns perf_dlfilter_fns = {
|
static const struct perf_dlfilter_fns perf_dlfilter_fns = {
|
||||||
|
@ -486,6 +486,7 @@ size_t perf_event__fprintf_text_poke(union perf_event *event, struct machine *ma
|
|||||||
if (machine) {
|
if (machine) {
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
al.map = map__get(maps__find(machine__kernel_maps(machine), tp->addr));
|
al.map = map__get(maps__find(machine__kernel_maps(machine), tp->addr));
|
||||||
if (al.map && map__load(al.map) >= 0) {
|
if (al.map && map__load(al.map) >= 0) {
|
||||||
al.addr = map__map_ip(al.map, tp->addr);
|
al.addr = map__map_ip(al.map, tp->addr);
|
||||||
@ -493,7 +494,7 @@ size_t perf_event__fprintf_text_poke(union perf_event *event, struct machine *ma
|
|||||||
if (al.sym)
|
if (al.sym)
|
||||||
ret += symbol__fprintf_symname_offs(al.sym, &al, fp);
|
ret += symbol__fprintf_symname_offs(al.sym, &al, fp);
|
||||||
}
|
}
|
||||||
map__put(al.map);
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
ret += fprintf(fp, " old len %u new len %u\n", tp->old_len, tp->new_len);
|
ret += fprintf(fp, " old len %u new len %u\n", tp->old_len, tp->new_len);
|
||||||
old = true;
|
old = true;
|
||||||
@ -577,8 +578,10 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
|
|||||||
struct machine *machine = maps__machine(maps);
|
struct machine *machine = maps__machine(maps);
|
||||||
bool load_map = false;
|
bool load_map = false;
|
||||||
|
|
||||||
al->maps = maps;
|
maps__zput(al->maps);
|
||||||
al->thread = thread;
|
map__zput(al->map);
|
||||||
|
thread__zput(al->thread);
|
||||||
|
|
||||||
al->addr = addr;
|
al->addr = addr;
|
||||||
al->cpumode = cpumode;
|
al->cpumode = cpumode;
|
||||||
al->filtered = 0;
|
al->filtered = 0;
|
||||||
@ -590,13 +593,13 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
|
|||||||
|
|
||||||
if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
|
if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
|
||||||
al->level = 'k';
|
al->level = 'k';
|
||||||
al->maps = maps = machine__kernel_maps(machine);
|
maps = machine__kernel_maps(machine);
|
||||||
load_map = true;
|
load_map = true;
|
||||||
} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
|
} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
|
||||||
al->level = '.';
|
al->level = '.';
|
||||||
} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
|
} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
|
||||||
al->level = 'g';
|
al->level = 'g';
|
||||||
al->maps = maps = machine__kernel_maps(machine);
|
maps = machine__kernel_maps(machine);
|
||||||
load_map = true;
|
load_map = true;
|
||||||
} else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
|
} else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
|
||||||
al->level = 'u';
|
al->level = 'u';
|
||||||
@ -615,7 +618,8 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
al->maps = maps__get(maps);
|
||||||
|
al->thread = thread__get(thread);
|
||||||
al->map = map__get(maps__find(maps, al->addr));
|
al->map = map__get(maps__find(maps, al->addr));
|
||||||
if (al->map != NULL) {
|
if (al->map != NULL) {
|
||||||
/*
|
/*
|
||||||
|
@ -128,8 +128,6 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
|
|||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
if (sample->callchain) {
|
if (sample->callchain) {
|
||||||
struct addr_location node_al;
|
|
||||||
|
|
||||||
callchain_cursor_commit(cursor);
|
callchain_cursor_commit(cursor);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -159,9 +157,12 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
|
|||||||
printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
|
printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
|
||||||
|
|
||||||
if (print_sym) {
|
if (print_sym) {
|
||||||
|
struct addr_location node_al;
|
||||||
|
|
||||||
|
addr_location__init(&node_al);
|
||||||
printed += fprintf(fp, " ");
|
printed += fprintf(fp, " ");
|
||||||
node_al.addr = addr;
|
node_al.addr = addr;
|
||||||
node_al.map = map;
|
node_al.map = map__get(map);
|
||||||
|
|
||||||
if (print_symoffset) {
|
if (print_symoffset) {
|
||||||
printed += __symbol__fprintf_symname_offs(sym, &node_al,
|
printed += __symbol__fprintf_symname_offs(sym, &node_al,
|
||||||
@ -171,6 +172,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
|
|||||||
printed += __symbol__fprintf_symname(sym, &node_al,
|
printed += __symbol__fprintf_symname(sym, &node_al,
|
||||||
print_unknown_as_addr, fp);
|
print_unknown_as_addr, fp);
|
||||||
}
|
}
|
||||||
|
addr_location__exit(&node_al);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print_dso && (!sym || !sym->inlined))
|
if (print_dso && (!sym || !sym->inlined))
|
||||||
|
@ -588,7 +588,7 @@ static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
|
|||||||
|
|
||||||
static struct hist_entry *hists__findnew_entry(struct hists *hists,
|
static struct hist_entry *hists__findnew_entry(struct hists *hists,
|
||||||
struct hist_entry *entry,
|
struct hist_entry *entry,
|
||||||
struct addr_location *al,
|
const struct addr_location *al,
|
||||||
bool sample_self)
|
bool sample_self)
|
||||||
{
|
{
|
||||||
struct rb_node **p;
|
struct rb_node **p;
|
||||||
@ -927,8 +927,10 @@ iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
|
|||||||
if (iter->curr >= iter->total)
|
if (iter->curr >= iter->total)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
al->maps = bi[i].to.ms.maps;
|
maps__put(al->maps);
|
||||||
al->map = bi[i].to.ms.map;
|
al->maps = maps__get(bi[i].to.ms.maps);
|
||||||
|
map__put(al->map);
|
||||||
|
al->map = map__get(bi[i].to.ms.map);
|
||||||
al->sym = bi[i].to.ms.sym;
|
al->sym = bi[i].to.ms.sym;
|
||||||
al->addr = bi[i].to.addr;
|
al->addr = bi[i].to.addr;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -754,13 +754,15 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
unsigned char buf[INTEL_PT_INSN_BUF_SZ];
|
unsigned char buf[INTEL_PT_INSN_BUF_SZ];
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
int x86_64;
|
int x86_64, ret = 0;
|
||||||
u8 cpumode;
|
u8 cpumode;
|
||||||
u64 offset, start_offset, start_ip;
|
u64 offset, start_offset, start_ip;
|
||||||
u64 insn_cnt = 0;
|
u64 insn_cnt = 0;
|
||||||
bool one_map = true;
|
bool one_map = true;
|
||||||
bool nr;
|
bool nr;
|
||||||
|
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
intel_pt_insn->length = 0;
|
intel_pt_insn->length = 0;
|
||||||
|
|
||||||
if (to_ip && *ip == to_ip)
|
if (to_ip && *ip == to_ip)
|
||||||
@ -773,19 +775,22 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
|||||||
if (ptq->pt->have_guest_sideband) {
|
if (ptq->pt->have_guest_sideband) {
|
||||||
if (!ptq->guest_machine || ptq->guest_machine_pid != ptq->pid) {
|
if (!ptq->guest_machine || ptq->guest_machine_pid != ptq->pid) {
|
||||||
intel_pt_log("ERROR: guest sideband but no guest machine\n");
|
intel_pt_log("ERROR: guest sideband but no guest machine\n");
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
} else if ((!symbol_conf.guest_code && cpumode != PERF_RECORD_MISC_GUEST_KERNEL) ||
|
} else if ((!symbol_conf.guest_code && cpumode != PERF_RECORD_MISC_GUEST_KERNEL) ||
|
||||||
intel_pt_get_guest(ptq)) {
|
intel_pt_get_guest(ptq)) {
|
||||||
intel_pt_log("ERROR: no guest machine\n");
|
intel_pt_log("ERROR: no guest machine\n");
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
machine = ptq->guest_machine;
|
machine = ptq->guest_machine;
|
||||||
thread = ptq->guest_thread;
|
thread = ptq->guest_thread;
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
if (cpumode != PERF_RECORD_MISC_GUEST_KERNEL) {
|
if (cpumode != PERF_RECORD_MISC_GUEST_KERNEL) {
|
||||||
intel_pt_log("ERROR: no guest thread\n");
|
intel_pt_log("ERROR: no guest thread\n");
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
thread = ptq->unknown_guest_thread;
|
thread = ptq->unknown_guest_thread;
|
||||||
}
|
}
|
||||||
@ -794,7 +799,8 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
|||||||
if (!thread) {
|
if (!thread) {
|
||||||
if (cpumode != PERF_RECORD_MISC_KERNEL) {
|
if (cpumode != PERF_RECORD_MISC_KERNEL) {
|
||||||
intel_pt_log("ERROR: no thread\n");
|
intel_pt_log("ERROR: no thread\n");
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
thread = ptq->pt->unknown_thread;
|
thread = ptq->pt->unknown_thread;
|
||||||
}
|
}
|
||||||
@ -808,13 +814,17 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
|||||||
intel_pt_log("ERROR: thread has no dso for %#" PRIx64 "\n", *ip);
|
intel_pt_log("ERROR: thread has no dso for %#" PRIx64 "\n", *ip);
|
||||||
else
|
else
|
||||||
intel_pt_log("ERROR: thread has no map for %#" PRIx64 "\n", *ip);
|
intel_pt_log("ERROR: thread has no map for %#" PRIx64 "\n", *ip);
|
||||||
return -EINVAL;
|
addr_location__exit(&al);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
dso = map__dso(al.map);
|
dso = map__dso(al.map);
|
||||||
|
|
||||||
if (dso->data.status == DSO_DATA_STATUS_ERROR &&
|
if (dso->data.status == DSO_DATA_STATUS_ERROR &&
|
||||||
dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE))
|
dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE)) {
|
||||||
return -ENOENT;
|
ret = -ENOENT;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
|
||||||
offset = map__map_ip(al.map, *ip);
|
offset = map__map_ip(al.map, *ip);
|
||||||
|
|
||||||
@ -833,7 +843,8 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
|||||||
intel_pt_insn->rel = e->rel;
|
intel_pt_insn->rel = e->rel;
|
||||||
memcpy(intel_pt_insn->buf, e->insn, INTEL_PT_INSN_BUF_SZ);
|
memcpy(intel_pt_insn->buf, e->insn, INTEL_PT_INSN_BUF_SZ);
|
||||||
intel_pt_log_insn_no_data(intel_pt_insn, *ip);
|
intel_pt_log_insn_no_data(intel_pt_insn, *ip);
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -854,11 +865,14 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
|||||||
offset);
|
offset);
|
||||||
if (intel_pt_enable_logging)
|
if (intel_pt_enable_logging)
|
||||||
dso__fprintf(dso, intel_pt_log_fp());
|
dso__fprintf(dso, intel_pt_log_fp());
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intel_pt_get_insn(buf, len, x86_64, intel_pt_insn))
|
if (intel_pt_get_insn(buf, len, x86_64, intel_pt_insn)) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_ret;
|
||||||
|
}
|
||||||
|
|
||||||
intel_pt_log_insn(intel_pt_insn, *ip);
|
intel_pt_log_insn(intel_pt_insn, *ip);
|
||||||
|
|
||||||
@ -909,17 +923,20 @@ out:
|
|||||||
|
|
||||||
e = intel_pt_cache_lookup(map__dso(al.map), machine, start_offset);
|
e = intel_pt_cache_lookup(map__dso(al.map), machine, start_offset);
|
||||||
if (e)
|
if (e)
|
||||||
return 0;
|
goto out_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore cache errors */
|
/* Ignore cache errors */
|
||||||
intel_pt_cache_add(map__dso(al.map), machine, start_offset, insn_cnt,
|
intel_pt_cache_add(map__dso(al.map), machine, start_offset, insn_cnt,
|
||||||
*ip - start_ip, intel_pt_insn);
|
*ip - start_ip, intel_pt_insn);
|
||||||
|
|
||||||
return 0;
|
out_ret:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
|
|
||||||
out_no_cache:
|
out_no_cache:
|
||||||
*insn_cnt_ptr = insn_cnt;
|
*insn_cnt_ptr = insn_cnt;
|
||||||
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -968,6 +985,7 @@ static int __intel_pt_pgd_ip(uint64_t ip, void *data)
|
|||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
u8 cpumode;
|
u8 cpumode;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (ptq->state->to_nr) {
|
if (ptq->state->to_nr) {
|
||||||
if (intel_pt_guest_kernel_ip(ip))
|
if (intel_pt_guest_kernel_ip(ip))
|
||||||
@ -984,12 +1002,15 @@ static int __intel_pt_pgd_ip(uint64_t ip, void *data)
|
|||||||
if (!thread)
|
if (!thread)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!thread__find_map(thread, cpumode, ip, &al) || !map__dso(al.map))
|
if (!thread__find_map(thread, cpumode, ip, &al) || !map__dso(al.map))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
offset = map__map_ip(al.map, ip);
|
offset = map__map_ip(al.map, ip);
|
||||||
|
|
||||||
return intel_pt_match_pgd_ip(ptq->pt, ip, offset, map__dso(al.map)->long_name);
|
res = intel_pt_match_pgd_ip(ptq->pt, ip, offset, map__dso(al.map)->long_name);
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool intel_pt_pgd_ip(uint64_t ip, void *data)
|
static bool intel_pt_pgd_ip(uint64_t ip, void *data)
|
||||||
@ -3372,20 +3393,22 @@ static int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event)
|
|||||||
/* Assume text poke begins in a basic block no more than 4096 bytes */
|
/* Assume text poke begins in a basic block no more than 4096 bytes */
|
||||||
int cnt = 4096 + event->text_poke.new_len;
|
int cnt = 4096 + event->text_poke.new_len;
|
||||||
struct thread *thread = pt->unknown_thread;
|
struct thread *thread = pt->unknown_thread;
|
||||||
struct addr_location al = { .map = NULL };
|
struct addr_location al;
|
||||||
struct machine *machine = pt->machine;
|
struct machine *machine = pt->machine;
|
||||||
struct intel_pt_cache_entry *e;
|
struct intel_pt_cache_entry *e;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!event->text_poke.new_len)
|
if (!event->text_poke.new_len)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
for (; cnt; cnt--, addr--) {
|
for (; cnt; cnt--, addr--) {
|
||||||
struct dso *dso;
|
struct dso *dso;
|
||||||
|
|
||||||
if (intel_pt_find_map(thread, cpumode, addr, &al)) {
|
if (intel_pt_find_map(thread, cpumode, addr, &al)) {
|
||||||
if (addr < event->text_poke.addr)
|
if (addr < event->text_poke.addr)
|
||||||
return 0;
|
goto out;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3406,15 +3429,16 @@ static int intel_pt_text_poke(struct intel_pt *pt, union perf_event *event)
|
|||||||
* branch instruction before the text poke address.
|
* branch instruction before the text poke address.
|
||||||
*/
|
*/
|
||||||
if (e->branch != INTEL_PT_BR_NO_BRANCH)
|
if (e->branch != INTEL_PT_BR_NO_BRANCH)
|
||||||
return 0;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
intel_pt_cache_invalidate(dso, machine, offset);
|
intel_pt_cache_invalidate(dso, machine, offset);
|
||||||
intel_pt_log("Invalidated instruction cache for %s at %#"PRIx64"\n",
|
intel_pt_log("Invalidated instruction cache for %s at %#"PRIx64"\n",
|
||||||
dso->long_name, addr);
|
dso->long_name, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
return 0;
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intel_pt_process_event(struct perf_session *session,
|
static int intel_pt_process_event(struct perf_session *session,
|
||||||
|
@ -2221,7 +2221,7 @@ static void ip__resolve_ams(struct thread *thread,
|
|||||||
{
|
{
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
|
||||||
memset(&al, 0, sizeof(al));
|
addr_location__init(&al);
|
||||||
/*
|
/*
|
||||||
* We cannot use the header.misc hint to determine whether a
|
* We cannot use the header.misc hint to determine whether a
|
||||||
* branch stack address is user, kernel, guest, hypervisor.
|
* branch stack address is user, kernel, guest, hypervisor.
|
||||||
@ -2234,11 +2234,12 @@ static void ip__resolve_ams(struct thread *thread,
|
|||||||
ams->addr = ip;
|
ams->addr = ip;
|
||||||
ams->al_addr = al.addr;
|
ams->al_addr = al.addr;
|
||||||
ams->al_level = al.level;
|
ams->al_level = al.level;
|
||||||
ams->ms.maps = al.maps;
|
ams->ms.maps = maps__get(al.maps);
|
||||||
ams->ms.sym = al.sym;
|
ams->ms.sym = al.sym;
|
||||||
ams->ms.map = al.map;
|
ams->ms.map = map__get(al.map);
|
||||||
ams->phys_addr = 0;
|
ams->phys_addr = 0;
|
||||||
ams->data_page_size = 0;
|
ams->data_page_size = 0;
|
||||||
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ip__resolve_data(struct thread *thread,
|
static void ip__resolve_data(struct thread *thread,
|
||||||
@ -2247,18 +2248,19 @@ static void ip__resolve_data(struct thread *thread,
|
|||||||
{
|
{
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
|
||||||
memset(&al, 0, sizeof(al));
|
addr_location__init(&al);
|
||||||
|
|
||||||
thread__find_symbol(thread, m, addr, &al);
|
thread__find_symbol(thread, m, addr, &al);
|
||||||
|
|
||||||
ams->addr = addr;
|
ams->addr = addr;
|
||||||
ams->al_addr = al.addr;
|
ams->al_addr = al.addr;
|
||||||
ams->al_level = al.level;
|
ams->al_level = al.level;
|
||||||
ams->ms.maps = al.maps;
|
ams->ms.maps = maps__get(al.maps);
|
||||||
ams->ms.sym = al.sym;
|
ams->ms.sym = al.sym;
|
||||||
ams->ms.map = al.map;
|
ams->ms.map = map__get(al.map);
|
||||||
ams->phys_addr = phys_addr;
|
ams->phys_addr = phys_addr;
|
||||||
ams->data_page_size = daddr_page_size;
|
ams->data_page_size = daddr_page_size;
|
||||||
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mem_info *sample__resolve_mem(struct perf_sample *sample,
|
struct mem_info *sample__resolve_mem(struct perf_sample *sample,
|
||||||
@ -2319,10 +2321,11 @@ static int add_callchain_ip(struct thread *thread,
|
|||||||
{
|
{
|
||||||
struct map_symbol ms;
|
struct map_symbol ms;
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
int nr_loop_iter = 0, err;
|
int nr_loop_iter = 0, err = 0;
|
||||||
u64 iter_cycles = 0;
|
u64 iter_cycles = 0;
|
||||||
const char *srcline = NULL;
|
const char *srcline = NULL;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
al.filtered = 0;
|
al.filtered = 0;
|
||||||
al.sym = NULL;
|
al.sym = NULL;
|
||||||
al.srcline = NULL;
|
al.srcline = NULL;
|
||||||
@ -2348,9 +2351,10 @@ static int add_callchain_ip(struct thread *thread,
|
|||||||
* Discard all.
|
* Discard all.
|
||||||
*/
|
*/
|
||||||
callchain_cursor_reset(cursor);
|
callchain_cursor_reset(cursor);
|
||||||
return 1;
|
err = 1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
thread__find_symbol(thread, *cpumode, ip, &al);
|
thread__find_symbol(thread, *cpumode, ip, &al);
|
||||||
}
|
}
|
||||||
@ -2363,31 +2367,32 @@ static int add_callchain_ip(struct thread *thread,
|
|||||||
symbol__match_regex(al.sym, &ignore_callees_regex)) {
|
symbol__match_regex(al.sym, &ignore_callees_regex)) {
|
||||||
/* Treat this symbol as the root,
|
/* Treat this symbol as the root,
|
||||||
forgetting its callees. */
|
forgetting its callees. */
|
||||||
*root_al = al;
|
addr_location__copy(root_al, &al);
|
||||||
callchain_cursor_reset(cursor);
|
callchain_cursor_reset(cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol_conf.hide_unresolved && al.sym == NULL)
|
if (symbol_conf.hide_unresolved && al.sym == NULL)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
if (iter) {
|
if (iter) {
|
||||||
nr_loop_iter = iter->nr_loop_iter;
|
nr_loop_iter = iter->nr_loop_iter;
|
||||||
iter_cycles = iter->cycles;
|
iter_cycles = iter->cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.maps = al.maps;
|
ms.maps = maps__get(al.maps);
|
||||||
ms.map = al.map;
|
ms.map = map__get(al.map);
|
||||||
ms.sym = al.sym;
|
ms.sym = al.sym;
|
||||||
|
|
||||||
if (!branch && append_inlines(cursor, &ms, ip) == 0)
|
if (!branch && append_inlines(cursor, &ms, ip) == 0)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
srcline = callchain_srcline(&ms, al.addr);
|
srcline = callchain_srcline(&ms, al.addr);
|
||||||
err = callchain_cursor_append(cursor, ip, &ms,
|
err = callchain_cursor_append(cursor, ip, &ms,
|
||||||
branch, flags, nr_loop_iter,
|
branch, flags, nr_loop_iter,
|
||||||
iter_cycles, branch_from, srcline);
|
iter_cycles, branch_from, srcline);
|
||||||
map__put(al.map);
|
out:
|
||||||
|
addr_location__exit(&al);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,9 +469,11 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
|
|||||||
struct addr_location node_al;
|
struct addr_location node_al;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
|
|
||||||
|
addr_location__init(&node_al);
|
||||||
node_al.addr = map__map_ip(map, node->ip);
|
node_al.addr = map__map_ip(map, node->ip);
|
||||||
node_al.map = map;
|
node_al.map = map__get(map);
|
||||||
offset = get_offset(node->ms.sym, &node_al);
|
offset = get_offset(node->ms.sym, &node_al);
|
||||||
|
addr_location__exit(&node_al);
|
||||||
|
|
||||||
pydict_set_item_string_decref(
|
pydict_set_item_string_decref(
|
||||||
pyelem, "sym_off",
|
pyelem, "sym_off",
|
||||||
@ -539,6 +541,7 @@ static PyObject *python_process_brstack(struct perf_sample *sample,
|
|||||||
pydict_set_item_string_decref(pyelem, "cycles",
|
pydict_set_item_string_decref(pyelem, "cycles",
|
||||||
PyLong_FromUnsignedLongLong(entries[i].flags.cycles));
|
PyLong_FromUnsignedLongLong(entries[i].flags.cycles));
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
thread__find_map_fb(thread, sample->cpumode,
|
thread__find_map_fb(thread, sample->cpumode,
|
||||||
entries[i].from, &al);
|
entries[i].from, &al);
|
||||||
dsoname = get_dsoname(al.map);
|
dsoname = get_dsoname(al.map);
|
||||||
@ -551,6 +554,7 @@ static PyObject *python_process_brstack(struct perf_sample *sample,
|
|||||||
pydict_set_item_string_decref(pyelem, "to_dsoname",
|
pydict_set_item_string_decref(pyelem, "to_dsoname",
|
||||||
_PyUnicode_FromString(dsoname));
|
_PyUnicode_FromString(dsoname));
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
PyList_Append(pylist, pyelem);
|
PyList_Append(pylist, pyelem);
|
||||||
Py_DECREF(pyelem);
|
Py_DECREF(pyelem);
|
||||||
}
|
}
|
||||||
@ -594,7 +598,6 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
|
|||||||
PyObject *pylist;
|
PyObject *pylist;
|
||||||
u64 i;
|
u64 i;
|
||||||
char bf[512];
|
char bf[512];
|
||||||
struct addr_location al;
|
|
||||||
|
|
||||||
pylist = PyList_New(0);
|
pylist = PyList_New(0);
|
||||||
if (!pylist)
|
if (!pylist)
|
||||||
@ -605,7 +608,9 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
|
|||||||
|
|
||||||
for (i = 0; i < br->nr; i++) {
|
for (i = 0; i < br->nr; i++) {
|
||||||
PyObject *pyelem;
|
PyObject *pyelem;
|
||||||
|
struct addr_location al;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
pyelem = PyDict_New();
|
pyelem = PyDict_New();
|
||||||
if (!pyelem)
|
if (!pyelem)
|
||||||
Py_FatalError("couldn't create Python dictionary");
|
Py_FatalError("couldn't create Python dictionary");
|
||||||
@ -644,6 +649,7 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
|
|||||||
|
|
||||||
PyList_Append(pylist, pyelem);
|
PyList_Append(pylist, pyelem);
|
||||||
Py_DECREF(pyelem);
|
Py_DECREF(pyelem);
|
||||||
|
addr_location__exit(&al);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@ -432,18 +432,25 @@ int thread__memcpy(struct thread *thread, struct machine *machine,
|
|||||||
if (machine__kernel_ip(machine, ip))
|
if (machine__kernel_ip(machine, ip))
|
||||||
cpumode = PERF_RECORD_MISC_KERNEL;
|
cpumode = PERF_RECORD_MISC_KERNEL;
|
||||||
|
|
||||||
if (!thread__find_map(thread, cpumode, ip, &al))
|
addr_location__init(&al);
|
||||||
return -1;
|
if (!thread__find_map(thread, cpumode, ip, &al)) {
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
dso = map__dso(al.map);
|
dso = map__dso(al.map);
|
||||||
|
|
||||||
if( !dso || dso->data.status == DSO_DATA_STATUS_ERROR || map__load(al.map) < 0)
|
if (!dso || dso->data.status == DSO_DATA_STATUS_ERROR || map__load(al.map) < 0) {
|
||||||
|
addr_location__exit(&al);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
offset = map__map_ip(al.map, ip);
|
offset = map__map_ip(al.map, ip);
|
||||||
if (is64bit)
|
if (is64bit)
|
||||||
*is64bit = dso->is_64_bit;
|
*is64bit = dso->is_64_bit;
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
|
|
||||||
return dso__data_read_offset(dso, machine, offset, buf, len);
|
return dso__data_read_offset(dso, machine, offset, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +90,12 @@ static int __report_module(struct addr_location *al, u64 ip,
|
|||||||
static int report_module(u64 ip, struct unwind_info *ui)
|
static int report_module(u64 ip, struct unwind_info *ui)
|
||||||
{
|
{
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
int res;
|
||||||
|
|
||||||
return __report_module(&al, ip, ui);
|
addr_location__init(&al);
|
||||||
|
res = __report_module(&al, ip, ui);
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -104,8 +108,11 @@ static int entry(u64 ip, struct unwind_info *ui)
|
|||||||
struct unwind_entry *e = &ui->entries[ui->idx++];
|
struct unwind_entry *e = &ui->entries[ui->idx++];
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
|
||||||
if (__report_module(&al, ip, ui))
|
addr_location__init(&al);
|
||||||
|
if (__report_module(&al, ip, ui)) {
|
||||||
|
addr_location__exit(&al);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
e->ip = ip;
|
e->ip = ip;
|
||||||
e->ms.maps = al.maps;
|
e->ms.maps = al.maps;
|
||||||
@ -116,6 +123,7 @@ static int entry(u64 ip, struct unwind_info *ui)
|
|||||||
al.sym ? al.sym->name : "''",
|
al.sym ? al.sym->name : "''",
|
||||||
ip,
|
ip,
|
||||||
al.map ? map__map_ip(al.map, ip) : (u64) 0);
|
al.map ? map__map_ip(al.map, ip) : (u64) 0);
|
||||||
|
addr_location__exit(&al);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,17 +144,22 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
|
|||||||
ssize_t size;
|
ssize_t size;
|
||||||
struct dso *dso;
|
struct dso *dso;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
if (!thread__find_map(ui->thread, PERF_RECORD_MISC_USER, addr, &al)) {
|
if (!thread__find_map(ui->thread, PERF_RECORD_MISC_USER, addr, &al)) {
|
||||||
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
|
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
|
||||||
return -1;
|
goto out_fail;
|
||||||
}
|
}
|
||||||
dso = map__dso(al.map);
|
dso = map__dso(al.map);
|
||||||
if (!dso)
|
if (!dso)
|
||||||
return -1;
|
goto out_fail;
|
||||||
|
|
||||||
size = dso__data_read_addr(dso, al.map, ui->machine, addr, (u8 *) data, sizeof(*data));
|
size = dso__data_read_addr(dso, al.map, ui->machine, addr, (u8 *) data, sizeof(*data));
|
||||||
|
|
||||||
|
addr_location__exit(&al);
|
||||||
return !(size == sizeof(*data));
|
return !(size == sizeof(*data));
|
||||||
|
out_fail:
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
|
static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
|
||||||
|
@ -416,7 +416,12 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
|
|||||||
static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
|
static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
|
||||||
{
|
{
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
return thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al);
|
struct map *ret;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
|
ret = thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al);
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -631,7 +636,9 @@ static int entry(u64 ip, struct thread *thread,
|
|||||||
{
|
{
|
||||||
struct unwind_entry e;
|
struct unwind_entry e;
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
addr_location__init(&al);
|
||||||
e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
|
e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
|
||||||
e.ip = ip;
|
e.ip = ip;
|
||||||
e.ms.map = al.map;
|
e.ms.map = al.map;
|
||||||
@ -642,7 +649,9 @@ static int entry(u64 ip, struct thread *thread,
|
|||||||
ip,
|
ip,
|
||||||
al.map ? map__map_ip(al.map, ip) : (u64) 0);
|
al.map ? map__map_ip(al.map, ip) : (u64) 0);
|
||||||
|
|
||||||
return cb(&e, arg);
|
ret = cb(&e, arg);
|
||||||
|
addr_location__exit(&al);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void display_error(int err)
|
static void display_error(int err)
|
||||||
|
Loading…
Reference in New Issue
Block a user