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