1 /*
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
19 #include <android-base/logging.h>
20 #include <android-base/strings.h>
21 #include <llvm/Support/MemoryBuffer.h>
22 #include <opencsd.h>
23
24 using namespace simpleperf;
25
26 namespace {
27
28 class DecoderLogStr : public ocsdMsgLogStrOutI {
29 public:
printOutStr(const std::string & out_str)30 void printOutStr(const std::string& out_str) override { LOG(INFO) << out_str; }
31 };
32
33 static ocsdDefaultErrorLogger g_err_logger;
34
InitDecoderLogging()35 static void InitDecoderLogging() {
36 static bool initialized = false;
37 static ocsdMsgLogger msg_logger;
38 static DecoderLogStr log_str;
39 if (!initialized) {
40 msg_logger.setLogOpts(ocsdMsgLogger::OUT_STR_CB);
41 msg_logger.setStrOutFn(&log_str);
42 ocsd_err_severity_t severity = android::base::GetMinimumLogSeverity() <= android::base::DEBUG
43 ? OCSD_ERR_SEV_INFO
44 : OCSD_ERR_SEV_WARN;
45 g_err_logger.initErrorLogger(severity, false);
46 g_err_logger.setOutputLogger(&msg_logger);
47 initialized = true;
48 }
49 }
50
IsRespError(ocsd_datapath_resp_t resp)51 static bool IsRespError(ocsd_datapath_resp_t resp) { return resp >= OCSD_RESP_ERR_CONT; }
52
53 // Used instead of DecodeTree in OpenCSD to avoid linking decoders not for ETMV4 instruction tracing
54 // in OpenCSD.
55 class ETMV4IDecodeTree {
56 public:
ETMV4IDecodeTree()57 ETMV4IDecodeTree() {
58 frame_decoder_.Configure(OCSD_DFRMTR_FRAME_MEM_ALIGN);
59 frame_decoder_.getErrLogAttachPt()->attach(&g_err_logger);
60 }
61
CreateDecoder(const EtmV4Config & config)62 bool CreateDecoder(const EtmV4Config& config) {
63 uint8_t trace_id = config.getTraceID();
64 auto packet_decoder = std::make_unique<TrcPktProcEtmV4I>(trace_id);
65 packet_decoder->setProtocolConfig(&config);
66 packet_decoder->getErrorLogAttachPt()->replace_first(&g_err_logger);
67 frame_decoder_.getIDStreamAttachPt(trace_id)->attach(packet_decoder.get());
68 auto result = packet_decoders_.emplace(trace_id, packet_decoder.release());
69 if (!result.second) {
70 LOG(ERROR) << "trace id " << trace_id << " has been used";
71 }
72 return result.second;
73 }
74
AttachPacketSink(uint8_t trace_id,IPktDataIn<EtmV4ITrcPacket> & packet_sink)75 void AttachPacketSink(uint8_t trace_id, IPktDataIn<EtmV4ITrcPacket>& packet_sink) {
76 auto& packet_decoder = packet_decoders_[trace_id];
77 CHECK(packet_decoder);
78 packet_decoder->getPacketOutAttachPt()->replace_first(&packet_sink);
79 }
80
AttachPacketMonitor(uint8_t trace_id,IPktRawDataMon<EtmV4ITrcPacket> & packet_monitor)81 void AttachPacketMonitor(uint8_t trace_id, IPktRawDataMon<EtmV4ITrcPacket>& packet_monitor) {
82 auto& packet_decoder = packet_decoders_[trace_id];
83 CHECK(packet_decoder);
84 packet_decoder->getRawPacketMonAttachPt()->replace_first(&packet_monitor);
85 }
86
AttachRawFramePrinter(RawFramePrinter & frame_printer)87 void AttachRawFramePrinter(RawFramePrinter& frame_printer) {
88 frame_decoder_.Configure(frame_decoder_.getConfigFlags() | OCSD_DFRMTR_PACKED_RAW_OUT);
89 frame_decoder_.getTrcRawFrameAttachPt()->replace_first(&frame_printer);
90 }
91
GetDataIn()92 ITrcDataIn& GetDataIn() { return frame_decoder_; }
93
94 private:
95 TraceFormatterFrameDecoder frame_decoder_;
96 std::unordered_map<uint8_t, std::unique_ptr<TrcPktProcEtmV4I>> packet_decoders_;
97 };
98
99 // Similar to IPktDataIn<EtmV4ITrcPacket>, but add trace id.
100 struct PacketCallback {
~PacketCallback__anond4e7cea80111::PacketCallback101 virtual ~PacketCallback() {}
102 virtual ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
103 ocsd_trc_index_t index_sop,
104 const EtmV4ITrcPacket* pkt) = 0;
105 };
106
107 // Receives packets from a packet decoder in OpenCSD library.
108 class PacketSink : public IPktDataIn<EtmV4ITrcPacket> {
109 public:
PacketSink(uint8_t trace_id)110 PacketSink(uint8_t trace_id) : trace_id_(trace_id) {}
111
AddCallback(PacketCallback * callback)112 void AddCallback(PacketCallback* callback) { callbacks_.push_back(callback); }
113
PacketDataIn(ocsd_datapath_op_t op,ocsd_trc_index_t index_sop,const EtmV4ITrcPacket * pkt)114 ocsd_datapath_resp_t PacketDataIn(ocsd_datapath_op_t op, ocsd_trc_index_t index_sop,
115 const EtmV4ITrcPacket* pkt) override {
116 for (auto& callback : callbacks_) {
117 auto resp = callback->ProcessPacket(trace_id_, op, index_sop, pkt);
118 if (IsRespError(resp)) {
119 return resp;
120 }
121 }
122 return OCSD_RESP_CONT;
123 }
124
125 private:
126 uint8_t trace_id_;
127 std::vector<PacketCallback*> callbacks_;
128 };
129
130 // Map (trace_id, ip address) to (binary_path, binary_offset), and read binary files.
131 class MemAccess : public ITargetMemAccess {
132 public:
MemAccess(ThreadTree & thread_tree)133 MemAccess(ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
134
ProcessPacket(uint8_t trace_id,const EtmV4ITrcPacket * packet)135 void ProcessPacket(uint8_t trace_id, const EtmV4ITrcPacket* packet) {
136 if (packet->getContext().updated_c) {
137 tid_map_[trace_id] = packet->getContext().ctxtID;
138 if (trace_id == trace_id_) {
139 // Invalidate the cached buffer when the last trace stream changes thread.
140 buffer_end_ = 0;
141 }
142 }
143 }
144
ReadTargetMemory(const ocsd_vaddr_t address,uint8_t cs_trace_id,ocsd_mem_space_acc_t,uint32_t * num_bytes,uint8_t * p_buffer)145 ocsd_err_t ReadTargetMemory(const ocsd_vaddr_t address, uint8_t cs_trace_id, ocsd_mem_space_acc_t,
146 uint32_t* num_bytes, uint8_t* p_buffer) override {
147 if (cs_trace_id == trace_id_ && address >= buffer_start_ &&
148 address + *num_bytes <= buffer_end_) {
149 if (buffer_ == nullptr) {
150 *num_bytes = 0;
151 } else {
152 memcpy(p_buffer, buffer_ + (address - buffer_start_), *num_bytes);
153 }
154 return OCSD_OK;
155 }
156
157 size_t copy_size = 0;
158 if (const MapEntry* map = FindMap(cs_trace_id, address); map != nullptr) {
159 llvm::MemoryBuffer* memory = GetMemoryBuffer(map->dso);
160 if (memory != nullptr) {
161 uint64_t offset = address - map->start_addr + map->pgoff;
162 size_t file_size = memory->getBufferSize();
163 copy_size = file_size > offset ? std::min<size_t>(file_size - offset, *num_bytes) : 0;
164 if (copy_size > 0) {
165 memcpy(p_buffer, memory->getBufferStart() + offset, copy_size);
166 }
167 }
168 // Update the last buffer cache.
169 trace_id_ = cs_trace_id;
170 buffer_ = memory == nullptr ? nullptr : (memory->getBufferStart() + map->pgoff);
171 buffer_start_ = map->start_addr;
172 buffer_end_ = map->get_end_addr();
173 }
174 *num_bytes = copy_size;
175 return OCSD_OK;
176 }
177
178 private:
FindMap(uint8_t trace_id,uint64_t address)179 const MapEntry* FindMap(uint8_t trace_id, uint64_t address) {
180 if (auto it = tid_map_.find(trace_id); it != tid_map_.end()) {
181 if (ThreadEntry* thread = thread_tree_.FindThread(it->second); thread != nullptr) {
182 if (const MapEntry* map = thread_tree_.FindMap(thread, address);
183 !thread_tree_.IsUnknownDso(map->dso)) {
184 return map;
185 }
186 }
187 }
188 return nullptr;
189 }
190
GetMemoryBuffer(Dso * dso)191 llvm::MemoryBuffer* GetMemoryBuffer(Dso* dso) {
192 if (auto it = memory_buffers_.find(dso); it != memory_buffers_.end()) {
193 return it->second.get();
194 }
195 auto buffer_or_err = llvm::MemoryBuffer::getFile(dso->GetDebugFilePath());
196 llvm::MemoryBuffer* buffer = buffer_or_err ? buffer_or_err.get().release() : nullptr;
197 memory_buffers_.emplace(dso, buffer);
198 return buffer;
199 }
200
201 // map from trace id to thread id
202 std::unordered_map<uint8_t, pid_t> tid_map_;
203 ThreadTree& thread_tree_;
204 std::unordered_map<Dso*, std::unique_ptr<llvm::MemoryBuffer>> memory_buffers_;
205 // cache of the last buffer
206 uint8_t trace_id_ = 0;
207 const char* buffer_ = nullptr;
208 uint64_t buffer_start_ = 0;
209 uint64_t buffer_end_ = 0;
210 };
211
212 class InstructionDecoder : public TrcIDecode {
213 public:
DecodeInstruction(ocsd_instr_info * instr_info)214 ocsd_err_t DecodeInstruction(ocsd_instr_info* instr_info) {
215 this->instr_info = instr_info;
216 return TrcIDecode::DecodeInstruction(instr_info);
217 }
218
219 ocsd_instr_info* instr_info;
220 };
221
222 // Similar to ITrcGenElemIn, but add next instruction info, which is needed to get branch to addr
223 // for an InstructionRange element.
224 struct ElementCallback {
225 public:
~ElementCallback__anond4e7cea80111::ElementCallback226 virtual ~ElementCallback(){};
227 virtual ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trace_id,
228 const OcsdTraceElement& elem,
229 const ocsd_instr_info* next_instr) = 0;
230 };
231
232 // Decode packets into elements.
233 class PacketToElement : public PacketCallback, public ITrcGenElemIn {
234 public:
PacketToElement(ThreadTree & thread_tree,const std::unordered_map<uint8_t,EtmV4Config> & configs)235 PacketToElement(ThreadTree& thread_tree, const std::unordered_map<uint8_t, EtmV4Config>& configs)
236 : mem_access_(thread_tree) {
237 for (auto& p : configs) {
238 uint8_t trace_id = p.first;
239 const EtmV4Config& config = p.second;
240 element_decoders_.emplace(trace_id, trace_id);
241 auto& decoder = element_decoders_[trace_id];
242 decoder.setProtocolConfig(&config);
243 decoder.getErrorLogAttachPt()->replace_first(&g_err_logger);
244 decoder.getInstrDecodeAttachPt()->replace_first(&instruction_decoder_);
245 decoder.getMemoryAccessAttachPt()->replace_first(&mem_access_);
246 decoder.getTraceElemOutAttachPt()->replace_first(this);
247 }
248 }
249
AddCallback(ElementCallback * callback)250 void AddCallback(ElementCallback* callback) { callbacks_.push_back(callback); }
251
ProcessPacket(uint8_t trace_id,ocsd_datapath_op_t op,ocsd_trc_index_t index_sop,const EtmV4ITrcPacket * pkt)252 ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
253 ocsd_trc_index_t index_sop,
254 const EtmV4ITrcPacket* pkt) override {
255 mem_access_.ProcessPacket(trace_id, pkt);
256 return element_decoders_[trace_id].PacketDataIn(op, index_sop, pkt);
257 }
258
TraceElemIn(const ocsd_trc_index_t index_sop,uint8_t trc_chan_id,const OcsdTraceElement & elem)259 ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
260 const OcsdTraceElement& elem) override {
261 for (auto& callback : callbacks_) {
262 auto resp =
263 callback->ProcessElement(index_sop, trc_chan_id, elem, instruction_decoder_.instr_info);
264 if (IsRespError(resp)) {
265 return resp;
266 }
267 }
268 return OCSD_RESP_CONT;
269 }
270
271 private:
272 // map from trace id of an etm device to its element decoder
273 std::unordered_map<uint8_t, TrcPktDecodeEtmV4I> element_decoders_;
274 MemAccess mem_access_;
275 InstructionDecoder instruction_decoder_;
276 std::vector<ElementCallback*> callbacks_;
277 };
278
279 // Dump etm data generated at different stages.
280 class DataDumper : public ElementCallback {
281 public:
DataDumper(ETMV4IDecodeTree & decode_tree)282 DataDumper(ETMV4IDecodeTree& decode_tree) : decode_tree_(decode_tree) {}
283
DumpRawData()284 void DumpRawData() {
285 decode_tree_.AttachRawFramePrinter(frame_printer_);
286 frame_printer_.setMessageLogger(&stdout_logger_);
287 }
288
DumpPackets(const std::unordered_map<uint8_t,EtmV4Config> & configs)289 void DumpPackets(const std::unordered_map<uint8_t, EtmV4Config>& configs) {
290 for (auto& p : configs) {
291 uint8_t trace_id = p.first;
292 auto result = packet_printers_.emplace(trace_id, trace_id);
293 CHECK(result.second);
294 auto& packet_printer = result.first->second;
295 decode_tree_.AttachPacketMonitor(trace_id, packet_printer);
296 packet_printer.setMessageLogger(&stdout_logger_);
297 }
298 }
299
DumpElements()300 void DumpElements() { element_printer_.setMessageLogger(&stdout_logger_); }
301
ProcessElement(ocsd_trc_index_t index_sop,uint8_t trc_chan_id,const OcsdTraceElement & elem,const ocsd_instr_info *)302 ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
303 const OcsdTraceElement& elem, const ocsd_instr_info*) {
304 return element_printer_.TraceElemIn(index_sop, trc_chan_id, elem);
305 }
306
307 private:
308 ETMV4IDecodeTree& decode_tree_;
309 RawFramePrinter frame_printer_;
310 std::unordered_map<uint8_t, PacketPrinter<EtmV4ITrcPacket>> packet_printers_;
311 TrcGenericElementPrinter element_printer_;
312 ocsdMsgLogger stdout_logger_;
313 };
314
315 // Base class for parsing executed instruction ranges from etm data.
316 class InstrRangeParser {
317 public:
InstrRangeParser(ThreadTree & thread_tree,const ETMDecoder::CallbackFn & callback)318 InstrRangeParser(ThreadTree& thread_tree, const ETMDecoder::CallbackFn& callback)
319 : thread_tree_(thread_tree), callback_(callback) {}
320
~InstrRangeParser()321 virtual ~InstrRangeParser() {}
322
323 protected:
324 ThreadTree& thread_tree_;
325 ETMDecoder::CallbackFn callback_;
326 };
327
328 // It decodes each ETMV4IPacket into TraceElements, and generates ETMInstrRanges from TraceElements.
329 // Decoding each packet is slow, but ensures correctness.
330 class BasicInstrRangeParser : public InstrRangeParser, public ElementCallback {
331 public:
BasicInstrRangeParser(ThreadTree & thread_tree,const ETMDecoder::CallbackFn & callback)332 BasicInstrRangeParser(ThreadTree& thread_tree, const ETMDecoder::CallbackFn& callback)
333 : InstrRangeParser(thread_tree, callback) {}
334
ProcessElement(const ocsd_trc_index_t,uint8_t trace_id,const OcsdTraceElement & elem,const ocsd_instr_info * next_instr)335 ocsd_datapath_resp_t ProcessElement(const ocsd_trc_index_t, uint8_t trace_id,
336 const OcsdTraceElement& elem,
337 const ocsd_instr_info* next_instr) override {
338 if (elem.getType() == OCSD_GEN_TRC_ELEM_PE_CONTEXT) {
339 if (elem.getContext().ctxt_id_valid) {
340 // trace_id is associated with a new thread.
341 pid_t new_tid = elem.getContext().context_id;
342 auto& tid = tid_map_[trace_id];
343 if (tid != new_tid) {
344 tid = new_tid;
345 if (trace_id == current_map_.trace_id) {
346 current_map_.Invalidate();
347 }
348 }
349 }
350 } else if (elem.getType() == OCSD_GEN_TRC_ELEM_INSTR_RANGE) {
351 if (!FindMap(trace_id, elem.st_addr)) {
352 return OCSD_RESP_CONT;
353 }
354 instr_range_.dso = current_map_.map->dso;
355 instr_range_.start_addr = current_map_.ToVaddrInFile(elem.st_addr);
356 instr_range_.end_addr = current_map_.ToVaddrInFile(elem.en_addr - elem.last_instr_sz);
357 bool end_with_branch =
358 elem.last_i_type == OCSD_INSTR_BR || elem.last_i_type == OCSD_INSTR_BR_INDIRECT;
359 bool branch_taken = end_with_branch && elem.last_instr_exec;
360 if (elem.last_i_type == OCSD_INSTR_BR && branch_taken) {
361 instr_range_.branch_to_addr = current_map_.ToVaddrInFile(next_instr->branch_addr);
362 } else {
363 instr_range_.branch_to_addr = 0;
364 }
365 instr_range_.branch_taken_count = branch_taken ? 1 : 0;
366 instr_range_.branch_not_taken_count = branch_taken ? 0 : 1;
367 callback_(instr_range_);
368 }
369 return OCSD_RESP_CONT;
370 }
371
372 private:
373 struct CurrentMap {
374 int trace_id = -1;
375 const MapEntry* map = nullptr;
376 uint64_t addr_in_file = 0;
377
Invalidate__anond4e7cea80111::BasicInstrRangeParser::CurrentMap378 void Invalidate() { trace_id = -1; }
379
IsAddrInMap__anond4e7cea80111::BasicInstrRangeParser::CurrentMap380 bool IsAddrInMap(uint8_t trace_id, uint64_t addr) {
381 return trace_id == this->trace_id && map != nullptr && addr >= map->start_addr &&
382 addr < map->get_end_addr();
383 }
384
ToVaddrInFile__anond4e7cea80111::BasicInstrRangeParser::CurrentMap385 uint64_t ToVaddrInFile(uint64_t addr) {
386 if (addr >= map->start_addr && addr < map->get_end_addr()) {
387 return addr - map->start_addr + addr_in_file;
388 }
389 return 0;
390 }
391 };
392
FindMap(uint8_t trace_id,uint64_t addr)393 bool FindMap(uint8_t trace_id, uint64_t addr) {
394 if (current_map_.IsAddrInMap(trace_id, addr)) {
395 return true;
396 }
397 ThreadEntry* thread = thread_tree_.FindThread(tid_map_[trace_id]);
398 if (thread != nullptr) {
399 const MapEntry* map = thread_tree_.FindMap(thread, addr, false);
400 if (map != nullptr && !thread_tree_.IsUnknownDso(map->dso)) {
401 current_map_.trace_id = trace_id;
402 current_map_.map = map;
403 current_map_.addr_in_file =
404 map->dso->IpToVaddrInFile(map->start_addr, map->start_addr, map->pgoff);
405 return true;
406 }
407 }
408 return false;
409 }
410
411 std::unordered_map<uint8_t, pid_t> tid_map_;
412 CurrentMap current_map_;
413 ETMInstrRange instr_range_;
414 };
415
416 // Etm data decoding in OpenCSD library has two steps:
417 // 1. From byte stream to etm packets. Each packet shows an event happened. For example,
418 // an Address packet shows the cpu is running the instruction at that address, an Atom
419 // packet shows whether the cpu decides to branch or not.
420 // 2. From etm packets to trace elements. To generates elements, the decoder needs both etm
421 // packets and executed binaries. For example, an InstructionRange element needs the decoder
422 // to find the next branch instruction starting from an address.
423 //
424 // ETMDecoderImpl uses OpenCSD library to decode etm data. It has the following properties:
425 // 1. Supports flexible decoding strategy. It allows installing packet callbacks and element
426 // callbacks, and decodes to either packets or elements based on requirements.
427 // 2. Supports dumping data at different stages.
428 class ETMDecoderImpl : public ETMDecoder {
429 public:
ETMDecoderImpl(ThreadTree & thread_tree)430 ETMDecoderImpl(ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
431
CreateDecodeTree(const AuxTraceInfoRecord & auxtrace_info)432 void CreateDecodeTree(const AuxTraceInfoRecord& auxtrace_info) {
433 for (int i = 0; i < auxtrace_info.data->nr_cpu; i++) {
434 auto& etm4 = auxtrace_info.data->etm4_info[i];
435 ocsd_etmv4_cfg cfg;
436 memset(&cfg, 0, sizeof(cfg));
437 cfg.reg_idr0 = etm4.trcidr0;
438 cfg.reg_idr1 = etm4.trcidr1;
439 cfg.reg_idr2 = etm4.trcidr2;
440 cfg.reg_idr8 = etm4.trcidr8;
441 cfg.reg_configr = etm4.trcconfigr;
442 cfg.reg_traceidr = etm4.trctraceidr;
443 cfg.arch_ver = ARCH_V8;
444 cfg.core_prof = profile_CortexA;
445 uint8_t trace_id = cfg.reg_traceidr & 0x7f;
446 configs_.emplace(trace_id, &cfg);
447 decode_tree_.CreateDecoder(configs_[trace_id]);
448 auto result = packet_sinks_.emplace(trace_id, trace_id);
449 CHECK(result.second);
450 decode_tree_.AttachPacketSink(trace_id, result.first->second);
451 }
452 }
453
EnableDump(const ETMDumpOption & option)454 void EnableDump(const ETMDumpOption& option) override {
455 dumper_.reset(new DataDumper(decode_tree_));
456 if (option.dump_raw_data) {
457 dumper_->DumpRawData();
458 }
459 if (option.dump_packets) {
460 dumper_->DumpPackets(configs_);
461 }
462 if (option.dump_elements) {
463 dumper_->DumpElements();
464 InstallElementCallback(dumper_.get());
465 }
466 }
467
RegisterCallback(const CallbackFn & callback)468 void RegisterCallback(const CallbackFn& callback) {
469 auto parser = std::make_unique<BasicInstrRangeParser>(thread_tree_, callback);
470 InstallElementCallback(parser.get());
471 instr_range_parser_.reset(parser.release());
472 }
473
ProcessData(const uint8_t * data,size_t size)474 bool ProcessData(const uint8_t* data, size_t size) override {
475 size_t left_size = size;
476 while (left_size > 0) {
477 uint32_t processed;
478 auto resp = decode_tree_.GetDataIn().TraceDataIn(OCSD_OP_DATA, data_index_, left_size, data,
479 &processed);
480 if (IsRespError(resp)) {
481 LOG(ERROR) << "failed to process etm data, resp " << resp;
482 return false;
483 }
484 data += processed;
485 left_size -= processed;
486 data_index_ += processed;
487 }
488 return true;
489 }
490
491 private:
InstallElementCallback(ElementCallback * callback)492 void InstallElementCallback(ElementCallback* callback) {
493 if (!packet_to_element_) {
494 packet_to_element_.reset(new PacketToElement(thread_tree_, configs_));
495 for (auto& p : packet_sinks_) {
496 p.second.AddCallback(packet_to_element_.get());
497 }
498 }
499 packet_to_element_->AddCallback(callback);
500 }
501
502 // map ip address to binary path and binary offset
503 ThreadTree& thread_tree_;
504 // handle to build OpenCSD decoder
505 ETMV4IDecodeTree decode_tree_;
506 // map from the trace id of an etm device to its config
507 std::unordered_map<uint8_t, EtmV4Config> configs_;
508 // map from the trace id of an etm device to its PacketSink
509 std::unordered_map<uint8_t, PacketSink> packet_sinks_;
510 std::unique_ptr<PacketToElement> packet_to_element_;
511 std::unique_ptr<DataDumper> dumper_;
512 // an index keeping processed etm data size
513 size_t data_index_ = 0;
514 std::unique_ptr<InstrRangeParser> instr_range_parser_;
515 };
516
517 } // namespace
518
519 namespace simpleperf {
520
ParseEtmDumpOption(const std::string & s,ETMDumpOption * option)521 bool ParseEtmDumpOption(const std::string& s, ETMDumpOption* option) {
522 for (auto& value : android::base::Split(s, ",")) {
523 if (value == "raw") {
524 option->dump_raw_data = true;
525 } else if (value == "packet") {
526 option->dump_packets = true;
527 } else if (value == "element") {
528 option->dump_elements = true;
529 } else {
530 LOG(ERROR) << "unknown etm dump option: " << value;
531 return false;
532 }
533 }
534 return true;
535 }
536
Create(const AuxTraceInfoRecord & auxtrace_info,ThreadTree & thread_tree)537 std::unique_ptr<ETMDecoder> ETMDecoder::Create(const AuxTraceInfoRecord& auxtrace_info,
538 ThreadTree& thread_tree) {
539 InitDecoderLogging();
540 auto decoder = std::make_unique<ETMDecoderImpl>(thread_tree);
541 decoder->CreateDecodeTree(auxtrace_info);
542 return std::unique_ptr<ETMDecoder>(decoder.release());
543 }
544
545 } // namespace simpleperf