/* * SPDX-License-Identifier: GPL-2.0 * * Copyright(C) 2015-2018 Linaro Limited. * * Author: Tor Jeremiassen * Author: Mathieu Poirier */ #include #include #include #include #include #include #include "auxtrace.h" #include "color.h" #include "cs-etm.h" #include "debug.h" #include "evlist.h" #include "intlist.h" #include "machine.h" #include "map.h" #include "perf.h" #include "thread.h" #include "thread_map.h" #include "thread-stack.h" #include "util.h" #define MAX_TIMESTAMP (~0ULL) struct cs_etm_auxtrace { struct auxtrace auxtrace; struct auxtrace_queues queues; struct auxtrace_heap heap; struct itrace_synth_opts synth_opts; struct perf_session *session; struct machine *machine; struct thread *unknown_thread; u8 timeless_decoding; u8 snapshot_mode; u8 data_queued; u8 sample_branches; int num_cpu; u32 auxtrace_type; u64 branches_sample_type; u64 branches_id; u64 **metadata; u64 kernel_start; unsigned int pmu_type; }; struct cs_etm_queue { struct cs_etm_auxtrace *etm; struct thread *thread; struct cs_etm_decoder *decoder; struct auxtrace_buffer *buffer; const struct cs_etm_state *state; union perf_event *event_buf; unsigned int queue_nr; pid_t pid, tid; int cpu; u64 time; u64 timestamp; u64 offset; }; static int cs_etm__flush_events(struct perf_session *session, struct perf_tool *tool) { (void) session; (void) tool; return 0; } static void cs_etm__free_queue(void *priv) { struct cs_etm_queue *etmq = priv; free(etmq); } static void cs_etm__free_events(struct perf_session *session) { unsigned int i; struct cs_etm_auxtrace *aux = container_of(session->auxtrace, struct cs_etm_auxtrace, auxtrace); struct auxtrace_queues *queues = &aux->queues; for (i = 0; i < queues->nr_queues; i++) { cs_etm__free_queue(queues->queue_array[i].priv); queues->queue_array[i].priv = NULL; } auxtrace_queues__free(queues); } static void cs_etm__free(struct perf_session *session) { struct cs_etm_auxtrace *aux = container_of(session->auxtrace, struct cs_etm_auxtrace, auxtrace); cs_etm__free_events(session); session->auxtrace = NULL; zfree(&aux); } static int cs_etm__process_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, struct perf_tool *tool) { (void) session; (void) event; (void) sample; (void) tool; return 0; } static int cs_etm__process_auxtrace_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool) { (void) session; (void) event; (void) tool; return 0; } static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm) { struct perf_evsel *evsel; struct perf_evlist *evlist = etm->session->evlist; bool timeless_decoding = true; /* * Circle through the list of event and complain if we find one * with the time bit set. */ evlist__for_each_entry(evlist, evsel) { if ((evsel->attr.sample_type & PERF_SAMPLE_TIME)) timeless_decoding = false; } return timeless_decoding; } int cs_etm__process_auxtrace_info(union perf_event *event, struct perf_session *session) { struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; struct cs_etm_auxtrace *etm = NULL; int event_header_size = sizeof(struct perf_event_header); int info_header_size; int total_size = auxtrace_info->header.size; int err = 0; /* * sizeof(auxtrace_info_event::type) + * sizeof(auxtrace_info_event::reserved) == 8 */ info_header_size = 8; if (total_size < (event_header_size + info_header_size)) return -EINVAL; etm = zalloc(sizeof(*etm)); if (!etm) err = -ENOMEM; err = auxtrace_queues__init(&etm->queues); if (err) goto err_free_etm; etm->session = session; etm->machine = &session->machines.host; etm->auxtrace_type = auxtrace_info->type; etm->timeless_decoding = cs_etm__is_timeless_decoding(etm); etm->auxtrace.process_event = cs_etm__process_event; etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event; etm->auxtrace.flush_events = cs_etm__flush_events; etm->auxtrace.free_events = cs_etm__free_events; etm->auxtrace.free = cs_etm__free; session->auxtrace = &etm->auxtrace; if (dump_trace) return 0; err = auxtrace_queues__process_index(&etm->queues, session); if (err) goto err_free_queues; etm->data_queued = etm->queues.populated; return 0; err_free_queues: auxtrace_queues__free(&etm->queues); session->auxtrace = NULL; err_free_etm: zfree(&etm); return -EINVAL; }