summaryrefslogtreecommitdiff
path: root/tools/perf/util/cs-etm.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/cs-etm.c')
-rw-r--r--tools/perf/util/cs-etm.c73
1 files changed, 55 insertions, 18 deletions
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 3d1c34fc4d68..707afdbd9529 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -21,14 +21,18 @@
#include "cs-etm.h"
#include "cs-etm-decoder/cs-etm-decoder.h"
#include "debug.h"
+#include "dso.h"
#include "evlist.h"
#include "intlist.h"
#include "machine.h"
#include "map.h"
#include "perf.h"
+#include "session.h"
+#include "map_symbol.h"
+#include "branch.h"
#include "symbol.h"
+#include "tool.h"
#include "thread.h"
-#include "thread_map.h"
#include "thread-stack.h"
#include <tools/libc_compat.h>
#include "util.h"
@@ -1076,6 +1080,35 @@ bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq)
return !!etmq->etm->timeless_decoding;
}
+static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
+ u64 trace_chan_id,
+ const struct cs_etm_packet *packet,
+ struct perf_sample *sample)
+{
+ /*
+ * It's pointless to read instructions for the CS_ETM_DISCONTINUITY
+ * packet, so directly bail out with 'insn_len' = 0.
+ */
+ if (packet->sample_type == CS_ETM_DISCONTINUITY) {
+ sample->insn_len = 0;
+ return;
+ }
+
+ /*
+ * T32 instruction size might be 32-bit or 16-bit, decide by calling
+ * cs_etm__t32_instr_size().
+ */
+ if (packet->isa == CS_ETM_ISA_T32)
+ sample->insn_len = cs_etm__t32_instr_size(etmq, trace_chan_id,
+ sample->ip);
+ /* Otherwise, A64 and A32 instruction size are always 32-bit. */
+ else
+ sample->insn_len = 4;
+
+ cs_etm__mem_access(etmq, trace_chan_id, sample->ip,
+ sample->insn_len, (void *)sample->insn);
+}
+
static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
u64 addr, u64 period)
@@ -1097,9 +1130,10 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
sample.period = period;
sample.cpu = tidq->packet->cpu;
sample.flags = tidq->prev_packet->flags;
- sample.insn_len = 1;
sample.cpumode = event->sample.header.misc;
+ cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample);
+
if (etm->synth_opts.last_branch) {
cs_etm__copy_last_branch_rb(etmq, tidq);
sample.branch_stack = tidq->last_branch;
@@ -1159,6 +1193,9 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
sample.flags = tidq->prev_packet->flags;
sample.cpumode = event->sample.header.misc;
+ cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->prev_packet,
+ &sample);
+
/*
* perf report cannot handle events without a branch stack
*/
@@ -1222,15 +1259,15 @@ static int cs_etm__synth_event(struct perf_session *session,
static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
struct perf_session *session)
{
- struct perf_evlist *evlist = session->evlist;
- struct perf_evsel *evsel;
+ struct evlist *evlist = session->evlist;
+ struct evsel *evsel;
struct perf_event_attr attr;
bool found = false;
u64 id;
int err;
evlist__for_each_entry(evlist, evsel) {
- if (evsel->attr.type == etm->pmu_type) {
+ if (evsel->core.attr.type == etm->pmu_type) {
found = true;
break;
}
@@ -1244,7 +1281,7 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
memset(&attr, 0, sizeof(struct perf_event_attr));
attr.size = sizeof(struct perf_event_attr);
attr.type = PERF_TYPE_HARDWARE;
- attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK;
+ attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK;
attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
PERF_SAMPLE_PERIOD;
if (etm->timeless_decoding)
@@ -1252,13 +1289,13 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
else
attr.sample_type |= PERF_SAMPLE_TIME;
- attr.exclude_user = evsel->attr.exclude_user;
- attr.exclude_kernel = evsel->attr.exclude_kernel;
- attr.exclude_hv = evsel->attr.exclude_hv;
- attr.exclude_host = evsel->attr.exclude_host;
- attr.exclude_guest = evsel->attr.exclude_guest;
- attr.sample_id_all = evsel->attr.sample_id_all;
- attr.read_format = evsel->attr.read_format;
+ attr.exclude_user = evsel->core.attr.exclude_user;
+ attr.exclude_kernel = evsel->core.attr.exclude_kernel;
+ attr.exclude_hv = evsel->core.attr.exclude_hv;
+ attr.exclude_host = evsel->core.attr.exclude_host;
+ attr.exclude_guest = evsel->core.attr.exclude_guest;
+ attr.sample_id_all = evsel->core.attr.sample_id_all;
+ attr.read_format = evsel->core.attr.read_format;
/* create new id val to be a fixed offset from evsel id */
id = evsel->id[0] + 1000000000;
@@ -2294,8 +2331,8 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,
static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
{
- struct perf_evsel *evsel;
- struct perf_evlist *evlist = etm->session->evlist;
+ struct evsel *evsel;
+ struct evlist *evlist = etm->session->evlist;
bool timeless_decoding = true;
/*
@@ -2303,7 +2340,7 @@ static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
* with the time bit set.
*/
evlist__for_each_entry(evlist, evsel) {
- if ((evsel->attr.sample_type & PERF_SAMPLE_TIME))
+ if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
timeless_decoding = false;
}
@@ -2337,7 +2374,7 @@ static const char * const cs_etmv4_priv_fmts[] = {
[CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n",
};
-static void cs_etm__print_auxtrace_info(u64 *val, int num)
+static void cs_etm__print_auxtrace_info(__u64 *val, int num)
{
int i, j, cpu = 0;
@@ -2360,7 +2397,7 @@ static void cs_etm__print_auxtrace_info(u64 *val, int num)
int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
- struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
+ struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
struct cs_etm_auxtrace *etm = NULL;
struct int_node *inode;
unsigned int pmu_type;