1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include "ETMDecoder.h"
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Worker #include <sstream>
20*288bf522SAndroid Build Coastguard Worker
21*288bf522SAndroid Build Coastguard Worker #include <android-base/expected.h>
22*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
23*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
24*288bf522SAndroid Build Coastguard Worker #include <llvm/Support/MemoryBuffer.h>
25*288bf522SAndroid Build Coastguard Worker #include <opencsd.h>
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Worker #include "ETMConstants.h"
28*288bf522SAndroid Build Coastguard Worker
29*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
30*288bf522SAndroid Build Coastguard Worker namespace {
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker class DecoderLogStr : public ocsdMsgLogStrOutI {
33*288bf522SAndroid Build Coastguard Worker public:
printOutStr(const std::string & out_str)34*288bf522SAndroid Build Coastguard Worker void printOutStr(const std::string& out_str) override { LOG(DEBUG) << out_str; }
35*288bf522SAndroid Build Coastguard Worker };
36*288bf522SAndroid Build Coastguard Worker
37*288bf522SAndroid Build Coastguard Worker class DecodeErrorLogger : public ocsdDefaultErrorLogger {
38*288bf522SAndroid Build Coastguard Worker public:
DecodeErrorLogger(const std::function<void (const ocsdError &)> & error_callback)39*288bf522SAndroid Build Coastguard Worker DecodeErrorLogger(const std::function<void(const ocsdError&)>& error_callback)
40*288bf522SAndroid Build Coastguard Worker : error_callback_(error_callback) {
41*288bf522SAndroid Build Coastguard Worker initErrorLogger(OCSD_ERR_SEV_INFO, false);
42*288bf522SAndroid Build Coastguard Worker msg_logger_.setLogOpts(ocsdMsgLogger::OUT_STR_CB);
43*288bf522SAndroid Build Coastguard Worker msg_logger_.setStrOutFn(&log_str_);
44*288bf522SAndroid Build Coastguard Worker setOutputLogger(&msg_logger_);
45*288bf522SAndroid Build Coastguard Worker }
46*288bf522SAndroid Build Coastguard Worker
LogError(const ocsd_hndl_err_log_t handle,const ocsdError * error)47*288bf522SAndroid Build Coastguard Worker void LogError(const ocsd_hndl_err_log_t handle, const ocsdError* error) override {
48*288bf522SAndroid Build Coastguard Worker ocsdDefaultErrorLogger::LogError(handle, error);
49*288bf522SAndroid Build Coastguard Worker if (error != nullptr) {
50*288bf522SAndroid Build Coastguard Worker error_callback_(*error);
51*288bf522SAndroid Build Coastguard Worker }
52*288bf522SAndroid Build Coastguard Worker }
53*288bf522SAndroid Build Coastguard Worker
54*288bf522SAndroid Build Coastguard Worker private:
55*288bf522SAndroid Build Coastguard Worker std::function<void(const ocsdError&)> error_callback_;
56*288bf522SAndroid Build Coastguard Worker DecoderLogStr log_str_;
57*288bf522SAndroid Build Coastguard Worker ocsdMsgLogger msg_logger_;
58*288bf522SAndroid Build Coastguard Worker };
59*288bf522SAndroid Build Coastguard Worker
IsRespError(ocsd_datapath_resp_t resp)60*288bf522SAndroid Build Coastguard Worker static bool IsRespError(ocsd_datapath_resp_t resp) {
61*288bf522SAndroid Build Coastguard Worker return resp >= OCSD_RESP_ERR_CONT;
62*288bf522SAndroid Build Coastguard Worker }
63*288bf522SAndroid Build Coastguard Worker
64*288bf522SAndroid Build Coastguard Worker // Used instead of DecodeTree in OpenCSD to avoid linking decoders not for ETMV4 instruction tracing
65*288bf522SAndroid Build Coastguard Worker // in OpenCSD.
66*288bf522SAndroid Build Coastguard Worker class ETMV4IDecodeTree {
67*288bf522SAndroid Build Coastguard Worker public:
ETMV4IDecodeTree()68*288bf522SAndroid Build Coastguard Worker ETMV4IDecodeTree()
69*288bf522SAndroid Build Coastguard Worker : error_logger_(std::bind(&ETMV4IDecodeTree::ProcessError, this, std::placeholders::_1)) {
70*288bf522SAndroid Build Coastguard Worker ocsd_err_t err = frame_decoder_.Init();
71*288bf522SAndroid Build Coastguard Worker CHECK_EQ(err, OCSD_OK);
72*288bf522SAndroid Build Coastguard Worker err = frame_decoder_.Configure(OCSD_DFRMTR_FRAME_MEM_ALIGN);
73*288bf522SAndroid Build Coastguard Worker CHECK_EQ(err, OCSD_OK);
74*288bf522SAndroid Build Coastguard Worker frame_decoder_.getErrLogAttachPt()->attach(&error_logger_);
75*288bf522SAndroid Build Coastguard Worker }
76*288bf522SAndroid Build Coastguard Worker
CreateDecoder(const EtmV4Config * config)77*288bf522SAndroid Build Coastguard Worker bool CreateDecoder(const EtmV4Config* config) {
78*288bf522SAndroid Build Coastguard Worker uint8_t trace_id = config->getTraceID();
79*288bf522SAndroid Build Coastguard Worker auto packet_decoder = std::make_unique<TrcPktProcEtmV4I>(trace_id);
80*288bf522SAndroid Build Coastguard Worker packet_decoder->setProtocolConfig(config);
81*288bf522SAndroid Build Coastguard Worker packet_decoder->getErrorLogAttachPt()->replace_first(&error_logger_);
82*288bf522SAndroid Build Coastguard Worker frame_decoder_.getIDStreamAttachPt(trace_id)->attach(packet_decoder.get());
83*288bf522SAndroid Build Coastguard Worker auto result = packet_decoders_.emplace(trace_id, packet_decoder.release());
84*288bf522SAndroid Build Coastguard Worker if (!result.second) {
85*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "trace id " << trace_id << " has been used";
86*288bf522SAndroid Build Coastguard Worker }
87*288bf522SAndroid Build Coastguard Worker return result.second;
88*288bf522SAndroid Build Coastguard Worker }
89*288bf522SAndroid Build Coastguard Worker
AttachPacketSink(uint8_t trace_id,IPktDataIn<EtmV4ITrcPacket> & packet_sink)90*288bf522SAndroid Build Coastguard Worker void AttachPacketSink(uint8_t trace_id, IPktDataIn<EtmV4ITrcPacket>& packet_sink) {
91*288bf522SAndroid Build Coastguard Worker auto& packet_decoder = packet_decoders_[trace_id];
92*288bf522SAndroid Build Coastguard Worker CHECK(packet_decoder);
93*288bf522SAndroid Build Coastguard Worker packet_decoder->getPacketOutAttachPt()->replace_first(&packet_sink);
94*288bf522SAndroid Build Coastguard Worker }
95*288bf522SAndroid Build Coastguard Worker
AttachPacketMonitor(uint8_t trace_id,IPktRawDataMon<EtmV4ITrcPacket> & packet_monitor)96*288bf522SAndroid Build Coastguard Worker void AttachPacketMonitor(uint8_t trace_id, IPktRawDataMon<EtmV4ITrcPacket>& packet_monitor) {
97*288bf522SAndroid Build Coastguard Worker auto& packet_decoder = packet_decoders_[trace_id];
98*288bf522SAndroid Build Coastguard Worker CHECK(packet_decoder);
99*288bf522SAndroid Build Coastguard Worker packet_decoder->getRawPacketMonAttachPt()->replace_first(&packet_monitor);
100*288bf522SAndroid Build Coastguard Worker }
101*288bf522SAndroid Build Coastguard Worker
AttachRawFramePrinter(RawFramePrinter & frame_printer)102*288bf522SAndroid Build Coastguard Worker void AttachRawFramePrinter(RawFramePrinter& frame_printer) {
103*288bf522SAndroid Build Coastguard Worker frame_decoder_.Configure(frame_decoder_.getConfigFlags() | OCSD_DFRMTR_PACKED_RAW_OUT);
104*288bf522SAndroid Build Coastguard Worker frame_decoder_.getTrcRawFrameAttachPt()->replace_first(&frame_printer);
105*288bf522SAndroid Build Coastguard Worker }
106*288bf522SAndroid Build Coastguard Worker
GetFormattedDataIn()107*288bf522SAndroid Build Coastguard Worker ITrcDataIn& GetFormattedDataIn() { return frame_decoder_; }
108*288bf522SAndroid Build Coastguard Worker
GetUnformattedDataIn(uint8_t trace_id)109*288bf522SAndroid Build Coastguard Worker ITrcDataIn& GetUnformattedDataIn(uint8_t trace_id) {
110*288bf522SAndroid Build Coastguard Worker auto& decoder = packet_decoders_[trace_id];
111*288bf522SAndroid Build Coastguard Worker CHECK(decoder);
112*288bf522SAndroid Build Coastguard Worker return *decoder;
113*288bf522SAndroid Build Coastguard Worker }
114*288bf522SAndroid Build Coastguard Worker
ProcessError(const ocsdError & error)115*288bf522SAndroid Build Coastguard Worker void ProcessError(const ocsdError& error) {
116*288bf522SAndroid Build Coastguard Worker if (error.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR) {
117*288bf522SAndroid Build Coastguard Worker // Found an invalid packet header, following packets for this trace id may also be invalid.
118*288bf522SAndroid Build Coastguard Worker // So reset the decoder to find I_ASYNC packet in the data stream.
119*288bf522SAndroid Build Coastguard Worker if (auto it = packet_decoders_.find(error.getErrorChanID()); it != packet_decoders_.end()) {
120*288bf522SAndroid Build Coastguard Worker auto& packet_decoder = it->second;
121*288bf522SAndroid Build Coastguard Worker CHECK(packet_decoder);
122*288bf522SAndroid Build Coastguard Worker packet_decoder->TraceDataIn(OCSD_OP_RESET, error.getErrorIndex(), 0, nullptr, nullptr);
123*288bf522SAndroid Build Coastguard Worker }
124*288bf522SAndroid Build Coastguard Worker }
125*288bf522SAndroid Build Coastguard Worker }
126*288bf522SAndroid Build Coastguard Worker
ErrorLogger()127*288bf522SAndroid Build Coastguard Worker DecodeErrorLogger& ErrorLogger() { return error_logger_; }
128*288bf522SAndroid Build Coastguard Worker
129*288bf522SAndroid Build Coastguard Worker private:
130*288bf522SAndroid Build Coastguard Worker DecodeErrorLogger error_logger_;
131*288bf522SAndroid Build Coastguard Worker TraceFormatterFrameDecoder frame_decoder_;
132*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, std::unique_ptr<TrcPktProcEtmV4I>> packet_decoders_;
133*288bf522SAndroid Build Coastguard Worker };
134*288bf522SAndroid Build Coastguard Worker
135*288bf522SAndroid Build Coastguard Worker // Similar to IPktDataIn<EtmV4ITrcPacket>, but add trace id.
136*288bf522SAndroid Build Coastguard Worker struct PacketCallback {
137*288bf522SAndroid Build Coastguard Worker // packet callbacks are called in priority order.
138*288bf522SAndroid Build Coastguard Worker enum Priority {
139*288bf522SAndroid Build Coastguard Worker MAP_LOCATOR,
140*288bf522SAndroid Build Coastguard Worker BRANCH_LIST_PARSER,
141*288bf522SAndroid Build Coastguard Worker PACKET_TO_ELEMENT,
142*288bf522SAndroid Build Coastguard Worker };
143*288bf522SAndroid Build Coastguard Worker
PacketCallbacksimpleperf::__anon3f3c96020111::PacketCallback144*288bf522SAndroid Build Coastguard Worker PacketCallback(Priority prio) : priority(prio) {}
~PacketCallbacksimpleperf::__anon3f3c96020111::PacketCallback145*288bf522SAndroid Build Coastguard Worker virtual ~PacketCallback() {}
146*288bf522SAndroid Build Coastguard Worker virtual ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
147*288bf522SAndroid Build Coastguard Worker ocsd_trc_index_t index_sop,
148*288bf522SAndroid Build Coastguard Worker const EtmV4ITrcPacket* pkt) = 0;
149*288bf522SAndroid Build Coastguard Worker const Priority priority;
150*288bf522SAndroid Build Coastguard Worker };
151*288bf522SAndroid Build Coastguard Worker
152*288bf522SAndroid Build Coastguard Worker // Receives packets from a packet decoder in OpenCSD library.
153*288bf522SAndroid Build Coastguard Worker class PacketSink : public IPktDataIn<EtmV4ITrcPacket> {
154*288bf522SAndroid Build Coastguard Worker public:
PacketSink(uint8_t trace_id)155*288bf522SAndroid Build Coastguard Worker PacketSink(uint8_t trace_id) : trace_id_(trace_id) {}
156*288bf522SAndroid Build Coastguard Worker
AddCallback(PacketCallback * callback)157*288bf522SAndroid Build Coastguard Worker void AddCallback(PacketCallback* callback) {
158*288bf522SAndroid Build Coastguard Worker auto it = std::lower_bound(callbacks_.begin(), callbacks_.end(), callback,
159*288bf522SAndroid Build Coastguard Worker [](const PacketCallback* c1, const PacketCallback* c2) {
160*288bf522SAndroid Build Coastguard Worker return c1->priority < c2->priority;
161*288bf522SAndroid Build Coastguard Worker });
162*288bf522SAndroid Build Coastguard Worker callbacks_.insert(it, callback);
163*288bf522SAndroid Build Coastguard Worker }
164*288bf522SAndroid Build Coastguard Worker
PacketDataIn(ocsd_datapath_op_t op,ocsd_trc_index_t index_sop,const EtmV4ITrcPacket * pkt)165*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t PacketDataIn(ocsd_datapath_op_t op, ocsd_trc_index_t index_sop,
166*288bf522SAndroid Build Coastguard Worker const EtmV4ITrcPacket* pkt) override {
167*288bf522SAndroid Build Coastguard Worker for (auto& callback : callbacks_) {
168*288bf522SAndroid Build Coastguard Worker auto resp = callback->ProcessPacket(trace_id_, op, index_sop, pkt);
169*288bf522SAndroid Build Coastguard Worker if (IsRespError(resp)) {
170*288bf522SAndroid Build Coastguard Worker return resp;
171*288bf522SAndroid Build Coastguard Worker }
172*288bf522SAndroid Build Coastguard Worker }
173*288bf522SAndroid Build Coastguard Worker return OCSD_RESP_CONT;
174*288bf522SAndroid Build Coastguard Worker }
175*288bf522SAndroid Build Coastguard Worker
176*288bf522SAndroid Build Coastguard Worker private:
177*288bf522SAndroid Build Coastguard Worker uint8_t trace_id_;
178*288bf522SAndroid Build Coastguard Worker std::vector<PacketCallback*> callbacks_;
179*288bf522SAndroid Build Coastguard Worker };
180*288bf522SAndroid Build Coastguard Worker
181*288bf522SAndroid Build Coastguard Worker // For each trace_id, when given an addr, find the thread and map it belongs to.
182*288bf522SAndroid Build Coastguard Worker class MapLocator : public PacketCallback {
183*288bf522SAndroid Build Coastguard Worker public:
MapLocator(ETMThreadTree & thread_tree)184*288bf522SAndroid Build Coastguard Worker MapLocator(ETMThreadTree& thread_tree)
185*288bf522SAndroid Build Coastguard Worker : PacketCallback(PacketCallback::MAP_LOCATOR), thread_tree_(thread_tree) {}
186*288bf522SAndroid Build Coastguard Worker
187*288bf522SAndroid Build Coastguard Worker // Return current thread id of a trace_id. If not available, return -1.
GetTid(uint8_t trace_id) const188*288bf522SAndroid Build Coastguard Worker pid_t GetTid(uint8_t trace_id) const { return trace_data_[trace_id].tid; }
189*288bf522SAndroid Build Coastguard Worker
ProcessPacket(uint8_t trace_id,ocsd_datapath_op_t op,ocsd_trc_index_t index_sop,const EtmV4ITrcPacket * pkt)190*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
191*288bf522SAndroid Build Coastguard Worker ocsd_trc_index_t index_sop,
192*288bf522SAndroid Build Coastguard Worker const EtmV4ITrcPacket* pkt) override {
193*288bf522SAndroid Build Coastguard Worker TraceData& data = trace_data_[trace_id];
194*288bf522SAndroid Build Coastguard Worker if (op == OCSD_OP_DATA) {
195*288bf522SAndroid Build Coastguard Worker if (pkt != nullptr && ((!data.use_vmid && pkt->getContext().updated_c) ||
196*288bf522SAndroid Build Coastguard Worker (data.use_vmid && pkt->getContext().updated_v))) {
197*288bf522SAndroid Build Coastguard Worker int32_t new_tid =
198*288bf522SAndroid Build Coastguard Worker static_cast<int32_t>(data.use_vmid ? pkt->getContext().VMID : pkt->getContext().ctxtID);
199*288bf522SAndroid Build Coastguard Worker if (data.tid != new_tid) {
200*288bf522SAndroid Build Coastguard Worker data.tid = new_tid;
201*288bf522SAndroid Build Coastguard Worker data.thread = nullptr;
202*288bf522SAndroid Build Coastguard Worker data.userspace_map = nullptr;
203*288bf522SAndroid Build Coastguard Worker }
204*288bf522SAndroid Build Coastguard Worker }
205*288bf522SAndroid Build Coastguard Worker } else if (op == OCSD_OP_RESET) {
206*288bf522SAndroid Build Coastguard Worker data.tid = -1;
207*288bf522SAndroid Build Coastguard Worker data.thread = nullptr;
208*288bf522SAndroid Build Coastguard Worker data.userspace_map = nullptr;
209*288bf522SAndroid Build Coastguard Worker }
210*288bf522SAndroid Build Coastguard Worker return OCSD_RESP_CONT;
211*288bf522SAndroid Build Coastguard Worker }
212*288bf522SAndroid Build Coastguard Worker
FindMap(uint8_t trace_id,uint64_t addr)213*288bf522SAndroid Build Coastguard Worker const MapEntry* FindMap(uint8_t trace_id, uint64_t addr) {
214*288bf522SAndroid Build Coastguard Worker TraceData& data = trace_data_[trace_id];
215*288bf522SAndroid Build Coastguard Worker if (data.userspace_map != nullptr && data.userspace_map->Contains(addr)) {
216*288bf522SAndroid Build Coastguard Worker return data.userspace_map;
217*288bf522SAndroid Build Coastguard Worker }
218*288bf522SAndroid Build Coastguard Worker if (data.tid == -1) {
219*288bf522SAndroid Build Coastguard Worker return nullptr;
220*288bf522SAndroid Build Coastguard Worker }
221*288bf522SAndroid Build Coastguard Worker if (data.thread == nullptr) {
222*288bf522SAndroid Build Coastguard Worker data.thread = thread_tree_.FindThread(data.tid);
223*288bf522SAndroid Build Coastguard Worker if (data.thread == nullptr) {
224*288bf522SAndroid Build Coastguard Worker return nullptr;
225*288bf522SAndroid Build Coastguard Worker }
226*288bf522SAndroid Build Coastguard Worker }
227*288bf522SAndroid Build Coastguard Worker data.userspace_map = data.thread->maps->FindMapByAddr(addr);
228*288bf522SAndroid Build Coastguard Worker if (data.userspace_map != nullptr) {
229*288bf522SAndroid Build Coastguard Worker return data.userspace_map;
230*288bf522SAndroid Build Coastguard Worker }
231*288bf522SAndroid Build Coastguard Worker // We don't cache kernel map. Because kernel map can start from 0 and overlap all userspace
232*288bf522SAndroid Build Coastguard Worker // maps.
233*288bf522SAndroid Build Coastguard Worker return thread_tree_.GetKernelMaps().FindMapByAddr(addr);
234*288bf522SAndroid Build Coastguard Worker }
235*288bf522SAndroid Build Coastguard Worker
SetUseVmid(uint8_t trace_id,bool value)236*288bf522SAndroid Build Coastguard Worker void SetUseVmid(uint8_t trace_id, bool value) { trace_data_[trace_id].use_vmid = value; }
237*288bf522SAndroid Build Coastguard Worker
238*288bf522SAndroid Build Coastguard Worker private:
239*288bf522SAndroid Build Coastguard Worker struct TraceData {
240*288bf522SAndroid Build Coastguard Worker int32_t tid = -1; // thread id, -1 if invalid
241*288bf522SAndroid Build Coastguard Worker const ThreadEntry* thread = nullptr;
242*288bf522SAndroid Build Coastguard Worker const MapEntry* userspace_map = nullptr;
243*288bf522SAndroid Build Coastguard Worker bool use_vmid = false; // use vmid for PID
244*288bf522SAndroid Build Coastguard Worker };
245*288bf522SAndroid Build Coastguard Worker
246*288bf522SAndroid Build Coastguard Worker ETMThreadTree& thread_tree_;
247*288bf522SAndroid Build Coastguard Worker TraceData trace_data_[256];
248*288bf522SAndroid Build Coastguard Worker };
249*288bf522SAndroid Build Coastguard Worker
250*288bf522SAndroid Build Coastguard Worker // Map (trace_id, ip address) to (binary_path, binary_offset), and read binary files.
251*288bf522SAndroid Build Coastguard Worker class MemAccess : public ITargetMemAccess {
252*288bf522SAndroid Build Coastguard Worker public:
MemAccess(MapLocator & map_locator)253*288bf522SAndroid Build Coastguard Worker MemAccess(MapLocator& map_locator) : map_locator_(map_locator) {}
254*288bf522SAndroid Build Coastguard Worker
ReadTargetMemory(const ocsd_vaddr_t address,uint8_t trace_id,ocsd_mem_space_acc_t,uint32_t * num_bytes,uint8_t * p_buffer)255*288bf522SAndroid Build Coastguard Worker ocsd_err_t ReadTargetMemory(const ocsd_vaddr_t address, uint8_t trace_id, ocsd_mem_space_acc_t,
256*288bf522SAndroid Build Coastguard Worker uint32_t* num_bytes, uint8_t* p_buffer) override {
257*288bf522SAndroid Build Coastguard Worker TraceData& data = trace_data_[trace_id];
258*288bf522SAndroid Build Coastguard Worker const MapEntry* map = map_locator_.FindMap(trace_id, address);
259*288bf522SAndroid Build Coastguard Worker // fast path
260*288bf522SAndroid Build Coastguard Worker if (map != nullptr && map == data.buffer_map && address >= data.buffer_start &&
261*288bf522SAndroid Build Coastguard Worker address + *num_bytes <= data.buffer_end) {
262*288bf522SAndroid Build Coastguard Worker if (data.buffer == nullptr) {
263*288bf522SAndroid Build Coastguard Worker *num_bytes = 0;
264*288bf522SAndroid Build Coastguard Worker } else {
265*288bf522SAndroid Build Coastguard Worker memcpy(p_buffer, data.buffer + (address - data.buffer_start), *num_bytes);
266*288bf522SAndroid Build Coastguard Worker }
267*288bf522SAndroid Build Coastguard Worker return OCSD_OK;
268*288bf522SAndroid Build Coastguard Worker }
269*288bf522SAndroid Build Coastguard Worker
270*288bf522SAndroid Build Coastguard Worker // slow path
271*288bf522SAndroid Build Coastguard Worker size_t copy_size = 0;
272*288bf522SAndroid Build Coastguard Worker if (map != nullptr) {
273*288bf522SAndroid Build Coastguard Worker llvm::MemoryBuffer* memory = GetMemoryBuffer(map->dso);
274*288bf522SAndroid Build Coastguard Worker if (memory != nullptr) {
275*288bf522SAndroid Build Coastguard Worker if (auto opt_offset = map->dso->IpToFileOffset(address, map->start_addr, map->pgoff);
276*288bf522SAndroid Build Coastguard Worker opt_offset) {
277*288bf522SAndroid Build Coastguard Worker uint64_t offset = opt_offset.value();
278*288bf522SAndroid Build Coastguard Worker size_t file_size = memory->getBufferSize();
279*288bf522SAndroid Build Coastguard Worker copy_size = file_size > offset ? std::min<size_t>(file_size - offset, *num_bytes) : 0;
280*288bf522SAndroid Build Coastguard Worker if (copy_size > 0) {
281*288bf522SAndroid Build Coastguard Worker memcpy(p_buffer, memory->getBufferStart() + offset, copy_size);
282*288bf522SAndroid Build Coastguard Worker }
283*288bf522SAndroid Build Coastguard Worker }
284*288bf522SAndroid Build Coastguard Worker }
285*288bf522SAndroid Build Coastguard Worker // Update the last buffer cache.
286*288bf522SAndroid Build Coastguard Worker // Don't cache for the kernel map. Because simpleperf doesn't record an accurate kernel end
287*288bf522SAndroid Build Coastguard Worker // addr.
288*288bf522SAndroid Build Coastguard Worker if (!map->in_kernel) {
289*288bf522SAndroid Build Coastguard Worker data.buffer_map = map;
290*288bf522SAndroid Build Coastguard Worker data.buffer_start = map->start_addr;
291*288bf522SAndroid Build Coastguard Worker data.buffer_end = map->get_end_addr();
292*288bf522SAndroid Build Coastguard Worker if (memory != nullptr && memory->getBufferSize() > map->pgoff &&
293*288bf522SAndroid Build Coastguard Worker (memory->getBufferSize() - map->pgoff >= map->len)) {
294*288bf522SAndroid Build Coastguard Worker data.buffer = memory->getBufferStart() + map->pgoff;
295*288bf522SAndroid Build Coastguard Worker } else if (memory == nullptr) {
296*288bf522SAndroid Build Coastguard Worker data.buffer = nullptr;
297*288bf522SAndroid Build Coastguard Worker } else {
298*288bf522SAndroid Build Coastguard Worker // Memory was found, but the buffer is not good enough to be
299*288bf522SAndroid Build Coastguard Worker // cached. "Invalidate" the cache by setting the map to
300*288bf522SAndroid Build Coastguard Worker // null.
301*288bf522SAndroid Build Coastguard Worker data.buffer_map = nullptr;
302*288bf522SAndroid Build Coastguard Worker }
303*288bf522SAndroid Build Coastguard Worker }
304*288bf522SAndroid Build Coastguard Worker }
305*288bf522SAndroid Build Coastguard Worker *num_bytes = copy_size;
306*288bf522SAndroid Build Coastguard Worker return OCSD_OK;
307*288bf522SAndroid Build Coastguard Worker }
308*288bf522SAndroid Build Coastguard Worker
InvalidateMemAccCache(const uint8_t cs_trace_id)309*288bf522SAndroid Build Coastguard Worker void InvalidateMemAccCache(const uint8_t cs_trace_id) override {}
310*288bf522SAndroid Build Coastguard Worker
311*288bf522SAndroid Build Coastguard Worker private:
GetMemoryBuffer(Dso * dso)312*288bf522SAndroid Build Coastguard Worker llvm::MemoryBuffer* GetMemoryBuffer(Dso* dso) {
313*288bf522SAndroid Build Coastguard Worker auto it = elf_map_.find(dso);
314*288bf522SAndroid Build Coastguard Worker if (it == elf_map_.end()) {
315*288bf522SAndroid Build Coastguard Worker ElfStatus status;
316*288bf522SAndroid Build Coastguard Worker auto res = elf_map_.emplace(dso, ElfFile::Open(dso->GetDebugFilePath(), &status));
317*288bf522SAndroid Build Coastguard Worker it = res.first;
318*288bf522SAndroid Build Coastguard Worker }
319*288bf522SAndroid Build Coastguard Worker return it->second ? it->second->GetMemoryBuffer() : nullptr;
320*288bf522SAndroid Build Coastguard Worker }
321*288bf522SAndroid Build Coastguard Worker
322*288bf522SAndroid Build Coastguard Worker struct TraceData {
323*288bf522SAndroid Build Coastguard Worker const MapEntry* buffer_map = nullptr;
324*288bf522SAndroid Build Coastguard Worker const char* buffer = nullptr;
325*288bf522SAndroid Build Coastguard Worker uint64_t buffer_start = 0;
326*288bf522SAndroid Build Coastguard Worker uint64_t buffer_end = 0;
327*288bf522SAndroid Build Coastguard Worker };
328*288bf522SAndroid Build Coastguard Worker
329*288bf522SAndroid Build Coastguard Worker MapLocator& map_locator_;
330*288bf522SAndroid Build Coastguard Worker std::unordered_map<Dso*, std::unique_ptr<ElfFile>> elf_map_;
331*288bf522SAndroid Build Coastguard Worker TraceData trace_data_[256];
332*288bf522SAndroid Build Coastguard Worker };
333*288bf522SAndroid Build Coastguard Worker
334*288bf522SAndroid Build Coastguard Worker class InstructionDecoder : public TrcIDecode {
335*288bf522SAndroid Build Coastguard Worker public:
DecodeInstruction(ocsd_instr_info * instr_info)336*288bf522SAndroid Build Coastguard Worker ocsd_err_t DecodeInstruction(ocsd_instr_info* instr_info) {
337*288bf522SAndroid Build Coastguard Worker this->instr_info = instr_info;
338*288bf522SAndroid Build Coastguard Worker return TrcIDecode::DecodeInstruction(instr_info);
339*288bf522SAndroid Build Coastguard Worker }
340*288bf522SAndroid Build Coastguard Worker
341*288bf522SAndroid Build Coastguard Worker ocsd_instr_info* instr_info;
342*288bf522SAndroid Build Coastguard Worker };
343*288bf522SAndroid Build Coastguard Worker
344*288bf522SAndroid Build Coastguard Worker // Similar to ITrcGenElemIn, but add next instruction info, which is needed to get branch to addr
345*288bf522SAndroid Build Coastguard Worker // for an InstructionRange element.
346*288bf522SAndroid Build Coastguard Worker struct ElementCallback {
347*288bf522SAndroid Build Coastguard Worker public:
~ElementCallbacksimpleperf::__anon3f3c96020111::ElementCallback348*288bf522SAndroid Build Coastguard Worker virtual ~ElementCallback() {};
349*288bf522SAndroid Build Coastguard Worker virtual ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trace_id,
350*288bf522SAndroid Build Coastguard Worker const OcsdTraceElement& elem,
351*288bf522SAndroid Build Coastguard Worker const ocsd_instr_info* next_instr) = 0;
352*288bf522SAndroid Build Coastguard Worker };
353*288bf522SAndroid Build Coastguard Worker
354*288bf522SAndroid Build Coastguard Worker // Decode packets into elements.
355*288bf522SAndroid Build Coastguard Worker class PacketToElement : public PacketCallback, public ITrcGenElemIn {
356*288bf522SAndroid Build Coastguard Worker public:
PacketToElement(MapLocator & map_locator,const std::unordered_map<uint8_t,std::unique_ptr<EtmV4Config>> & configs,DecodeErrorLogger & error_logger)357*288bf522SAndroid Build Coastguard Worker PacketToElement(MapLocator& map_locator,
358*288bf522SAndroid Build Coastguard Worker const std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs,
359*288bf522SAndroid Build Coastguard Worker DecodeErrorLogger& error_logger)
360*288bf522SAndroid Build Coastguard Worker : PacketCallback(PacketCallback::PACKET_TO_ELEMENT), mem_access_(map_locator) {
361*288bf522SAndroid Build Coastguard Worker for (auto& p : configs) {
362*288bf522SAndroid Build Coastguard Worker uint8_t trace_id = p.first;
363*288bf522SAndroid Build Coastguard Worker const EtmV4Config* config = p.second.get();
364*288bf522SAndroid Build Coastguard Worker element_decoders_.emplace(trace_id, trace_id);
365*288bf522SAndroid Build Coastguard Worker auto& decoder = element_decoders_[trace_id];
366*288bf522SAndroid Build Coastguard Worker decoder.setProtocolConfig(config);
367*288bf522SAndroid Build Coastguard Worker decoder.getErrorLogAttachPt()->replace_first(&error_logger);
368*288bf522SAndroid Build Coastguard Worker decoder.getInstrDecodeAttachPt()->replace_first(&instruction_decoder_);
369*288bf522SAndroid Build Coastguard Worker decoder.getMemoryAccessAttachPt()->replace_first(&mem_access_);
370*288bf522SAndroid Build Coastguard Worker decoder.getTraceElemOutAttachPt()->replace_first(this);
371*288bf522SAndroid Build Coastguard Worker }
372*288bf522SAndroid Build Coastguard Worker }
373*288bf522SAndroid Build Coastguard Worker
AddCallback(ElementCallback * callback)374*288bf522SAndroid Build Coastguard Worker void AddCallback(ElementCallback* callback) { callbacks_.push_back(callback); }
375*288bf522SAndroid Build Coastguard Worker
ProcessPacket(uint8_t trace_id,ocsd_datapath_op_t op,ocsd_trc_index_t index_sop,const EtmV4ITrcPacket * pkt)376*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
377*288bf522SAndroid Build Coastguard Worker ocsd_trc_index_t index_sop,
378*288bf522SAndroid Build Coastguard Worker const EtmV4ITrcPacket* pkt) override {
379*288bf522SAndroid Build Coastguard Worker return element_decoders_[trace_id].PacketDataIn(op, index_sop, pkt);
380*288bf522SAndroid Build Coastguard Worker }
381*288bf522SAndroid Build Coastguard Worker
TraceElemIn(const ocsd_trc_index_t index_sop,uint8_t trc_chan_id,const OcsdTraceElement & elem)382*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
383*288bf522SAndroid Build Coastguard Worker const OcsdTraceElement& elem) override {
384*288bf522SAndroid Build Coastguard Worker for (auto& callback : callbacks_) {
385*288bf522SAndroid Build Coastguard Worker auto resp =
386*288bf522SAndroid Build Coastguard Worker callback->ProcessElement(index_sop, trc_chan_id, elem, instruction_decoder_.instr_info);
387*288bf522SAndroid Build Coastguard Worker if (IsRespError(resp)) {
388*288bf522SAndroid Build Coastguard Worker return resp;
389*288bf522SAndroid Build Coastguard Worker }
390*288bf522SAndroid Build Coastguard Worker }
391*288bf522SAndroid Build Coastguard Worker return OCSD_RESP_CONT;
392*288bf522SAndroid Build Coastguard Worker }
393*288bf522SAndroid Build Coastguard Worker
394*288bf522SAndroid Build Coastguard Worker private:
395*288bf522SAndroid Build Coastguard Worker // map from trace id of an etm device to its element decoder
396*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, TrcPktDecodeEtmV4I> element_decoders_;
397*288bf522SAndroid Build Coastguard Worker MemAccess mem_access_;
398*288bf522SAndroid Build Coastguard Worker InstructionDecoder instruction_decoder_;
399*288bf522SAndroid Build Coastguard Worker std::vector<ElementCallback*> callbacks_;
400*288bf522SAndroid Build Coastguard Worker };
401*288bf522SAndroid Build Coastguard Worker
402*288bf522SAndroid Build Coastguard Worker // Dump etm data generated at different stages.
403*288bf522SAndroid Build Coastguard Worker class DataDumper : public ElementCallback {
404*288bf522SAndroid Build Coastguard Worker public:
DataDumper(ETMV4IDecodeTree & decode_tree)405*288bf522SAndroid Build Coastguard Worker DataDumper(ETMV4IDecodeTree& decode_tree) : decode_tree_(decode_tree) {}
406*288bf522SAndroid Build Coastguard Worker
DumpRawData()407*288bf522SAndroid Build Coastguard Worker void DumpRawData() {
408*288bf522SAndroid Build Coastguard Worker decode_tree_.AttachRawFramePrinter(frame_printer_);
409*288bf522SAndroid Build Coastguard Worker frame_printer_.setMessageLogger(&stdout_logger_);
410*288bf522SAndroid Build Coastguard Worker }
411*288bf522SAndroid Build Coastguard Worker
DumpPackets(const std::unordered_map<uint8_t,std::unique_ptr<EtmV4Config>> & configs)412*288bf522SAndroid Build Coastguard Worker void DumpPackets(const std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs) {
413*288bf522SAndroid Build Coastguard Worker for (auto& p : configs) {
414*288bf522SAndroid Build Coastguard Worker uint8_t trace_id = p.first;
415*288bf522SAndroid Build Coastguard Worker auto result = packet_printers_.emplace(trace_id, trace_id);
416*288bf522SAndroid Build Coastguard Worker CHECK(result.second);
417*288bf522SAndroid Build Coastguard Worker auto& packet_printer = result.first->second;
418*288bf522SAndroid Build Coastguard Worker decode_tree_.AttachPacketMonitor(trace_id, packet_printer);
419*288bf522SAndroid Build Coastguard Worker packet_printer.setMessageLogger(&stdout_logger_);
420*288bf522SAndroid Build Coastguard Worker }
421*288bf522SAndroid Build Coastguard Worker }
422*288bf522SAndroid Build Coastguard Worker
DumpElements()423*288bf522SAndroid Build Coastguard Worker void DumpElements() { element_printer_.setMessageLogger(&stdout_logger_); }
424*288bf522SAndroid Build Coastguard Worker
ProcessElement(ocsd_trc_index_t index_sop,uint8_t trc_chan_id,const OcsdTraceElement & elem,const ocsd_instr_info *)425*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
426*288bf522SAndroid Build Coastguard Worker const OcsdTraceElement& elem, const ocsd_instr_info*) {
427*288bf522SAndroid Build Coastguard Worker return element_printer_.TraceElemIn(index_sop, trc_chan_id, elem);
428*288bf522SAndroid Build Coastguard Worker }
429*288bf522SAndroid Build Coastguard Worker
430*288bf522SAndroid Build Coastguard Worker private:
431*288bf522SAndroid Build Coastguard Worker ETMV4IDecodeTree& decode_tree_;
432*288bf522SAndroid Build Coastguard Worker RawFramePrinter frame_printer_;
433*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, PacketPrinter<EtmV4ITrcPacket>> packet_printers_;
434*288bf522SAndroid Build Coastguard Worker TrcGenericElementPrinter element_printer_;
435*288bf522SAndroid Build Coastguard Worker ocsdMsgLogger stdout_logger_;
436*288bf522SAndroid Build Coastguard Worker };
437*288bf522SAndroid Build Coastguard Worker
438*288bf522SAndroid Build Coastguard Worker // It decodes each ETMV4IPacket into TraceElements, and generates ETMInstrRanges from TraceElements.
439*288bf522SAndroid Build Coastguard Worker // Decoding each packet is slow, but ensures correctness.
440*288bf522SAndroid Build Coastguard Worker class InstrRangeParser : public ElementCallback {
441*288bf522SAndroid Build Coastguard Worker private:
442*288bf522SAndroid Build Coastguard Worker struct TraceData {
443*288bf522SAndroid Build Coastguard Worker ETMInstrRange instr_range;
444*288bf522SAndroid Build Coastguard Worker bool wait_for_branch_to_addr_fix = false;
445*288bf522SAndroid Build Coastguard Worker };
446*288bf522SAndroid Build Coastguard Worker
447*288bf522SAndroid Build Coastguard Worker public:
InstrRangeParser(MapLocator & map_locator,const ETMDecoder::InstrRangeCallbackFn & callback)448*288bf522SAndroid Build Coastguard Worker InstrRangeParser(MapLocator& map_locator, const ETMDecoder::InstrRangeCallbackFn& callback)
449*288bf522SAndroid Build Coastguard Worker : map_locator_(map_locator), callback_(callback) {}
450*288bf522SAndroid Build Coastguard Worker
ProcessElement(const ocsd_trc_index_t,uint8_t trace_id,const OcsdTraceElement & elem,const ocsd_instr_info * next_instr)451*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t ProcessElement(const ocsd_trc_index_t, uint8_t trace_id,
452*288bf522SAndroid Build Coastguard Worker const OcsdTraceElement& elem,
453*288bf522SAndroid Build Coastguard Worker const ocsd_instr_info* next_instr) override {
454*288bf522SAndroid Build Coastguard Worker if (elem.getType() == OCSD_GEN_TRC_ELEM_INSTR_RANGE) {
455*288bf522SAndroid Build Coastguard Worker TraceData& data = trace_data_[trace_id];
456*288bf522SAndroid Build Coastguard Worker const MapEntry* map = map_locator_.FindMap(trace_id, elem.st_addr);
457*288bf522SAndroid Build Coastguard Worker if (map == nullptr) {
458*288bf522SAndroid Build Coastguard Worker FlushData(data);
459*288bf522SAndroid Build Coastguard Worker return OCSD_RESP_CONT;
460*288bf522SAndroid Build Coastguard Worker }
461*288bf522SAndroid Build Coastguard Worker uint64_t start_addr = map->GetVaddrInFile(elem.st_addr);
462*288bf522SAndroid Build Coastguard Worker auto& instr_range = data.instr_range;
463*288bf522SAndroid Build Coastguard Worker
464*288bf522SAndroid Build Coastguard Worker if (data.wait_for_branch_to_addr_fix) {
465*288bf522SAndroid Build Coastguard Worker // OpenCSD may cache a list of InstrRange elements, making it inaccurate to get branch to
466*288bf522SAndroid Build Coastguard Worker // address from next_instr->branch_addr. So fix it by using the start address of the next
467*288bf522SAndroid Build Coastguard Worker // InstrRange element.
468*288bf522SAndroid Build Coastguard Worker instr_range.branch_to_addr = start_addr;
469*288bf522SAndroid Build Coastguard Worker }
470*288bf522SAndroid Build Coastguard Worker FlushData(data);
471*288bf522SAndroid Build Coastguard Worker instr_range.dso = map->dso;
472*288bf522SAndroid Build Coastguard Worker instr_range.start_addr = start_addr;
473*288bf522SAndroid Build Coastguard Worker instr_range.end_addr = map->GetVaddrInFile(elem.en_addr - elem.last_instr_sz);
474*288bf522SAndroid Build Coastguard Worker bool end_with_branch =
475*288bf522SAndroid Build Coastguard Worker elem.last_i_type == OCSD_INSTR_BR || elem.last_i_type == OCSD_INSTR_BR_INDIRECT;
476*288bf522SAndroid Build Coastguard Worker bool branch_taken = end_with_branch && elem.last_instr_exec;
477*288bf522SAndroid Build Coastguard Worker if (elem.last_i_type == OCSD_INSTR_BR && branch_taken) {
478*288bf522SAndroid Build Coastguard Worker // It is based on the assumption that we only do immediate branch inside a binary,
479*288bf522SAndroid Build Coastguard Worker // which may not be true for all cases. TODO: http://b/151665001.
480*288bf522SAndroid Build Coastguard Worker instr_range.branch_to_addr = map->GetVaddrInFile(next_instr->branch_addr);
481*288bf522SAndroid Build Coastguard Worker data.wait_for_branch_to_addr_fix = true;
482*288bf522SAndroid Build Coastguard Worker } else {
483*288bf522SAndroid Build Coastguard Worker instr_range.branch_to_addr = 0;
484*288bf522SAndroid Build Coastguard Worker }
485*288bf522SAndroid Build Coastguard Worker instr_range.branch_taken_count = branch_taken ? 1 : 0;
486*288bf522SAndroid Build Coastguard Worker instr_range.branch_not_taken_count = branch_taken ? 0 : 1;
487*288bf522SAndroid Build Coastguard Worker
488*288bf522SAndroid Build Coastguard Worker } else if (elem.getType() == OCSD_GEN_TRC_ELEM_TRACE_ON) {
489*288bf522SAndroid Build Coastguard Worker // According to the ETM Specification, the Trace On element indicates a discontinuity in the
490*288bf522SAndroid Build Coastguard Worker // instruction trace stream. So it cuts the connection between instr ranges.
491*288bf522SAndroid Build Coastguard Worker FlushData(trace_data_[trace_id]);
492*288bf522SAndroid Build Coastguard Worker }
493*288bf522SAndroid Build Coastguard Worker return OCSD_RESP_CONT;
494*288bf522SAndroid Build Coastguard Worker }
495*288bf522SAndroid Build Coastguard Worker
FinishData()496*288bf522SAndroid Build Coastguard Worker void FinishData() {
497*288bf522SAndroid Build Coastguard Worker for (auto& pair : trace_data_) {
498*288bf522SAndroid Build Coastguard Worker FlushData(pair.second);
499*288bf522SAndroid Build Coastguard Worker }
500*288bf522SAndroid Build Coastguard Worker }
501*288bf522SAndroid Build Coastguard Worker
502*288bf522SAndroid Build Coastguard Worker private:
FlushData(TraceData & data)503*288bf522SAndroid Build Coastguard Worker void FlushData(TraceData& data) {
504*288bf522SAndroid Build Coastguard Worker if (data.instr_range.dso != nullptr) {
505*288bf522SAndroid Build Coastguard Worker callback_(data.instr_range);
506*288bf522SAndroid Build Coastguard Worker data.instr_range.dso = nullptr;
507*288bf522SAndroid Build Coastguard Worker }
508*288bf522SAndroid Build Coastguard Worker data.wait_for_branch_to_addr_fix = false;
509*288bf522SAndroid Build Coastguard Worker }
510*288bf522SAndroid Build Coastguard Worker
511*288bf522SAndroid Build Coastguard Worker MapLocator& map_locator_;
512*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, TraceData> trace_data_;
513*288bf522SAndroid Build Coastguard Worker ETMDecoder::InstrRangeCallbackFn callback_;
514*288bf522SAndroid Build Coastguard Worker };
515*288bf522SAndroid Build Coastguard Worker
516*288bf522SAndroid Build Coastguard Worker // It parses ETMBranchLists from ETMV4IPackets.
517*288bf522SAndroid Build Coastguard Worker // It doesn't do element decoding and instruction decoding, thus is about 5 timers faster than
518*288bf522SAndroid Build Coastguard Worker // InstrRangeParser. But some data will be lost when converting ETMBranchLists to InstrRanges:
519*288bf522SAndroid Build Coastguard Worker // 1. InstrRanges described by Except packets (the last instructions executed before exeception,
520*288bf522SAndroid Build Coastguard Worker // about 2%?).
521*288bf522SAndroid Build Coastguard Worker // 2. Branch to addresses of direct branch instructions across binaries.
522*288bf522SAndroid Build Coastguard Worker class BranchListParser : public PacketCallback {
523*288bf522SAndroid Build Coastguard Worker private:
524*288bf522SAndroid Build Coastguard Worker struct TraceData {
525*288bf522SAndroid Build Coastguard Worker uint64_t addr = 0;
526*288bf522SAndroid Build Coastguard Worker uint8_t addr_valid_bits = 0;
527*288bf522SAndroid Build Coastguard Worker uint8_t isa = 0;
528*288bf522SAndroid Build Coastguard Worker bool invalid_branch = false;
529*288bf522SAndroid Build Coastguard Worker ETMBranchList branch;
530*288bf522SAndroid Build Coastguard Worker };
531*288bf522SAndroid Build Coastguard Worker
532*288bf522SAndroid Build Coastguard Worker public:
BranchListParser(MapLocator & map_locator,const ETMDecoder::BranchListCallbackFn & callback)533*288bf522SAndroid Build Coastguard Worker BranchListParser(MapLocator& map_locator, const ETMDecoder::BranchListCallbackFn& callback)
534*288bf522SAndroid Build Coastguard Worker : PacketCallback(BRANCH_LIST_PARSER), map_locator_(map_locator), callback_(callback) {}
535*288bf522SAndroid Build Coastguard Worker
CheckConfigs(std::unordered_map<uint8_t,std::unique_ptr<EtmV4Config>> & configs)536*288bf522SAndroid Build Coastguard Worker void CheckConfigs(std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs) {
537*288bf522SAndroid Build Coastguard Worker // TODO: Current implementation doesn't support non-zero speculation length and return stack.
538*288bf522SAndroid Build Coastguard Worker for (auto& p : configs) {
539*288bf522SAndroid Build Coastguard Worker if (p.second->MaxSpecDepth() > 0) {
540*288bf522SAndroid Build Coastguard Worker LOG(WARNING) << "branch list collection isn't accurate with non-zero speculation length";
541*288bf522SAndroid Build Coastguard Worker break;
542*288bf522SAndroid Build Coastguard Worker }
543*288bf522SAndroid Build Coastguard Worker }
544*288bf522SAndroid Build Coastguard Worker for (auto& p : configs) {
545*288bf522SAndroid Build Coastguard Worker if (p.second->enabledRetStack()) {
546*288bf522SAndroid Build Coastguard Worker LOG(WARNING) << "branch list collection will lose some data with return stack enabled";
547*288bf522SAndroid Build Coastguard Worker break;
548*288bf522SAndroid Build Coastguard Worker }
549*288bf522SAndroid Build Coastguard Worker }
550*288bf522SAndroid Build Coastguard Worker }
551*288bf522SAndroid Build Coastguard Worker
IsAddrPacket(const EtmV4ITrcPacket * pkt)552*288bf522SAndroid Build Coastguard Worker bool IsAddrPacket(const EtmV4ITrcPacket* pkt) {
553*288bf522SAndroid Build Coastguard Worker return pkt->getType() >= ETM4_PKT_I_ADDR_CTXT_L_32IS0 &&
554*288bf522SAndroid Build Coastguard Worker pkt->getType() <= ETM4_PKT_I_ADDR_L_64IS1;
555*288bf522SAndroid Build Coastguard Worker }
556*288bf522SAndroid Build Coastguard Worker
IsAtomPacket(const EtmV4ITrcPacket * pkt)557*288bf522SAndroid Build Coastguard Worker bool IsAtomPacket(const EtmV4ITrcPacket* pkt) { return pkt->getAtom().num > 0; }
558*288bf522SAndroid Build Coastguard Worker
ProcessPacket(uint8_t trace_id,ocsd_datapath_op_t op,ocsd_trc_index_t,const EtmV4ITrcPacket * pkt)559*288bf522SAndroid Build Coastguard Worker ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
560*288bf522SAndroid Build Coastguard Worker ocsd_trc_index_t /*index_sop */,
561*288bf522SAndroid Build Coastguard Worker const EtmV4ITrcPacket* pkt) override {
562*288bf522SAndroid Build Coastguard Worker TraceData& data = trace_data_[trace_id];
563*288bf522SAndroid Build Coastguard Worker if (op == OCSD_OP_DATA) {
564*288bf522SAndroid Build Coastguard Worker if (IsAddrPacket(pkt)) {
565*288bf522SAndroid Build Coastguard Worker // Flush branch when seeing an Addr packet. Because it isn't correct to concatenate
566*288bf522SAndroid Build Coastguard Worker // branches before and after an Addr packet.
567*288bf522SAndroid Build Coastguard Worker FlushBranch(data);
568*288bf522SAndroid Build Coastguard Worker data.addr = pkt->getAddrVal();
569*288bf522SAndroid Build Coastguard Worker data.addr_valid_bits = pkt->v_addr.valid_bits;
570*288bf522SAndroid Build Coastguard Worker data.isa = pkt->getAddrIS();
571*288bf522SAndroid Build Coastguard Worker }
572*288bf522SAndroid Build Coastguard Worker
573*288bf522SAndroid Build Coastguard Worker if (IsAtomPacket(pkt)) {
574*288bf522SAndroid Build Coastguard Worker // An atom packet contains a branch list. We may receive one or more atom packets in a row,
575*288bf522SAndroid Build Coastguard Worker // and need to concatenate them.
576*288bf522SAndroid Build Coastguard Worker ProcessAtomPacket(trace_id, data, pkt);
577*288bf522SAndroid Build Coastguard Worker }
578*288bf522SAndroid Build Coastguard Worker
579*288bf522SAndroid Build Coastguard Worker } else {
580*288bf522SAndroid Build Coastguard Worker // Flush branch when seeing a flush or reset operation.
581*288bf522SAndroid Build Coastguard Worker FlushBranch(data);
582*288bf522SAndroid Build Coastguard Worker if (op == OCSD_OP_RESET) {
583*288bf522SAndroid Build Coastguard Worker data.addr = 0;
584*288bf522SAndroid Build Coastguard Worker data.addr_valid_bits = 0;
585*288bf522SAndroid Build Coastguard Worker data.isa = 0;
586*288bf522SAndroid Build Coastguard Worker data.invalid_branch = false;
587*288bf522SAndroid Build Coastguard Worker }
588*288bf522SAndroid Build Coastguard Worker }
589*288bf522SAndroid Build Coastguard Worker return OCSD_RESP_CONT;
590*288bf522SAndroid Build Coastguard Worker }
591*288bf522SAndroid Build Coastguard Worker
FinishData()592*288bf522SAndroid Build Coastguard Worker void FinishData() {
593*288bf522SAndroid Build Coastguard Worker for (auto& pair : trace_data_) {
594*288bf522SAndroid Build Coastguard Worker FlushBranch(pair.second);
595*288bf522SAndroid Build Coastguard Worker }
596*288bf522SAndroid Build Coastguard Worker }
597*288bf522SAndroid Build Coastguard Worker
598*288bf522SAndroid Build Coastguard Worker private:
ProcessAtomPacket(uint8_t trace_id,TraceData & data,const EtmV4ITrcPacket * pkt)599*288bf522SAndroid Build Coastguard Worker void ProcessAtomPacket(uint8_t trace_id, TraceData& data, const EtmV4ITrcPacket* pkt) {
600*288bf522SAndroid Build Coastguard Worker if (data.invalid_branch) {
601*288bf522SAndroid Build Coastguard Worker return; // Skip atom packets when we think a branch list is invalid.
602*288bf522SAndroid Build Coastguard Worker }
603*288bf522SAndroid Build Coastguard Worker if (data.branch.branch.empty()) {
604*288bf522SAndroid Build Coastguard Worker // This is the first atom packet in a branch list. Check if we have tid and addr info to
605*288bf522SAndroid Build Coastguard Worker // parse it and the following atom packets. If not, mark the branch list as invalid.
606*288bf522SAndroid Build Coastguard Worker if (map_locator_.GetTid(trace_id) == -1 || data.addr_valid_bits == 0) {
607*288bf522SAndroid Build Coastguard Worker data.invalid_branch = true;
608*288bf522SAndroid Build Coastguard Worker return;
609*288bf522SAndroid Build Coastguard Worker }
610*288bf522SAndroid Build Coastguard Worker const MapEntry* map = map_locator_.FindMap(trace_id, data.addr);
611*288bf522SAndroid Build Coastguard Worker if (map == nullptr) {
612*288bf522SAndroid Build Coastguard Worker data.invalid_branch = true;
613*288bf522SAndroid Build Coastguard Worker return;
614*288bf522SAndroid Build Coastguard Worker }
615*288bf522SAndroid Build Coastguard Worker data.branch.dso = map->dso;
616*288bf522SAndroid Build Coastguard Worker data.branch.addr = map->GetVaddrInFile(data.addr);
617*288bf522SAndroid Build Coastguard Worker if (data.isa == 1) { // thumb instruction, mark it in bit 0.
618*288bf522SAndroid Build Coastguard Worker data.branch.addr |= 1;
619*288bf522SAndroid Build Coastguard Worker }
620*288bf522SAndroid Build Coastguard Worker }
621*288bf522SAndroid Build Coastguard Worker uint32_t bits = pkt->atom.En_bits;
622*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < pkt->atom.num; i++) {
623*288bf522SAndroid Build Coastguard Worker data.branch.branch.push_back((bits & 1) == 1);
624*288bf522SAndroid Build Coastguard Worker bits >>= 1;
625*288bf522SAndroid Build Coastguard Worker }
626*288bf522SAndroid Build Coastguard Worker }
627*288bf522SAndroid Build Coastguard Worker
FlushBranch(TraceData & data)628*288bf522SAndroid Build Coastguard Worker void FlushBranch(TraceData& data) {
629*288bf522SAndroid Build Coastguard Worker if (!data.branch.branch.empty()) {
630*288bf522SAndroid Build Coastguard Worker callback_(data.branch);
631*288bf522SAndroid Build Coastguard Worker data.branch.branch.clear();
632*288bf522SAndroid Build Coastguard Worker }
633*288bf522SAndroid Build Coastguard Worker data.invalid_branch = false;
634*288bf522SAndroid Build Coastguard Worker }
635*288bf522SAndroid Build Coastguard Worker
636*288bf522SAndroid Build Coastguard Worker MapLocator& map_locator_;
637*288bf522SAndroid Build Coastguard Worker ETMDecoder::BranchListCallbackFn callback_;
638*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, TraceData> trace_data_;
639*288bf522SAndroid Build Coastguard Worker };
640*288bf522SAndroid Build Coastguard Worker
641*288bf522SAndroid Build Coastguard Worker // Etm data decoding in OpenCSD library has two steps:
642*288bf522SAndroid Build Coastguard Worker // 1. From byte stream to etm packets. Each packet shows an event happened. For example,
643*288bf522SAndroid Build Coastguard Worker // an Address packet shows the cpu is running the instruction at that address, an Atom
644*288bf522SAndroid Build Coastguard Worker // packet shows whether the cpu decides to branch or not.
645*288bf522SAndroid Build Coastguard Worker // 2. From etm packets to trace elements. To generates elements, the decoder needs both etm
646*288bf522SAndroid Build Coastguard Worker // packets and executed binaries. For example, an InstructionRange element needs the decoder
647*288bf522SAndroid Build Coastguard Worker // to find the next branch instruction starting from an address.
648*288bf522SAndroid Build Coastguard Worker //
649*288bf522SAndroid Build Coastguard Worker // ETMDecoderImpl uses OpenCSD library to decode etm data. It has the following properties:
650*288bf522SAndroid Build Coastguard Worker // 1. Supports flexible decoding strategy. It allows installing packet callbacks and element
651*288bf522SAndroid Build Coastguard Worker // callbacks, and decodes to either packets or elements based on requirements.
652*288bf522SAndroid Build Coastguard Worker // 2. Supports dumping data at different stages.
653*288bf522SAndroid Build Coastguard Worker class ETMDecoderImpl : public ETMDecoder {
654*288bf522SAndroid Build Coastguard Worker public:
ETMDecoderImpl(ETMThreadTree & thread_tree)655*288bf522SAndroid Build Coastguard Worker ETMDecoderImpl(ETMThreadTree& thread_tree) : thread_tree_(thread_tree) {
656*288bf522SAndroid Build Coastguard Worker // If the aux record for a thread is processed after it's thread exit record, we can't find
657*288bf522SAndroid Build Coastguard Worker // the thread's maps when processing ETM data. To handle this, disable thread exit records.
658*288bf522SAndroid Build Coastguard Worker thread_tree.DisableThreadExitRecords();
659*288bf522SAndroid Build Coastguard Worker }
660*288bf522SAndroid Build Coastguard Worker
CreateDecodeTree(const AuxTraceInfoRecord & auxtrace_info)661*288bf522SAndroid Build Coastguard Worker void CreateDecodeTree(const AuxTraceInfoRecord& auxtrace_info) {
662*288bf522SAndroid Build Coastguard Worker uint8_t trace_id = 0;
663*288bf522SAndroid Build Coastguard Worker uint64_t* info = auxtrace_info.data->info;
664*288bf522SAndroid Build Coastguard Worker for (int i = 0; i < auxtrace_info.data->nr_cpu; i++) {
665*288bf522SAndroid Build Coastguard Worker if (info[0] == AuxTraceInfoRecord::MAGIC_ETM4) {
666*288bf522SAndroid Build Coastguard Worker auto& etm4 = *reinterpret_cast<AuxTraceInfoRecord::ETM4Info*>(info);
667*288bf522SAndroid Build Coastguard Worker ocsd_etmv4_cfg cfg;
668*288bf522SAndroid Build Coastguard Worker memset(&cfg, 0, sizeof(cfg));
669*288bf522SAndroid Build Coastguard Worker cfg.reg_idr0 = etm4.trcidr0;
670*288bf522SAndroid Build Coastguard Worker cfg.reg_idr1 = etm4.trcidr1;
671*288bf522SAndroid Build Coastguard Worker cfg.reg_idr2 = etm4.trcidr2;
672*288bf522SAndroid Build Coastguard Worker cfg.reg_idr8 = etm4.trcidr8;
673*288bf522SAndroid Build Coastguard Worker cfg.reg_configr = etm4.trcconfigr;
674*288bf522SAndroid Build Coastguard Worker cfg.reg_traceidr = etm4.trctraceidr;
675*288bf522SAndroid Build Coastguard Worker cfg.arch_ver = ARCH_V8;
676*288bf522SAndroid Build Coastguard Worker cfg.core_prof = profile_CortexA;
677*288bf522SAndroid Build Coastguard Worker trace_id = cfg.reg_traceidr & 0x7f;
678*288bf522SAndroid Build Coastguard Worker trace_ids_.emplace(etm4.cpu, trace_id);
679*288bf522SAndroid Build Coastguard Worker configs_.emplace(trace_id, new EtmV4Config(&cfg));
680*288bf522SAndroid Build Coastguard Worker info = reinterpret_cast<uint64_t*>(&etm4 + 1);
681*288bf522SAndroid Build Coastguard Worker } else {
682*288bf522SAndroid Build Coastguard Worker CHECK_EQ(info[0], AuxTraceInfoRecord::MAGIC_ETE);
683*288bf522SAndroid Build Coastguard Worker auto& ete = *reinterpret_cast<AuxTraceInfoRecord::ETEInfo*>(info);
684*288bf522SAndroid Build Coastguard Worker ocsd_ete_cfg cfg;
685*288bf522SAndroid Build Coastguard Worker memset(&cfg, 0, sizeof(cfg));
686*288bf522SAndroid Build Coastguard Worker cfg.reg_idr0 = ete.trcidr0;
687*288bf522SAndroid Build Coastguard Worker cfg.reg_idr1 = ete.trcidr1;
688*288bf522SAndroid Build Coastguard Worker cfg.reg_idr2 = ete.trcidr2;
689*288bf522SAndroid Build Coastguard Worker cfg.reg_idr8 = ete.trcidr8;
690*288bf522SAndroid Build Coastguard Worker cfg.reg_devarch = ete.trcdevarch;
691*288bf522SAndroid Build Coastguard Worker cfg.reg_configr = ete.trcconfigr;
692*288bf522SAndroid Build Coastguard Worker cfg.reg_traceidr = ete.trctraceidr;
693*288bf522SAndroid Build Coastguard Worker cfg.arch_ver = ARCH_AA64;
694*288bf522SAndroid Build Coastguard Worker cfg.core_prof = profile_CortexA;
695*288bf522SAndroid Build Coastguard Worker trace_id = cfg.reg_traceidr & 0x7f;
696*288bf522SAndroid Build Coastguard Worker trace_ids_.emplace(ete.cpu, trace_id);
697*288bf522SAndroid Build Coastguard Worker configs_.emplace(trace_id, new ETEConfig(&cfg));
698*288bf522SAndroid Build Coastguard Worker info = reinterpret_cast<uint64_t*>(&ete + 1);
699*288bf522SAndroid Build Coastguard Worker }
700*288bf522SAndroid Build Coastguard Worker decode_tree_.CreateDecoder(configs_[trace_id].get());
701*288bf522SAndroid Build Coastguard Worker auto result = packet_sinks_.emplace(trace_id, trace_id);
702*288bf522SAndroid Build Coastguard Worker CHECK(result.second);
703*288bf522SAndroid Build Coastguard Worker decode_tree_.AttachPacketSink(trace_id, result.first->second);
704*288bf522SAndroid Build Coastguard Worker }
705*288bf522SAndroid Build Coastguard Worker }
706*288bf522SAndroid Build Coastguard Worker
EnableDump(const ETMDumpOption & option)707*288bf522SAndroid Build Coastguard Worker void EnableDump(const ETMDumpOption& option) override {
708*288bf522SAndroid Build Coastguard Worker dumper_.reset(new DataDumper(decode_tree_));
709*288bf522SAndroid Build Coastguard Worker if (option.dump_raw_data) {
710*288bf522SAndroid Build Coastguard Worker dumper_->DumpRawData();
711*288bf522SAndroid Build Coastguard Worker }
712*288bf522SAndroid Build Coastguard Worker if (option.dump_packets) {
713*288bf522SAndroid Build Coastguard Worker dumper_->DumpPackets(configs_);
714*288bf522SAndroid Build Coastguard Worker }
715*288bf522SAndroid Build Coastguard Worker if (option.dump_elements) {
716*288bf522SAndroid Build Coastguard Worker dumper_->DumpElements();
717*288bf522SAndroid Build Coastguard Worker InstallElementCallback(dumper_.get());
718*288bf522SAndroid Build Coastguard Worker }
719*288bf522SAndroid Build Coastguard Worker }
720*288bf522SAndroid Build Coastguard Worker
RegisterCallback(const InstrRangeCallbackFn & callback)721*288bf522SAndroid Build Coastguard Worker void RegisterCallback(const InstrRangeCallbackFn& callback) {
722*288bf522SAndroid Build Coastguard Worker InstallMapLocator();
723*288bf522SAndroid Build Coastguard Worker instr_range_parser_.reset(new InstrRangeParser(*map_locator_, callback));
724*288bf522SAndroid Build Coastguard Worker InstallElementCallback(instr_range_parser_.get());
725*288bf522SAndroid Build Coastguard Worker }
726*288bf522SAndroid Build Coastguard Worker
RegisterCallback(const BranchListCallbackFn & callback)727*288bf522SAndroid Build Coastguard Worker void RegisterCallback(const BranchListCallbackFn& callback) {
728*288bf522SAndroid Build Coastguard Worker InstallMapLocator();
729*288bf522SAndroid Build Coastguard Worker branch_list_parser_.reset(new BranchListParser(*map_locator_, callback));
730*288bf522SAndroid Build Coastguard Worker branch_list_parser_->CheckConfigs(configs_);
731*288bf522SAndroid Build Coastguard Worker InstallPacketCallback(branch_list_parser_.get());
732*288bf522SAndroid Build Coastguard Worker }
733*288bf522SAndroid Build Coastguard Worker
ProcessData(const uint8_t * data,size_t size,bool formatted,uint32_t cpu)734*288bf522SAndroid Build Coastguard Worker bool ProcessData(const uint8_t* data, size_t size, bool formatted, uint32_t cpu) override {
735*288bf522SAndroid Build Coastguard Worker // Reset decoders before processing each data block. Because:
736*288bf522SAndroid Build Coastguard Worker // 1. Data blocks are not continuous. So decoders shouldn't keep previous states when
737*288bf522SAndroid Build Coastguard Worker // processing a new block.
738*288bf522SAndroid Build Coastguard Worker // 2. The beginning part of a data block may be truncated if kernel buffer is temporarily full.
739*288bf522SAndroid Build Coastguard Worker // So we may see garbage data, which can cause decoding errors if we don't reset decoders.
740*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "Processing " << (!formatted ? "un" : "") << "formatted data with size " << size;
741*288bf522SAndroid Build Coastguard Worker auto& decoder = formatted ? decode_tree_.GetFormattedDataIn()
742*288bf522SAndroid Build Coastguard Worker : decode_tree_.GetUnformattedDataIn(trace_ids_[cpu]);
743*288bf522SAndroid Build Coastguard Worker
744*288bf522SAndroid Build Coastguard Worker auto resp = decoder.TraceDataIn(OCSD_OP_RESET, data_index_, 0, nullptr, nullptr);
745*288bf522SAndroid Build Coastguard Worker if (IsRespError(resp)) {
746*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "failed to reset decoder, resp " << resp;
747*288bf522SAndroid Build Coastguard Worker return false;
748*288bf522SAndroid Build Coastguard Worker }
749*288bf522SAndroid Build Coastguard Worker size_t left_size = size;
750*288bf522SAndroid Build Coastguard Worker const size_t MAX_RESET_RETRY_COUNT = 3;
751*288bf522SAndroid Build Coastguard Worker size_t reset_retry_count = 0;
752*288bf522SAndroid Build Coastguard Worker while (left_size > 0) {
753*288bf522SAndroid Build Coastguard Worker uint32_t processed;
754*288bf522SAndroid Build Coastguard Worker auto resp = decoder.TraceDataIn(OCSD_OP_DATA, data_index_, left_size, data, &processed);
755*288bf522SAndroid Build Coastguard Worker if (IsRespError(resp)) {
756*288bf522SAndroid Build Coastguard Worker // A decoding error shouldn't ruin all data. Reset decoders to recover from it.
757*288bf522SAndroid Build Coastguard Worker // But some errors may not be recoverable by resetting decoders. So use a max retry limit.
758*288bf522SAndroid Build Coastguard Worker if (++reset_retry_count > MAX_RESET_RETRY_COUNT) {
759*288bf522SAndroid Build Coastguard Worker break;
760*288bf522SAndroid Build Coastguard Worker }
761*288bf522SAndroid Build Coastguard Worker LOG(DEBUG) << "reset etm decoders for seeing a decode failure, resp " << resp
762*288bf522SAndroid Build Coastguard Worker << ", reset_retry_count is " << reset_retry_count;
763*288bf522SAndroid Build Coastguard Worker decoder.TraceDataIn(OCSD_OP_RESET, data_index_ + processed, 0, nullptr, nullptr);
764*288bf522SAndroid Build Coastguard Worker }
765*288bf522SAndroid Build Coastguard Worker data += processed;
766*288bf522SAndroid Build Coastguard Worker left_size -= processed;
767*288bf522SAndroid Build Coastguard Worker data_index_ += processed;
768*288bf522SAndroid Build Coastguard Worker }
769*288bf522SAndroid Build Coastguard Worker return true;
770*288bf522SAndroid Build Coastguard Worker }
771*288bf522SAndroid Build Coastguard Worker
FinishData()772*288bf522SAndroid Build Coastguard Worker bool FinishData() override {
773*288bf522SAndroid Build Coastguard Worker if (instr_range_parser_) {
774*288bf522SAndroid Build Coastguard Worker instr_range_parser_->FinishData();
775*288bf522SAndroid Build Coastguard Worker }
776*288bf522SAndroid Build Coastguard Worker if (branch_list_parser_) {
777*288bf522SAndroid Build Coastguard Worker branch_list_parser_->FinishData();
778*288bf522SAndroid Build Coastguard Worker }
779*288bf522SAndroid Build Coastguard Worker return true;
780*288bf522SAndroid Build Coastguard Worker }
781*288bf522SAndroid Build Coastguard Worker
782*288bf522SAndroid Build Coastguard Worker private:
InstallMapLocator()783*288bf522SAndroid Build Coastguard Worker void InstallMapLocator() {
784*288bf522SAndroid Build Coastguard Worker if (!map_locator_) {
785*288bf522SAndroid Build Coastguard Worker map_locator_.reset(new MapLocator(thread_tree_));
786*288bf522SAndroid Build Coastguard Worker for (auto& cfg : configs_) {
787*288bf522SAndroid Build Coastguard Worker int64_t configr = (*(const ocsd_etmv4_cfg*)*cfg.second).reg_configr;
788*288bf522SAndroid Build Coastguard Worker map_locator_->SetUseVmid(cfg.first,
789*288bf522SAndroid Build Coastguard Worker configr & (1U << ETM4_CFG_BIT_VMID | 1U << ETM4_CFG_BIT_VMID_OPT));
790*288bf522SAndroid Build Coastguard Worker }
791*288bf522SAndroid Build Coastguard Worker
792*288bf522SAndroid Build Coastguard Worker InstallPacketCallback(map_locator_.get());
793*288bf522SAndroid Build Coastguard Worker }
794*288bf522SAndroid Build Coastguard Worker }
795*288bf522SAndroid Build Coastguard Worker
InstallPacketCallback(PacketCallback * callback)796*288bf522SAndroid Build Coastguard Worker void InstallPacketCallback(PacketCallback* callback) {
797*288bf522SAndroid Build Coastguard Worker for (auto& p : packet_sinks_) {
798*288bf522SAndroid Build Coastguard Worker p.second.AddCallback(callback);
799*288bf522SAndroid Build Coastguard Worker }
800*288bf522SAndroid Build Coastguard Worker }
801*288bf522SAndroid Build Coastguard Worker
InstallElementCallback(ElementCallback * callback)802*288bf522SAndroid Build Coastguard Worker void InstallElementCallback(ElementCallback* callback) {
803*288bf522SAndroid Build Coastguard Worker if (!packet_to_element_) {
804*288bf522SAndroid Build Coastguard Worker InstallMapLocator();
805*288bf522SAndroid Build Coastguard Worker packet_to_element_.reset(
806*288bf522SAndroid Build Coastguard Worker new PacketToElement(*map_locator_, configs_, decode_tree_.ErrorLogger()));
807*288bf522SAndroid Build Coastguard Worker InstallPacketCallback(packet_to_element_.get());
808*288bf522SAndroid Build Coastguard Worker }
809*288bf522SAndroid Build Coastguard Worker packet_to_element_->AddCallback(callback);
810*288bf522SAndroid Build Coastguard Worker }
811*288bf522SAndroid Build Coastguard Worker
812*288bf522SAndroid Build Coastguard Worker // map ip address to binary path and binary offset
813*288bf522SAndroid Build Coastguard Worker ETMThreadTree& thread_tree_;
814*288bf522SAndroid Build Coastguard Worker // handle to build OpenCSD decoder
815*288bf522SAndroid Build Coastguard Worker ETMV4IDecodeTree decode_tree_;
816*288bf522SAndroid Build Coastguard Worker // map from cpu to trace id
817*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint64_t, uint8_t> trace_ids_;
818*288bf522SAndroid Build Coastguard Worker // map from the trace id of an etm device to its config
819*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>> configs_;
820*288bf522SAndroid Build Coastguard Worker // map from the trace id of an etm device to its PacketSink
821*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint8_t, PacketSink> packet_sinks_;
822*288bf522SAndroid Build Coastguard Worker std::unique_ptr<PacketToElement> packet_to_element_;
823*288bf522SAndroid Build Coastguard Worker std::unique_ptr<DataDumper> dumper_;
824*288bf522SAndroid Build Coastguard Worker // an index keeping processed etm data size
825*288bf522SAndroid Build Coastguard Worker size_t data_index_ = 0;
826*288bf522SAndroid Build Coastguard Worker std::unique_ptr<InstrRangeParser> instr_range_parser_;
827*288bf522SAndroid Build Coastguard Worker std::unique_ptr<MapLocator> map_locator_;
828*288bf522SAndroid Build Coastguard Worker std::unique_ptr<BranchListParser> branch_list_parser_;
829*288bf522SAndroid Build Coastguard Worker };
830*288bf522SAndroid Build Coastguard Worker
831*288bf522SAndroid Build Coastguard Worker } // namespace
832*288bf522SAndroid Build Coastguard Worker
ParseEtmDumpOption(const std::string & s,ETMDumpOption * option)833*288bf522SAndroid Build Coastguard Worker bool ParseEtmDumpOption(const std::string& s, ETMDumpOption* option) {
834*288bf522SAndroid Build Coastguard Worker for (auto& value : android::base::Split(s, ",")) {
835*288bf522SAndroid Build Coastguard Worker if (value == "raw") {
836*288bf522SAndroid Build Coastguard Worker option->dump_raw_data = true;
837*288bf522SAndroid Build Coastguard Worker } else if (value == "packet") {
838*288bf522SAndroid Build Coastguard Worker option->dump_packets = true;
839*288bf522SAndroid Build Coastguard Worker } else if (value == "element") {
840*288bf522SAndroid Build Coastguard Worker option->dump_elements = true;
841*288bf522SAndroid Build Coastguard Worker } else {
842*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "unknown etm dump option: " << value;
843*288bf522SAndroid Build Coastguard Worker return false;
844*288bf522SAndroid Build Coastguard Worker }
845*288bf522SAndroid Build Coastguard Worker }
846*288bf522SAndroid Build Coastguard Worker return true;
847*288bf522SAndroid Build Coastguard Worker }
848*288bf522SAndroid Build Coastguard Worker
Create(const AuxTraceInfoRecord & auxtrace_info,ETMThreadTree & thread_tree)849*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ETMDecoder> ETMDecoder::Create(const AuxTraceInfoRecord& auxtrace_info,
850*288bf522SAndroid Build Coastguard Worker ETMThreadTree& thread_tree) {
851*288bf522SAndroid Build Coastguard Worker auto decoder = std::make_unique<ETMDecoderImpl>(thread_tree);
852*288bf522SAndroid Build Coastguard Worker decoder->CreateDecodeTree(auxtrace_info);
853*288bf522SAndroid Build Coastguard Worker return std::unique_ptr<ETMDecoder>(decoder.release());
854*288bf522SAndroid Build Coastguard Worker }
855*288bf522SAndroid Build Coastguard Worker
856*288bf522SAndroid Build Coastguard Worker // Use OpenCSD instruction decoder to convert branches to instruction addresses.
857*288bf522SAndroid Build Coastguard Worker class BranchDecoder {
858*288bf522SAndroid Build Coastguard Worker public:
Init(Dso * dso)859*288bf522SAndroid Build Coastguard Worker android::base::expected<void, std::string> Init(Dso* dso) {
860*288bf522SAndroid Build Coastguard Worker ElfStatus status;
861*288bf522SAndroid Build Coastguard Worker elf_ = ElfFile::Open(dso->GetDebugFilePath(), &status);
862*288bf522SAndroid Build Coastguard Worker if (!elf_) {
863*288bf522SAndroid Build Coastguard Worker std::stringstream ss;
864*288bf522SAndroid Build Coastguard Worker ss << status;
865*288bf522SAndroid Build Coastguard Worker return android::base::unexpected(ss.str());
866*288bf522SAndroid Build Coastguard Worker }
867*288bf522SAndroid Build Coastguard Worker if (dso->type() == DSO_KERNEL_MODULE) {
868*288bf522SAndroid Build Coastguard Worker // Kernel module doesn't have program header. So create a fake one mapping to .text section.
869*288bf522SAndroid Build Coastguard Worker for (const auto& section : elf_->GetSectionHeader()) {
870*288bf522SAndroid Build Coastguard Worker if (section.name == ".text") {
871*288bf522SAndroid Build Coastguard Worker segments_.resize(1);
872*288bf522SAndroid Build Coastguard Worker segments_[0].is_executable = true;
873*288bf522SAndroid Build Coastguard Worker segments_[0].is_load = true;
874*288bf522SAndroid Build Coastguard Worker segments_[0].file_offset = section.file_offset;
875*288bf522SAndroid Build Coastguard Worker segments_[0].file_size = section.size;
876*288bf522SAndroid Build Coastguard Worker segments_[0].vaddr = section.vaddr;
877*288bf522SAndroid Build Coastguard Worker break;
878*288bf522SAndroid Build Coastguard Worker }
879*288bf522SAndroid Build Coastguard Worker }
880*288bf522SAndroid Build Coastguard Worker } else {
881*288bf522SAndroid Build Coastguard Worker segments_ = elf_->GetProgramHeader();
882*288bf522SAndroid Build Coastguard Worker auto it = std::remove_if(segments_.begin(), segments_.end(),
883*288bf522SAndroid Build Coastguard Worker [](const ElfSegment& s) { return !s.is_executable; });
884*288bf522SAndroid Build Coastguard Worker segments_.resize(it - segments_.begin());
885*288bf522SAndroid Build Coastguard Worker }
886*288bf522SAndroid Build Coastguard Worker if (segments_.empty()) {
887*288bf522SAndroid Build Coastguard Worker return android::base::unexpected("no segments");
888*288bf522SAndroid Build Coastguard Worker }
889*288bf522SAndroid Build Coastguard Worker buffer_ = elf_->GetMemoryBuffer();
890*288bf522SAndroid Build Coastguard Worker return {};
891*288bf522SAndroid Build Coastguard Worker }
892*288bf522SAndroid Build Coastguard Worker
SetAddr(uint64_t addr,bool is_thumb)893*288bf522SAndroid Build Coastguard Worker void SetAddr(uint64_t addr, bool is_thumb) {
894*288bf522SAndroid Build Coastguard Worker memset(&instr_info_, 0, sizeof(instr_info_));
895*288bf522SAndroid Build Coastguard Worker instr_info_.pe_type.arch = ARCH_V8;
896*288bf522SAndroid Build Coastguard Worker instr_info_.pe_type.profile = profile_CortexA;
897*288bf522SAndroid Build Coastguard Worker instr_info_.isa =
898*288bf522SAndroid Build Coastguard Worker elf_->Is64Bit() ? ocsd_isa_aarch64 : (is_thumb ? ocsd_isa_thumb2 : ocsd_isa_arm);
899*288bf522SAndroid Build Coastguard Worker instr_info_.instr_addr = addr;
900*288bf522SAndroid Build Coastguard Worker }
901*288bf522SAndroid Build Coastguard Worker
FindNextBranch()902*288bf522SAndroid Build Coastguard Worker bool FindNextBranch() {
903*288bf522SAndroid Build Coastguard Worker // Loop until we find a branch instruction.
904*288bf522SAndroid Build Coastguard Worker while (ReadMem(instr_info_.instr_addr, 4, &instr_info_.opcode)) {
905*288bf522SAndroid Build Coastguard Worker ocsd_err_t err = instruction_decoder_.DecodeInstruction(&instr_info_);
906*288bf522SAndroid Build Coastguard Worker if (err != OCSD_OK) {
907*288bf522SAndroid Build Coastguard Worker break;
908*288bf522SAndroid Build Coastguard Worker }
909*288bf522SAndroid Build Coastguard Worker if (instr_info_.type != OCSD_INSTR_OTHER) {
910*288bf522SAndroid Build Coastguard Worker return true;
911*288bf522SAndroid Build Coastguard Worker }
912*288bf522SAndroid Build Coastguard Worker instr_info_.instr_addr += instr_info_.instr_size;
913*288bf522SAndroid Build Coastguard Worker }
914*288bf522SAndroid Build Coastguard Worker return false;
915*288bf522SAndroid Build Coastguard Worker };
916*288bf522SAndroid Build Coastguard Worker
InstrInfo()917*288bf522SAndroid Build Coastguard Worker ocsd_instr_info& InstrInfo() { return instr_info_; }
918*288bf522SAndroid Build Coastguard Worker
919*288bf522SAndroid Build Coastguard Worker private:
ReadMem(uint64_t vaddr,size_t size,void * data)920*288bf522SAndroid Build Coastguard Worker bool ReadMem(uint64_t vaddr, size_t size, void* data) {
921*288bf522SAndroid Build Coastguard Worker for (auto& segment : segments_) {
922*288bf522SAndroid Build Coastguard Worker if (vaddr >= segment.vaddr && vaddr + size <= segment.vaddr + segment.file_size) {
923*288bf522SAndroid Build Coastguard Worker uint64_t offset = vaddr - segment.vaddr + segment.file_offset;
924*288bf522SAndroid Build Coastguard Worker memcpy(data, buffer_->getBufferStart() + offset, size);
925*288bf522SAndroid Build Coastguard Worker return true;
926*288bf522SAndroid Build Coastguard Worker }
927*288bf522SAndroid Build Coastguard Worker }
928*288bf522SAndroid Build Coastguard Worker return false;
929*288bf522SAndroid Build Coastguard Worker }
930*288bf522SAndroid Build Coastguard Worker
931*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ElfFile> elf_;
932*288bf522SAndroid Build Coastguard Worker std::vector<ElfSegment> segments_;
933*288bf522SAndroid Build Coastguard Worker llvm::MemoryBuffer* buffer_ = nullptr;
934*288bf522SAndroid Build Coastguard Worker ocsd_instr_info instr_info_;
935*288bf522SAndroid Build Coastguard Worker InstructionDecoder instruction_decoder_;
936*288bf522SAndroid Build Coastguard Worker };
937*288bf522SAndroid Build Coastguard Worker
ConvertETMBranchMapToInstrRanges(Dso * dso,const ETMBranchMap & branch_map,const ETMDecoder::InstrRangeCallbackFn & callback)938*288bf522SAndroid Build Coastguard Worker android::base::expected<void, std::string> ConvertETMBranchMapToInstrRanges(
939*288bf522SAndroid Build Coastguard Worker Dso* dso, const ETMBranchMap& branch_map, const ETMDecoder::InstrRangeCallbackFn& callback) {
940*288bf522SAndroid Build Coastguard Worker BranchDecoder decoder;
941*288bf522SAndroid Build Coastguard Worker if (auto result = decoder.Init(dso); !result.ok()) {
942*288bf522SAndroid Build Coastguard Worker return result;
943*288bf522SAndroid Build Coastguard Worker }
944*288bf522SAndroid Build Coastguard Worker
945*288bf522SAndroid Build Coastguard Worker struct MapEntry {
946*288bf522SAndroid Build Coastguard Worker bool valid = false;
947*288bf522SAndroid Build Coastguard Worker bool end_with_branch = false;
948*288bf522SAndroid Build Coastguard Worker bool end_with_direct_branch = false;
949*288bf522SAndroid Build Coastguard Worker uint32_t end_instr_size = 0;
950*288bf522SAndroid Build Coastguard Worker uint64_t end_addr = 0;
951*288bf522SAndroid Build Coastguard Worker uint64_t branch_addr = 0;
952*288bf522SAndroid Build Coastguard Worker uint64_t branch_taken_count = 0;
953*288bf522SAndroid Build Coastguard Worker uint64_t branch_not_taken_count = 0;
954*288bf522SAndroid Build Coastguard Worker };
955*288bf522SAndroid Build Coastguard Worker std::unordered_map<uint64_t, MapEntry> cache;
956*288bf522SAndroid Build Coastguard Worker
957*288bf522SAndroid Build Coastguard Worker for (const auto& addr_p : branch_map) {
958*288bf522SAndroid Build Coastguard Worker for (const auto& branch_p : addr_p.second) {
959*288bf522SAndroid Build Coastguard Worker const std::vector<bool>& branch = branch_p.first;
960*288bf522SAndroid Build Coastguard Worker uint64_t count = branch_p.second;
961*288bf522SAndroid Build Coastguard Worker uint64_t start_addr = addr_p.first & ~1ULL;
962*288bf522SAndroid Build Coastguard Worker bool is_thumb = addr_p.first & 1;
963*288bf522SAndroid Build Coastguard Worker for (bool b : branch) {
964*288bf522SAndroid Build Coastguard Worker auto it = cache.find(start_addr);
965*288bf522SAndroid Build Coastguard Worker if (it == cache.end()) {
966*288bf522SAndroid Build Coastguard Worker MapEntry entry;
967*288bf522SAndroid Build Coastguard Worker decoder.SetAddr(start_addr, is_thumb);
968*288bf522SAndroid Build Coastguard Worker if (decoder.FindNextBranch()) {
969*288bf522SAndroid Build Coastguard Worker ocsd_instr_info& instr = decoder.InstrInfo();
970*288bf522SAndroid Build Coastguard Worker entry.valid = true;
971*288bf522SAndroid Build Coastguard Worker entry.end_with_branch =
972*288bf522SAndroid Build Coastguard Worker instr.type == OCSD_INSTR_BR || instr.type == OCSD_INSTR_BR_INDIRECT;
973*288bf522SAndroid Build Coastguard Worker entry.end_with_direct_branch = instr.type == OCSD_INSTR_BR;
974*288bf522SAndroid Build Coastguard Worker entry.end_addr = instr.instr_addr;
975*288bf522SAndroid Build Coastguard Worker entry.end_instr_size = instr.instr_size;
976*288bf522SAndroid Build Coastguard Worker // For OCSD_INSTR_BR_INDIRECT, instr.branch_addr points to old branch addresses.
977*288bf522SAndroid Build Coastguard Worker // So only use instr.branch_addr for direct branch instructions.
978*288bf522SAndroid Build Coastguard Worker entry.branch_addr = (entry.end_with_direct_branch ? instr.branch_addr : 0);
979*288bf522SAndroid Build Coastguard Worker }
980*288bf522SAndroid Build Coastguard Worker it = cache.emplace(start_addr, entry).first;
981*288bf522SAndroid Build Coastguard Worker }
982*288bf522SAndroid Build Coastguard Worker MapEntry& entry = it->second;
983*288bf522SAndroid Build Coastguard Worker if (!entry.valid) {
984*288bf522SAndroid Build Coastguard Worker break;
985*288bf522SAndroid Build Coastguard Worker }
986*288bf522SAndroid Build Coastguard Worker bool branch_taken = entry.end_with_branch && b;
987*288bf522SAndroid Build Coastguard Worker // As in "Table D4-10 Meaning of Atom elements in AArch64 A64" of ARMv9 manual,
988*288bf522SAndroid Build Coastguard Worker // for branch instructions, b == true means branch taken. But for other instructions
989*288bf522SAndroid Build Coastguard Worker // (like ISB), CPU continus to execute following instructions.
990*288bf522SAndroid Build Coastguard Worker if (branch_taken) {
991*288bf522SAndroid Build Coastguard Worker entry.branch_taken_count += count;
992*288bf522SAndroid Build Coastguard Worker start_addr = entry.branch_addr & ~1ULL;
993*288bf522SAndroid Build Coastguard Worker is_thumb = entry.branch_addr & 1;
994*288bf522SAndroid Build Coastguard Worker } else {
995*288bf522SAndroid Build Coastguard Worker entry.branch_not_taken_count += count;
996*288bf522SAndroid Build Coastguard Worker start_addr = entry.end_addr + entry.end_instr_size;
997*288bf522SAndroid Build Coastguard Worker }
998*288bf522SAndroid Build Coastguard Worker }
999*288bf522SAndroid Build Coastguard Worker }
1000*288bf522SAndroid Build Coastguard Worker }
1001*288bf522SAndroid Build Coastguard Worker
1002*288bf522SAndroid Build Coastguard Worker for (auto& p : cache) {
1003*288bf522SAndroid Build Coastguard Worker uint64_t start_addr = p.first;
1004*288bf522SAndroid Build Coastguard Worker MapEntry& entry = p.second;
1005*288bf522SAndroid Build Coastguard Worker if (entry.valid) {
1006*288bf522SAndroid Build Coastguard Worker ETMInstrRange instr_range;
1007*288bf522SAndroid Build Coastguard Worker instr_range.start_addr = start_addr;
1008*288bf522SAndroid Build Coastguard Worker instr_range.end_addr = entry.end_addr;
1009*288bf522SAndroid Build Coastguard Worker instr_range.branch_to_addr = entry.branch_addr;
1010*288bf522SAndroid Build Coastguard Worker instr_range.branch_taken_count = entry.branch_taken_count;
1011*288bf522SAndroid Build Coastguard Worker instr_range.branch_not_taken_count = entry.branch_not_taken_count;
1012*288bf522SAndroid Build Coastguard Worker callback(instr_range);
1013*288bf522SAndroid Build Coastguard Worker }
1014*288bf522SAndroid Build Coastguard Worker }
1015*288bf522SAndroid Build Coastguard Worker
1016*288bf522SAndroid Build Coastguard Worker return {};
1017*288bf522SAndroid Build Coastguard Worker }
1018*288bf522SAndroid Build Coastguard Worker
1019*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
1020