blob: 62fe997cf881ba5b78410e8928b6fdeefa5a594a [file] [log] [blame]
Yabin Cuifc9da9b2019-08-08 18:15:14 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ETMDecoder.h"
18
Yabin Cui16f41ff2021-03-23 14:58:25 -070019#include <sstream>
20
21#include <android-base/expected.h>
Yabin Cuifc9da9b2019-08-08 18:15:14 -070022#include <android-base/logging.h>
23#include <android-base/strings.h>
24#include <llvm/Support/MemoryBuffer.h>
25#include <opencsd.h>
26
Tamas Zsoldos68fa61e2021-05-05 14:42:09 +020027#include "ETMConstants.h"
28
Yabin Cuifaa7b922021-01-11 17:35:57 -080029namespace simpleperf {
Yabin Cuifc9da9b2019-08-08 18:15:14 -070030namespace {
31
32class DecoderLogStr : public ocsdMsgLogStrOutI {
33 public:
Yabin Cuif058ffa2022-02-01 10:24:48 -080034 void printOutStr(const std::string& out_str) override { LOG(DEBUG) << out_str; }
Yabin Cuifc9da9b2019-08-08 18:15:14 -070035};
36
Yabin Cui7d2a6cc2019-10-18 14:01:15 -070037class DecodeErrorLogger : public ocsdDefaultErrorLogger {
38 public:
39 DecodeErrorLogger(const std::function<void(const ocsdError&)>& error_callback)
40 : error_callback_(error_callback) {
41 initErrorLogger(OCSD_ERR_SEV_INFO, false);
42 msg_logger_.setLogOpts(ocsdMsgLogger::OUT_STR_CB);
43 msg_logger_.setStrOutFn(&log_str_);
44 setOutputLogger(&msg_logger_);
Yabin Cuifc9da9b2019-08-08 18:15:14 -070045 }
Yabin Cui7d2a6cc2019-10-18 14:01:15 -070046
47 void LogError(const ocsd_hndl_err_log_t handle, const ocsdError* error) override {
48 ocsdDefaultErrorLogger::LogError(handle, error);
49 if (error != nullptr) {
50 error_callback_(*error);
51 }
52 }
53
54 private:
55 std::function<void(const ocsdError&)> error_callback_;
56 DecoderLogStr log_str_;
57 ocsdMsgLogger msg_logger_;
58};
Yabin Cuifc9da9b2019-08-08 18:15:14 -070059
ThiƩbaud Weksteen4848ee02020-10-23 16:06:59 +020060static bool IsRespError(ocsd_datapath_resp_t resp) {
61 return resp >= OCSD_RESP_ERR_CONT;
62}
Yabin Cuifc9da9b2019-08-08 18:15:14 -070063
64// Used instead of DecodeTree in OpenCSD to avoid linking decoders not for ETMV4 instruction tracing
65// in OpenCSD.
66class ETMV4IDecodeTree {
67 public:
Yabin Cui7d2a6cc2019-10-18 14:01:15 -070068 ETMV4IDecodeTree()
69 : error_logger_(std::bind(&ETMV4IDecodeTree::ProcessError, this, std::placeholders::_1)) {
Yabin Cuifc9da9b2019-08-08 18:15:14 -070070 frame_decoder_.Configure(OCSD_DFRMTR_FRAME_MEM_ALIGN);
Yabin Cui7d2a6cc2019-10-18 14:01:15 -070071 frame_decoder_.getErrLogAttachPt()->attach(&error_logger_);
Yabin Cuifc9da9b2019-08-08 18:15:14 -070072 }
73
Branislav Rankov587fd042021-09-28 21:45:45 +010074 bool CreateDecoder(const EtmV4Config* config) {
75 uint8_t trace_id = config->getTraceID();
Yabin Cuifc9da9b2019-08-08 18:15:14 -070076 auto packet_decoder = std::make_unique<TrcPktProcEtmV4I>(trace_id);
Branislav Rankov587fd042021-09-28 21:45:45 +010077 packet_decoder->setProtocolConfig(config);
Yabin Cui7d2a6cc2019-10-18 14:01:15 -070078 packet_decoder->getErrorLogAttachPt()->replace_first(&error_logger_);
Yabin Cuifc9da9b2019-08-08 18:15:14 -070079 frame_decoder_.getIDStreamAttachPt(trace_id)->attach(packet_decoder.get());
80 auto result = packet_decoders_.emplace(trace_id, packet_decoder.release());
81 if (!result.second) {
82 LOG(ERROR) << "trace id " << trace_id << " has been used";
83 }
84 return result.second;
85 }
86
87 void AttachPacketSink(uint8_t trace_id, IPktDataIn<EtmV4ITrcPacket>& packet_sink) {
88 auto& packet_decoder = packet_decoders_[trace_id];
89 CHECK(packet_decoder);
90 packet_decoder->getPacketOutAttachPt()->replace_first(&packet_sink);
91 }
92
93 void AttachPacketMonitor(uint8_t trace_id, IPktRawDataMon<EtmV4ITrcPacket>& packet_monitor) {
94 auto& packet_decoder = packet_decoders_[trace_id];
95 CHECK(packet_decoder);
96 packet_decoder->getRawPacketMonAttachPt()->replace_first(&packet_monitor);
97 }
98
99 void AttachRawFramePrinter(RawFramePrinter& frame_printer) {
100 frame_decoder_.Configure(frame_decoder_.getConfigFlags() | OCSD_DFRMTR_PACKED_RAW_OUT);
101 frame_decoder_.getTrcRawFrameAttachPt()->replace_first(&frame_printer);
102 }
103
Tamas Zsoldosdd9ff552021-04-23 17:25:00 +0200104 ITrcDataIn& GetFormattedDataIn() { return frame_decoder_; }
105
106 ITrcDataIn& GetUnformattedDataIn(uint8_t trace_id) {
107 auto& decoder = packet_decoders_[trace_id];
108 CHECK(decoder);
109 return *decoder;
110 }
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700111
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700112 void ProcessError(const ocsdError& error) {
113 if (error.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR) {
114 // Found an invalid packet header, following packets for this trace id may also be invalid.
115 // So reset the decoder to find I_ASYNC packet in the data stream.
116 if (auto it = packet_decoders_.find(error.getErrorChanID()); it != packet_decoders_.end()) {
117 auto& packet_decoder = it->second;
118 CHECK(packet_decoder);
119 packet_decoder->TraceDataIn(OCSD_OP_RESET, error.getErrorIndex(), 0, nullptr, nullptr);
120 }
121 }
122 }
123
124 DecodeErrorLogger& ErrorLogger() { return error_logger_; }
125
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700126 private:
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700127 DecodeErrorLogger error_logger_;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700128 TraceFormatterFrameDecoder frame_decoder_;
129 std::unordered_map<uint8_t, std::unique_ptr<TrcPktProcEtmV4I>> packet_decoders_;
130};
131
132// Similar to IPktDataIn<EtmV4ITrcPacket>, but add trace id.
133struct PacketCallback {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700134 // packet callbacks are called in priority order.
135 enum Priority {
136 MAP_LOCATOR,
Yabin Cui193f2382020-04-01 14:30:03 -0700137 BRANCH_LIST_PARSER,
Yabin Cui418ba0d2020-03-24 11:53:39 -0700138 PACKET_TO_ELEMENT,
139 };
140
141 PacketCallback(Priority prio) : priority(prio) {}
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700142 virtual ~PacketCallback() {}
143 virtual ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
144 ocsd_trc_index_t index_sop,
145 const EtmV4ITrcPacket* pkt) = 0;
Yabin Cui418ba0d2020-03-24 11:53:39 -0700146 const Priority priority;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700147};
148
149// Receives packets from a packet decoder in OpenCSD library.
150class PacketSink : public IPktDataIn<EtmV4ITrcPacket> {
151 public:
152 PacketSink(uint8_t trace_id) : trace_id_(trace_id) {}
153
Yabin Cui418ba0d2020-03-24 11:53:39 -0700154 void AddCallback(PacketCallback* callback) {
155 auto it = std::lower_bound(callbacks_.begin(), callbacks_.end(), callback,
156 [](const PacketCallback* c1, const PacketCallback* c2) {
157 return c1->priority < c2->priority;
158 });
159 callbacks_.insert(it, callback);
160 }
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700161
162 ocsd_datapath_resp_t PacketDataIn(ocsd_datapath_op_t op, ocsd_trc_index_t index_sop,
163 const EtmV4ITrcPacket* pkt) override {
164 for (auto& callback : callbacks_) {
165 auto resp = callback->ProcessPacket(trace_id_, op, index_sop, pkt);
166 if (IsRespError(resp)) {
167 return resp;
168 }
169 }
170 return OCSD_RESP_CONT;
171 }
172
173 private:
174 uint8_t trace_id_;
175 std::vector<PacketCallback*> callbacks_;
176};
177
Yabin Cui418ba0d2020-03-24 11:53:39 -0700178// For each trace_id, when given an addr, find the thread and map it belongs to.
179class MapLocator : public PacketCallback {
180 public:
181 MapLocator(ThreadTree& thread_tree)
182 : PacketCallback(PacketCallback::MAP_LOCATOR), thread_tree_(thread_tree) {}
183
184 ThreadTree& GetThreadTree() { return thread_tree_; }
185
Yabin Cui193f2382020-04-01 14:30:03 -0700186 // Return current thread id of a trace_id. If not available, return -1.
ThiƩbaud Weksteen4848ee02020-10-23 16:06:59 +0200187 pid_t GetTid(uint8_t trace_id) const { return trace_data_[trace_id].tid; }
Yabin Cui193f2382020-04-01 14:30:03 -0700188
Yabin Cui418ba0d2020-03-24 11:53:39 -0700189 ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
190 ocsd_trc_index_t index_sop,
191 const EtmV4ITrcPacket* pkt) override {
192 TraceData& data = trace_data_[trace_id];
193 if (op == OCSD_OP_DATA) {
Tamas Zsoldos68fa61e2021-05-05 14:42:09 +0200194 if (pkt != nullptr && ((!data.use_vmid && pkt->getContext().updated_c) ||
195 (data.use_vmid && pkt->getContext().updated_v))) {
196 int32_t new_tid =
197 static_cast<int32_t>(data.use_vmid ? pkt->getContext().VMID : pkt->getContext().ctxtID);
Yabin Cui418ba0d2020-03-24 11:53:39 -0700198 if (data.tid != new_tid) {
199 data.tid = new_tid;
200 data.thread = nullptr;
201 data.userspace_map = nullptr;
202 }
203 }
204 } else if (op == OCSD_OP_RESET) {
205 data.tid = -1;
206 data.thread = nullptr;
207 data.userspace_map = nullptr;
208 }
209 return OCSD_RESP_CONT;
210 }
211
212 const MapEntry* FindMap(uint8_t trace_id, uint64_t addr) {
213 TraceData& data = trace_data_[trace_id];
214 if (data.userspace_map != nullptr && data.userspace_map->Contains(addr)) {
215 return data.userspace_map;
216 }
217 if (data.tid == -1) {
218 return nullptr;
219 }
220 if (data.thread == nullptr) {
221 data.thread = thread_tree_.FindThread(data.tid);
222 if (data.thread == nullptr) {
223 return nullptr;
224 }
225 }
226 data.userspace_map = data.thread->maps->FindMapByAddr(addr);
227 if (data.userspace_map != nullptr) {
228 return data.userspace_map;
229 }
230 // We don't cache kernel map. Because kernel map can start from 0 and overlap all userspace
231 // maps.
232 return thread_tree_.GetKernelMaps().FindMapByAddr(addr);
233 }
234
Tamas Zsoldos68fa61e2021-05-05 14:42:09 +0200235 void SetUseVmid(uint8_t trace_id, bool value) { trace_data_[trace_id].use_vmid = value; }
236
Yabin Cui418ba0d2020-03-24 11:53:39 -0700237 private:
238 struct TraceData {
239 int32_t tid = -1; // thread id, -1 if invalid
240 const ThreadEntry* thread = nullptr;
241 const MapEntry* userspace_map = nullptr;
Tamas Zsoldos68fa61e2021-05-05 14:42:09 +0200242 bool use_vmid = false; // use vmid for PID
Yabin Cui418ba0d2020-03-24 11:53:39 -0700243 };
244
245 ThreadTree& thread_tree_;
246 TraceData trace_data_[256];
247};
248
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700249// Map (trace_id, ip address) to (binary_path, binary_offset), and read binary files.
250class MemAccess : public ITargetMemAccess {
251 public:
Yabin Cui418ba0d2020-03-24 11:53:39 -0700252 MemAccess(MapLocator& map_locator) : map_locator_(map_locator) {}
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700253
Yabin Cui418ba0d2020-03-24 11:53:39 -0700254 ocsd_err_t ReadTargetMemory(const ocsd_vaddr_t address, uint8_t trace_id, ocsd_mem_space_acc_t,
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700255 uint32_t* num_bytes, uint8_t* p_buffer) override {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700256 TraceData& data = trace_data_[trace_id];
257 const MapEntry* map = map_locator_.FindMap(trace_id, address);
258 // fast path
259 if (map != nullptr && map == data.buffer_map && address >= data.buffer_start &&
260 address + *num_bytes <= data.buffer_end) {
261 if (data.buffer == nullptr) {
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700262 *num_bytes = 0;
263 } else {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700264 memcpy(p_buffer, data.buffer + (address - data.buffer_start), *num_bytes);
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700265 }
266 return OCSD_OK;
267 }
268
Yabin Cui418ba0d2020-03-24 11:53:39 -0700269 // slow path
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700270 size_t copy_size = 0;
Yabin Cui418ba0d2020-03-24 11:53:39 -0700271 if (map != nullptr) {
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700272 llvm::MemoryBuffer* memory = GetMemoryBuffer(map->dso);
273 if (memory != nullptr) {
Yabin Cui7078c672020-11-10 16:24:12 -0800274 if (auto opt_offset = map->dso->IpToFileOffset(address, map->start_addr, map->pgoff);
275 opt_offset) {
276 uint64_t offset = opt_offset.value();
277 size_t file_size = memory->getBufferSize();
278 copy_size = file_size > offset ? std::min<size_t>(file_size - offset, *num_bytes) : 0;
279 if (copy_size > 0) {
280 memcpy(p_buffer, memory->getBufferStart() + offset, copy_size);
281 }
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700282 }
283 }
284 // Update the last buffer cache.
Yabin Cui7078c672020-11-10 16:24:12 -0800285 // Don't cache for the kernel map. Because simpleperf doesn't record an accurate kernel end
286 // addr.
287 if (!map->in_kernel) {
288 data.buffer_map = map;
289 data.buffer = memory == nullptr ? nullptr : (memory->getBufferStart() + map->pgoff);
290 data.buffer_start = map->start_addr;
291 data.buffer_end = map->get_end_addr();
292 }
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700293 }
294 *num_bytes = copy_size;
295 return OCSD_OK;
296 }
297
298 private:
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700299 llvm::MemoryBuffer* GetMemoryBuffer(Dso* dso) {
Yabin Cui02e20332020-03-16 19:38:23 -0700300 auto it = elf_map_.find(dso);
301 if (it == elf_map_.end()) {
302 ElfStatus status;
303 auto res = elf_map_.emplace(dso, ElfFile::Open(dso->GetDebugFilePath(), &status));
304 it = res.first;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700305 }
Yabin Cui02e20332020-03-16 19:38:23 -0700306 return it->second ? it->second->GetMemoryBuffer() : nullptr;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700307 }
308
Yabin Cui418ba0d2020-03-24 11:53:39 -0700309 struct TraceData {
310 const MapEntry* buffer_map = nullptr;
311 const char* buffer = nullptr;
312 uint64_t buffer_start = 0;
313 uint64_t buffer_end = 0;
314 };
315
316 MapLocator& map_locator_;
Yabin Cui02e20332020-03-16 19:38:23 -0700317 std::unordered_map<Dso*, std::unique_ptr<ElfFile>> elf_map_;
Yabin Cui418ba0d2020-03-24 11:53:39 -0700318 TraceData trace_data_[256];
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700319};
320
321class InstructionDecoder : public TrcIDecode {
322 public:
323 ocsd_err_t DecodeInstruction(ocsd_instr_info* instr_info) {
324 this->instr_info = instr_info;
325 return TrcIDecode::DecodeInstruction(instr_info);
326 }
327
328 ocsd_instr_info* instr_info;
329};
330
331// Similar to ITrcGenElemIn, but add next instruction info, which is needed to get branch to addr
332// for an InstructionRange element.
333struct ElementCallback {
334 public:
335 virtual ~ElementCallback(){};
336 virtual ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trace_id,
337 const OcsdTraceElement& elem,
338 const ocsd_instr_info* next_instr) = 0;
339};
340
341// Decode packets into elements.
342class PacketToElement : public PacketCallback, public ITrcGenElemIn {
343 public:
Branislav Rankov587fd042021-09-28 21:45:45 +0100344 PacketToElement(MapLocator& map_locator,
345 const std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs,
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700346 DecodeErrorLogger& error_logger)
Yabin Cui418ba0d2020-03-24 11:53:39 -0700347 : PacketCallback(PacketCallback::PACKET_TO_ELEMENT), mem_access_(map_locator) {
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700348 for (auto& p : configs) {
349 uint8_t trace_id = p.first;
Branislav Rankov587fd042021-09-28 21:45:45 +0100350 const EtmV4Config* config = p.second.get();
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700351 element_decoders_.emplace(trace_id, trace_id);
352 auto& decoder = element_decoders_[trace_id];
Branislav Rankov587fd042021-09-28 21:45:45 +0100353 decoder.setProtocolConfig(config);
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700354 decoder.getErrorLogAttachPt()->replace_first(&error_logger);
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700355 decoder.getInstrDecodeAttachPt()->replace_first(&instruction_decoder_);
356 decoder.getMemoryAccessAttachPt()->replace_first(&mem_access_);
357 decoder.getTraceElemOutAttachPt()->replace_first(this);
358 }
359 }
360
361 void AddCallback(ElementCallback* callback) { callbacks_.push_back(callback); }
362
363 ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
364 ocsd_trc_index_t index_sop,
365 const EtmV4ITrcPacket* pkt) override {
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700366 return element_decoders_[trace_id].PacketDataIn(op, index_sop, pkt);
367 }
368
369 ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
370 const OcsdTraceElement& elem) override {
371 for (auto& callback : callbacks_) {
372 auto resp =
373 callback->ProcessElement(index_sop, trc_chan_id, elem, instruction_decoder_.instr_info);
374 if (IsRespError(resp)) {
375 return resp;
376 }
377 }
378 return OCSD_RESP_CONT;
379 }
380
381 private:
382 // map from trace id of an etm device to its element decoder
383 std::unordered_map<uint8_t, TrcPktDecodeEtmV4I> element_decoders_;
384 MemAccess mem_access_;
385 InstructionDecoder instruction_decoder_;
386 std::vector<ElementCallback*> callbacks_;
387};
388
389// Dump etm data generated at different stages.
390class DataDumper : public ElementCallback {
391 public:
392 DataDumper(ETMV4IDecodeTree& decode_tree) : decode_tree_(decode_tree) {}
393
394 void DumpRawData() {
395 decode_tree_.AttachRawFramePrinter(frame_printer_);
396 frame_printer_.setMessageLogger(&stdout_logger_);
397 }
398
Branislav Rankov587fd042021-09-28 21:45:45 +0100399 void DumpPackets(const std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs) {
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700400 for (auto& p : configs) {
401 uint8_t trace_id = p.first;
402 auto result = packet_printers_.emplace(trace_id, trace_id);
403 CHECK(result.second);
404 auto& packet_printer = result.first->second;
405 decode_tree_.AttachPacketMonitor(trace_id, packet_printer);
406 packet_printer.setMessageLogger(&stdout_logger_);
407 }
408 }
409
410 void DumpElements() { element_printer_.setMessageLogger(&stdout_logger_); }
411
412 ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
413 const OcsdTraceElement& elem, const ocsd_instr_info*) {
414 return element_printer_.TraceElemIn(index_sop, trc_chan_id, elem);
415 }
416
417 private:
418 ETMV4IDecodeTree& decode_tree_;
419 RawFramePrinter frame_printer_;
420 std::unordered_map<uint8_t, PacketPrinter<EtmV4ITrcPacket>> packet_printers_;
421 TrcGenericElementPrinter element_printer_;
422 ocsdMsgLogger stdout_logger_;
423};
424
Yabin Cuic573eaa2019-08-21 16:05:07 -0700425// It decodes each ETMV4IPacket into TraceElements, and generates ETMInstrRanges from TraceElements.
426// Decoding each packet is slow, but ensures correctness.
Yabin Cui418ba0d2020-03-24 11:53:39 -0700427class InstrRangeParser : public ElementCallback {
Yabin Cui2c294912020-03-31 11:59:47 -0700428 private:
429 struct TraceData {
430 ETMInstrRange instr_range;
431 bool wait_for_branch_to_addr_fix = false;
432 };
433
Yabin Cuic573eaa2019-08-21 16:05:07 -0700434 public:
Yabin Cui193f2382020-04-01 14:30:03 -0700435 InstrRangeParser(MapLocator& map_locator, const ETMDecoder::InstrRangeCallbackFn& callback)
Yabin Cui418ba0d2020-03-24 11:53:39 -0700436 : map_locator_(map_locator), callback_(callback) {}
Yabin Cuic573eaa2019-08-21 16:05:07 -0700437
438 ocsd_datapath_resp_t ProcessElement(const ocsd_trc_index_t, uint8_t trace_id,
439 const OcsdTraceElement& elem,
440 const ocsd_instr_info* next_instr) override {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700441 if (elem.getType() == OCSD_GEN_TRC_ELEM_INSTR_RANGE) {
Yabin Cui2c294912020-03-31 11:59:47 -0700442 TraceData& data = trace_data_[trace_id];
Yabin Cui418ba0d2020-03-24 11:53:39 -0700443 const MapEntry* map = map_locator_.FindMap(trace_id, elem.st_addr);
444 if (map == nullptr) {
Yabin Cui2c294912020-03-31 11:59:47 -0700445 FlushData(data);
Yabin Cuic573eaa2019-08-21 16:05:07 -0700446 return OCSD_RESP_CONT;
447 }
Yabin Cui2c294912020-03-31 11:59:47 -0700448 uint64_t start_addr = map->GetVaddrInFile(elem.st_addr);
449 auto& instr_range = data.instr_range;
450
451 if (data.wait_for_branch_to_addr_fix) {
452 // OpenCSD may cache a list of InstrRange elements, making it inaccurate to get branch to
453 // address from next_instr->branch_addr. So fix it by using the start address of the next
454 // InstrRange element.
455 instr_range.branch_to_addr = start_addr;
456 }
457 FlushData(data);
458 instr_range.dso = map->dso;
459 instr_range.start_addr = start_addr;
460 instr_range.end_addr = map->GetVaddrInFile(elem.en_addr - elem.last_instr_sz);
Yabin Cuic573eaa2019-08-21 16:05:07 -0700461 bool end_with_branch =
462 elem.last_i_type == OCSD_INSTR_BR || elem.last_i_type == OCSD_INSTR_BR_INDIRECT;
463 bool branch_taken = end_with_branch && elem.last_instr_exec;
464 if (elem.last_i_type == OCSD_INSTR_BR && branch_taken) {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700465 // It is based on the assumption that we only do immediate branch inside a binary,
466 // which may not be true for all cases. TODO: http://b/151665001.
Yabin Cui2c294912020-03-31 11:59:47 -0700467 instr_range.branch_to_addr = map->GetVaddrInFile(next_instr->branch_addr);
468 data.wait_for_branch_to_addr_fix = true;
Yabin Cuic573eaa2019-08-21 16:05:07 -0700469 } else {
Yabin Cui2c294912020-03-31 11:59:47 -0700470 instr_range.branch_to_addr = 0;
Yabin Cuic573eaa2019-08-21 16:05:07 -0700471 }
Yabin Cui2c294912020-03-31 11:59:47 -0700472 instr_range.branch_taken_count = branch_taken ? 1 : 0;
473 instr_range.branch_not_taken_count = branch_taken ? 0 : 1;
474
475 } else if (elem.getType() == OCSD_GEN_TRC_ELEM_TRACE_ON) {
476 // According to the ETM Specification, the Trace On element indicates a discontinuity in the
477 // instruction trace stream. So it cuts the connection between instr ranges.
478 FlushData(trace_data_[trace_id]);
Yabin Cuic573eaa2019-08-21 16:05:07 -0700479 }
480 return OCSD_RESP_CONT;
481 }
482
Yabin Cui2c294912020-03-31 11:59:47 -0700483 void FinishData() {
484 for (auto& pair : trace_data_) {
485 FlushData(pair.second);
486 }
487 }
488
Yabin Cuic573eaa2019-08-21 16:05:07 -0700489 private:
Yabin Cui2c294912020-03-31 11:59:47 -0700490 void FlushData(TraceData& data) {
491 if (data.instr_range.dso != nullptr) {
492 callback_(data.instr_range);
493 data.instr_range.dso = nullptr;
494 }
495 data.wait_for_branch_to_addr_fix = false;
496 }
497
Yabin Cui418ba0d2020-03-24 11:53:39 -0700498 MapLocator& map_locator_;
Yabin Cui2c294912020-03-31 11:59:47 -0700499 std::unordered_map<uint8_t, TraceData> trace_data_;
Yabin Cui193f2382020-04-01 14:30:03 -0700500 ETMDecoder::InstrRangeCallbackFn callback_;
501};
502
503// It parses ETMBranchLists from ETMV4IPackets.
504// It doesn't do element decoding and instruction decoding, thus is about 5 timers faster than
505// InstrRangeParser. But some data will be lost when converting ETMBranchLists to InstrRanges:
506// 1. InstrRanges described by Except packets (the last instructions executed before exeception,
507// about 2%?).
508// 2. Branch to addresses of direct branch instructions across binaries.
509class BranchListParser : public PacketCallback {
510 private:
511 struct TraceData {
512 uint64_t addr = 0;
513 uint8_t addr_valid_bits = 0;
514 uint8_t isa = 0;
515 bool invalid_branch = false;
516 ETMBranchList branch;
517 };
518
519 public:
520 BranchListParser(MapLocator& map_locator, const ETMDecoder::BranchListCallbackFn& callback)
521 : PacketCallback(BRANCH_LIST_PARSER), map_locator_(map_locator), callback_(callback) {}
522
Branislav Rankov587fd042021-09-28 21:45:45 +0100523 void CheckConfigs(std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs) {
Yabin Cui193f2382020-04-01 14:30:03 -0700524 // TODO: Current implementation doesn't support non-zero speculation length and return stack.
525 for (auto& p : configs) {
Branislav Rankov587fd042021-09-28 21:45:45 +0100526 if (p.second->MaxSpecDepth() > 0) {
Yabin Cui193f2382020-04-01 14:30:03 -0700527 LOG(WARNING) << "branch list collection isn't accurate with non-zero speculation length";
528 break;
529 }
530 }
531 for (auto& p : configs) {
Branislav Rankov587fd042021-09-28 21:45:45 +0100532 if (p.second->enabledRetStack()) {
Yabin Cui193f2382020-04-01 14:30:03 -0700533 LOG(WARNING) << "branch list collection will lose some data with return stack enabled";
534 break;
535 }
536 }
537 }
538
539 bool IsAddrPacket(const EtmV4ITrcPacket* pkt) {
540 return pkt->getType() >= ETM4_PKT_I_ADDR_CTXT_L_32IS0 &&
541 pkt->getType() <= ETM4_PKT_I_ADDR_L_64IS1;
542 }
543
544 bool IsAtomPacket(const EtmV4ITrcPacket* pkt) { return pkt->getAtom().num > 0; }
545
546 ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
547 ocsd_trc_index_t /*index_sop */,
548 const EtmV4ITrcPacket* pkt) override {
549 TraceData& data = trace_data_[trace_id];
550 if (op == OCSD_OP_DATA) {
551 if (IsAddrPacket(pkt)) {
552 // Flush branch when seeing an Addr packet. Because it isn't correct to concatenate
553 // branches before and after an Addr packet.
554 FlushBranch(data);
555 data.addr = pkt->getAddrVal();
556 data.addr_valid_bits = pkt->v_addr.valid_bits;
557 data.isa = pkt->getAddrIS();
558 }
559
560 if (IsAtomPacket(pkt)) {
561 // An atom packet contains a branch list. We may receive one or more atom packets in a row,
562 // and need to concatenate them.
563 ProcessAtomPacket(trace_id, data, pkt);
564 }
565
566 } else {
567 // Flush branch when seeing a flush or reset operation.
568 FlushBranch(data);
569 if (op == OCSD_OP_RESET) {
570 data.addr = 0;
571 data.addr_valid_bits = 0;
572 data.isa = 0;
573 data.invalid_branch = false;
574 }
575 }
576 return OCSD_RESP_CONT;
577 }
578
579 void FinishData() {
580 for (auto& pair : trace_data_) {
581 FlushBranch(pair.second);
582 }
583 }
584
585 private:
586 void ProcessAtomPacket(uint8_t trace_id, TraceData& data, const EtmV4ITrcPacket* pkt) {
587 if (data.invalid_branch) {
588 return; // Skip atom packets when we think a branch list is invalid.
589 }
590 if (data.branch.branch.empty()) {
591 // This is the first atom packet in a branch list. Check if we have tid and addr info to
592 // parse it and the following atom packets. If not, mark the branch list as invalid.
593 if (map_locator_.GetTid(trace_id) == -1 || data.addr_valid_bits == 0) {
594 data.invalid_branch = true;
595 return;
596 }
597 const MapEntry* map = map_locator_.FindMap(trace_id, data.addr);
598 if (map == nullptr) {
599 data.invalid_branch = true;
600 return;
601 }
602 data.branch.dso = map->dso;
603 data.branch.addr = map->GetVaddrInFile(data.addr);
604 if (data.isa == 1) { // thumb instruction, mark it in bit 0.
605 data.branch.addr |= 1;
606 }
607 }
608 uint32_t bits = pkt->atom.En_bits;
609 for (size_t i = 0; i < pkt->atom.num; i++) {
610 data.branch.branch.push_back((bits & 1) == 1);
611 bits >>= 1;
612 }
613 }
614
615 void FlushBranch(TraceData& data) {
616 if (!data.branch.branch.empty()) {
617 callback_(data.branch);
618 data.branch.branch.clear();
619 }
620 data.invalid_branch = false;
621 }
622
623 MapLocator& map_locator_;
624 ETMDecoder::BranchListCallbackFn callback_;
625 std::unordered_map<uint8_t, TraceData> trace_data_;
Yabin Cuic573eaa2019-08-21 16:05:07 -0700626};
627
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700628// Etm data decoding in OpenCSD library has two steps:
629// 1. From byte stream to etm packets. Each packet shows an event happened. For example,
630// an Address packet shows the cpu is running the instruction at that address, an Atom
631// packet shows whether the cpu decides to branch or not.
632// 2. From etm packets to trace elements. To generates elements, the decoder needs both etm
633// packets and executed binaries. For example, an InstructionRange element needs the decoder
634// to find the next branch instruction starting from an address.
635//
636// ETMDecoderImpl uses OpenCSD library to decode etm data. It has the following properties:
637// 1. Supports flexible decoding strategy. It allows installing packet callbacks and element
638// callbacks, and decodes to either packets or elements based on requirements.
639// 2. Supports dumping data at different stages.
640class ETMDecoderImpl : public ETMDecoder {
641 public:
642 ETMDecoderImpl(ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
643
644 void CreateDecodeTree(const AuxTraceInfoRecord& auxtrace_info) {
Branislav Rankov587fd042021-09-28 21:45:45 +0100645 uint8_t trace_id = 0;
646 uint64_t* info = auxtrace_info.data->info;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700647 for (int i = 0; i < auxtrace_info.data->nr_cpu; i++) {
Branislav Rankov587fd042021-09-28 21:45:45 +0100648 if (info[0] == AuxTraceInfoRecord::MAGIC_ETM4) {
649 auto& etm4 = *reinterpret_cast<AuxTraceInfoRecord::ETM4Info*>(info);
650 ocsd_etmv4_cfg cfg;
651 memset(&cfg, 0, sizeof(cfg));
652 cfg.reg_idr0 = etm4.trcidr0;
653 cfg.reg_idr1 = etm4.trcidr1;
654 cfg.reg_idr2 = etm4.trcidr2;
655 cfg.reg_idr8 = etm4.trcidr8;
656 cfg.reg_configr = etm4.trcconfigr;
657 cfg.reg_traceidr = etm4.trctraceidr;
658 cfg.arch_ver = ARCH_V8;
659 cfg.core_prof = profile_CortexA;
660 trace_id = cfg.reg_traceidr & 0x7f;
661 trace_ids_.emplace(etm4.cpu, trace_id);
662 configs_.emplace(trace_id, new EtmV4Config(&cfg));
663 info = reinterpret_cast<uint64_t*>(&etm4 + 1);
664 } else {
665 CHECK_EQ(info[0], AuxTraceInfoRecord::MAGIC_ETE);
666 auto& ete = *reinterpret_cast<AuxTraceInfoRecord::ETEInfo*>(info);
667 ocsd_ete_cfg cfg;
668 memset(&cfg, 0, sizeof(cfg));
669 cfg.reg_idr0 = ete.trcidr0;
670 cfg.reg_idr1 = ete.trcidr1;
671 cfg.reg_idr2 = ete.trcidr2;
672 cfg.reg_idr8 = ete.trcidr8;
673 cfg.reg_devarch = ete.trcdevarch;
674 cfg.reg_configr = ete.trcconfigr;
675 cfg.reg_traceidr = ete.trctraceidr;
676 cfg.arch_ver = ARCH_AA64;
677 cfg.core_prof = profile_CortexA;
678 trace_id = cfg.reg_traceidr & 0x7f;
679 trace_ids_.emplace(ete.cpu, trace_id);
680 configs_.emplace(trace_id, new ETEConfig(&cfg));
681 info = reinterpret_cast<uint64_t*>(&ete + 1);
682 }
683 decode_tree_.CreateDecoder(configs_[trace_id].get());
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700684 auto result = packet_sinks_.emplace(trace_id, trace_id);
685 CHECK(result.second);
686 decode_tree_.AttachPacketSink(trace_id, result.first->second);
687 }
688 }
689
690 void EnableDump(const ETMDumpOption& option) override {
691 dumper_.reset(new DataDumper(decode_tree_));
692 if (option.dump_raw_data) {
693 dumper_->DumpRawData();
694 }
695 if (option.dump_packets) {
696 dumper_->DumpPackets(configs_);
697 }
698 if (option.dump_elements) {
699 dumper_->DumpElements();
700 InstallElementCallback(dumper_.get());
701 }
702 }
703
Yabin Cui193f2382020-04-01 14:30:03 -0700704 void RegisterCallback(const InstrRangeCallbackFn& callback) {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700705 InstallMapLocator();
706 instr_range_parser_.reset(new InstrRangeParser(*map_locator_, callback));
707 InstallElementCallback(instr_range_parser_.get());
Yabin Cuic573eaa2019-08-21 16:05:07 -0700708 }
709
ThiƩbaud Weksteen4848ee02020-10-23 16:06:59 +0200710 void RegisterCallback(const BranchListCallbackFn& callback) {
Yabin Cui193f2382020-04-01 14:30:03 -0700711 InstallMapLocator();
712 branch_list_parser_.reset(new BranchListParser(*map_locator_, callback));
713 branch_list_parser_->CheckConfigs(configs_);
714 InstallPacketCallback(branch_list_parser_.get());
715 }
716
Tamas Zsoldosdd9ff552021-04-23 17:25:00 +0200717 bool ProcessData(const uint8_t* data, size_t size, bool formatted, uint32_t cpu) override {
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700718 // Reset decoders before processing each data block. Because:
719 // 1. Data blocks are not continuous. So decoders shouldn't keep previous states when
720 // processing a new block.
721 // 2. The beginning part of a data block may be truncated if kernel buffer is temporarily full.
722 // So we may see garbage data, which can cause decoding errors if we don't reset decoders.
Tamas Zsoldosdd9ff552021-04-23 17:25:00 +0200723 LOG(DEBUG) << "Processing " << (!formatted ? "un" : "") << "formatted data with size " << size;
724 auto& decoder = formatted ? decode_tree_.GetFormattedDataIn()
725 : decode_tree_.GetUnformattedDataIn(trace_ids_[cpu]);
726
727 auto resp = decoder.TraceDataIn(OCSD_OP_RESET, data_index_, 0, nullptr, nullptr);
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700728 if (IsRespError(resp)) {
729 LOG(ERROR) << "failed to reset decoder, resp " << resp;
730 return false;
731 }
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700732 size_t left_size = size;
Yabin Cui930b6a82022-03-07 14:29:16 -0800733 const size_t MAX_RESET_RETRY_COUNT = 3;
734 size_t reset_retry_count = 0;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700735 while (left_size > 0) {
736 uint32_t processed;
Tamas Zsoldosdd9ff552021-04-23 17:25:00 +0200737 auto resp = decoder.TraceDataIn(OCSD_OP_DATA, data_index_, left_size, data, &processed);
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700738 if (IsRespError(resp)) {
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700739 // A decoding error shouldn't ruin all data. Reset decoders to recover from it.
Yabin Cui930b6a82022-03-07 14:29:16 -0800740 // But some errors may not be recoverable by resetting decoders. So use a max retry limit.
741 if (++reset_retry_count > MAX_RESET_RETRY_COUNT) {
742 break;
743 }
744 LOG(DEBUG) << "reset etm decoders for seeing a decode failure, resp " << resp
745 << ", reset_retry_count is " << reset_retry_count;
Tamas Zsoldosdd9ff552021-04-23 17:25:00 +0200746 decoder.TraceDataIn(OCSD_OP_RESET, data_index_ + processed, 0, nullptr, nullptr);
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700747 }
748 data += processed;
749 left_size -= processed;
750 data_index_ += processed;
751 }
752 return true;
753 }
754
Yabin Cui2c294912020-03-31 11:59:47 -0700755 bool FinishData() override {
756 if (instr_range_parser_) {
757 instr_range_parser_->FinishData();
758 }
Yabin Cui193f2382020-04-01 14:30:03 -0700759 if (branch_list_parser_) {
760 branch_list_parser_->FinishData();
761 }
Yabin Cui2c294912020-03-31 11:59:47 -0700762 return true;
763 }
764
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700765 private:
Yabin Cui418ba0d2020-03-24 11:53:39 -0700766 void InstallMapLocator() {
767 if (!map_locator_) {
768 map_locator_.reset(new MapLocator(thread_tree_));
Tamas Zsoldos68fa61e2021-05-05 14:42:09 +0200769 for (auto& cfg : configs_) {
Branislav Rankov587fd042021-09-28 21:45:45 +0100770 int64_t configr = (*(const ocsd_etmv4_cfg*)*cfg.second).reg_configr;
Yabin Cuif058ffa2022-02-01 10:24:48 -0800771 map_locator_->SetUseVmid(cfg.first,
772 configr & (1U << ETM4_CFG_BIT_VMID | 1U << ETM4_CFG_BIT_VMID_OPT));
Tamas Zsoldos68fa61e2021-05-05 14:42:09 +0200773 }
774
Yabin Cui418ba0d2020-03-24 11:53:39 -0700775 InstallPacketCallback(map_locator_.get());
776 }
777 }
778
779 void InstallPacketCallback(PacketCallback* callback) {
780 for (auto& p : packet_sinks_) {
781 p.second.AddCallback(callback);
782 }
783 }
784
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700785 void InstallElementCallback(ElementCallback* callback) {
786 if (!packet_to_element_) {
Yabin Cui418ba0d2020-03-24 11:53:39 -0700787 InstallMapLocator();
Yabin Cui7d2a6cc2019-10-18 14:01:15 -0700788 packet_to_element_.reset(
Yabin Cui418ba0d2020-03-24 11:53:39 -0700789 new PacketToElement(*map_locator_, configs_, decode_tree_.ErrorLogger()));
790 InstallPacketCallback(packet_to_element_.get());
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700791 }
792 packet_to_element_->AddCallback(callback);
793 }
794
795 // map ip address to binary path and binary offset
796 ThreadTree& thread_tree_;
797 // handle to build OpenCSD decoder
798 ETMV4IDecodeTree decode_tree_;
Tamas Zsoldosdd9ff552021-04-23 17:25:00 +0200799 // map from cpu to trace id
800 std::unordered_map<uint64_t, uint8_t> trace_ids_;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700801 // map from the trace id of an etm device to its config
Branislav Rankov587fd042021-09-28 21:45:45 +0100802 std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>> configs_;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700803 // map from the trace id of an etm device to its PacketSink
804 std::unordered_map<uint8_t, PacketSink> packet_sinks_;
805 std::unique_ptr<PacketToElement> packet_to_element_;
806 std::unique_ptr<DataDumper> dumper_;
807 // an index keeping processed etm data size
808 size_t data_index_ = 0;
Yabin Cuic573eaa2019-08-21 16:05:07 -0700809 std::unique_ptr<InstrRangeParser> instr_range_parser_;
Yabin Cui418ba0d2020-03-24 11:53:39 -0700810 std::unique_ptr<MapLocator> map_locator_;
Yabin Cui193f2382020-04-01 14:30:03 -0700811 std::unique_ptr<BranchListParser> branch_list_parser_;
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700812};
813
814} // namespace
815
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700816bool ParseEtmDumpOption(const std::string& s, ETMDumpOption* option) {
817 for (auto& value : android::base::Split(s, ",")) {
818 if (value == "raw") {
819 option->dump_raw_data = true;
820 } else if (value == "packet") {
821 option->dump_packets = true;
822 } else if (value == "element") {
823 option->dump_elements = true;
824 } else {
825 LOG(ERROR) << "unknown etm dump option: " << value;
826 return false;
827 }
828 }
829 return true;
830}
831
832std::unique_ptr<ETMDecoder> ETMDecoder::Create(const AuxTraceInfoRecord& auxtrace_info,
833 ThreadTree& thread_tree) {
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700834 auto decoder = std::make_unique<ETMDecoderImpl>(thread_tree);
835 decoder->CreateDecodeTree(auxtrace_info);
836 return std::unique_ptr<ETMDecoder>(decoder.release());
837}
838
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700839// Use OpenCSD instruction decoder to convert branches to instruction addresses.
840class BranchDecoder {
841 public:
Yabin Cui16f41ff2021-03-23 14:58:25 -0700842 android::base::expected<void, std::string> Init(Dso* dso) {
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700843 ElfStatus status;
844 elf_ = ElfFile::Open(dso->GetDebugFilePath(), &status);
845 if (!elf_) {
Yabin Cui16f41ff2021-03-23 14:58:25 -0700846 std::stringstream ss;
847 ss << status;
848 return android::base::unexpected(ss.str());
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700849 }
Yabin Cui16f41ff2021-03-23 14:58:25 -0700850 if (dso->type() == DSO_KERNEL_MODULE) {
851 // Kernel module doesn't have program header. So create a fake one mapping to .text section.
852 for (const auto& section : elf_->GetSectionHeader()) {
853 if (section.name == ".text") {
854 segments_.resize(1);
855 segments_[0].is_executable = true;
856 segments_[0].is_load = true;
857 segments_[0].file_offset = section.file_offset;
858 segments_[0].file_size = section.size;
859 segments_[0].vaddr = section.vaddr;
860 break;
861 }
862 }
863 } else {
864 segments_ = elf_->GetProgramHeader();
865 auto it = std::remove_if(segments_.begin(), segments_.end(),
866 [](const ElfSegment& s) { return !s.is_executable; });
867 segments_.resize(it - segments_.begin());
868 }
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700869 if (segments_.empty()) {
Yabin Cui16f41ff2021-03-23 14:58:25 -0700870 return android::base::unexpected("no segments");
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700871 }
872 buffer_ = elf_->GetMemoryBuffer();
Yabin Cui16f41ff2021-03-23 14:58:25 -0700873 return {};
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700874 }
875
876 void SetAddr(uint64_t addr, bool is_thumb) {
877 memset(&instr_info_, 0, sizeof(instr_info_));
878 instr_info_.pe_type.arch = ARCH_V8;
879 instr_info_.pe_type.profile = profile_CortexA;
880 instr_info_.isa =
881 elf_->Is64Bit() ? ocsd_isa_aarch64 : (is_thumb ? ocsd_isa_thumb2 : ocsd_isa_arm);
882 instr_info_.instr_addr = addr;
883 }
884
885 bool FindNextBranch() {
886 // Loop until we find a branch instruction.
887 while (ReadMem(instr_info_.instr_addr, 4, &instr_info_.opcode)) {
888 ocsd_err_t err = instruction_decoder_.DecodeInstruction(&instr_info_);
889 if (err != OCSD_OK) {
890 break;
891 }
892 if (instr_info_.type != OCSD_INSTR_OTHER) {
893 return true;
894 }
895 instr_info_.instr_addr += instr_info_.instr_size;
896 }
897 return false;
898 };
899
900 ocsd_instr_info& InstrInfo() { return instr_info_; }
901
902 private:
903 bool ReadMem(uint64_t vaddr, size_t size, void* data) {
904 for (auto& segment : segments_) {
905 if (vaddr >= segment.vaddr && vaddr + size <= segment.vaddr + segment.file_size) {
906 uint64_t offset = vaddr - segment.vaddr + segment.file_offset;
907 memcpy(data, buffer_->getBufferStart() + offset, size);
908 return true;
909 }
910 }
911 return false;
912 }
913
914 std::unique_ptr<ElfFile> elf_;
915 std::vector<ElfSegment> segments_;
916 llvm::MemoryBuffer* buffer_ = nullptr;
917 ocsd_instr_info instr_info_;
918 InstructionDecoder instruction_decoder_;
919};
920
Yabin Cui16f41ff2021-03-23 14:58:25 -0700921android::base::expected<void, std::string> ConvertBranchMapToInstrRanges(
922 Dso* dso, const BranchMap& branch_map, const ETMDecoder::InstrRangeCallbackFn& callback) {
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700923 ETMInstrRange instr_range;
924 instr_range.dso = dso;
925
926 BranchDecoder decoder;
Yabin Cui16f41ff2021-03-23 14:58:25 -0700927 if (auto result = decoder.Init(dso); !result.ok()) {
928 return result;
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700929 }
930
931 for (const auto& addr_p : branch_map) {
932 uint64_t start_addr = addr_p.first & ~1ULL;
933 bool is_thumb = addr_p.first & 1;
934 for (const auto& branch_p : addr_p.second) {
935 const std::vector<bool>& branch = branch_p.first;
936 uint64_t count = branch_p.second;
937 decoder.SetAddr(start_addr, is_thumb);
938
939 for (bool b : branch) {
940 ocsd_instr_info& instr = decoder.InstrInfo();
941 uint64_t from_addr = instr.instr_addr;
942 if (!decoder.FindNextBranch()) {
943 break;
944 }
945 bool end_with_branch = instr.type == OCSD_INSTR_BR || instr.type == OCSD_INSTR_BR_INDIRECT;
946 bool branch_taken = end_with_branch && b;
947 instr_range.start_addr = from_addr;
948 instr_range.end_addr = instr.instr_addr;
949 if (instr.type == OCSD_INSTR_BR) {
950 instr_range.branch_to_addr = instr.branch_addr;
951 } else {
952 instr_range.branch_to_addr = 0;
953 }
954 instr_range.branch_taken_count = branch_taken ? count : 0;
955 instr_range.branch_not_taken_count = branch_taken ? 0 : count;
956
957 callback(instr_range);
958
959 if (b) {
960 instr.instr_addr = instr.branch_addr;
961 } else {
962 instr.instr_addr += instr.instr_size;
963 }
964 }
965 }
966 }
Yabin Cui16f41ff2021-03-23 14:58:25 -0700967 return {};
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700968}
969
Yabin Cuifc9da9b2019-08-08 18:15:14 -0700970} // namespace simpleperf