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:
30   void printOutStr(const std::string& out_str) override { LOG(INFO) << out_str; }
31 };
32 
33 class DecodeErrorLogger : public ocsdDefaultErrorLogger {
34  public:
35   DecodeErrorLogger(const std::function<void(const ocsdError&)>& error_callback)
36       : error_callback_(error_callback) {
37     initErrorLogger(OCSD_ERR_SEV_INFO, false);
38     msg_logger_.setLogOpts(ocsdMsgLogger::OUT_STR_CB);
39     msg_logger_.setStrOutFn(&log_str_);
40     setOutputLogger(&msg_logger_);
41   }
42 
43   void LogError(const ocsd_hndl_err_log_t handle, const ocsdError* error) override {
44     ocsdDefaultErrorLogger::LogError(handle, error);
45     if (error != nullptr) {
46       error_callback_(*error);
47     }
48   }
49 
50  private:
51   std::function<void(const ocsdError&)> error_callback_;
52   DecoderLogStr log_str_;
53   ocsdMsgLogger msg_logger_;
54 };
55 
56 static bool IsRespError(ocsd_datapath_resp_t resp) { return resp >= OCSD_RESP_ERR_CONT; }
57 
58 // Used instead of DecodeTree in OpenCSD to avoid linking decoders not for ETMV4 instruction tracing
59 // in OpenCSD.
60 class ETMV4IDecodeTree {
61  public:
62   ETMV4IDecodeTree()
63       : error_logger_(std::bind(&ETMV4IDecodeTree::ProcessError, this, std::placeholders::_1)) {
64     frame_decoder_.Configure(OCSD_DFRMTR_FRAME_MEM_ALIGN);
65     frame_decoder_.getErrLogAttachPt()->attach(&error_logger_);
66   }
67 
68   bool CreateDecoder(const EtmV4Config& config) {
69     uint8_t trace_id = config.getTraceID();
70     auto packet_decoder = std::make_unique<TrcPktProcEtmV4I>(trace_id);
71     packet_decoder->setProtocolConfig(&config);
72     packet_decoder->getErrorLogAttachPt()->replace_first(&error_logger_);
73     frame_decoder_.getIDStreamAttachPt(trace_id)->attach(packet_decoder.get());
74     auto result = packet_decoders_.emplace(trace_id, packet_decoder.release());
75     if (!result.second) {
76       LOG(ERROR) << "trace id " << trace_id << " has been used";
77     }
78     return result.second;
79   }
80 
81   void AttachPacketSink(uint8_t trace_id, IPktDataIn<EtmV4ITrcPacket>& packet_sink) {
82     auto& packet_decoder = packet_decoders_[trace_id];
83     CHECK(packet_decoder);
84     packet_decoder->getPacketOutAttachPt()->replace_first(&packet_sink);
85   }
86 
87   void AttachPacketMonitor(uint8_t trace_id, IPktRawDataMon<EtmV4ITrcPacket>& packet_monitor) {
88     auto& packet_decoder = packet_decoders_[trace_id];
89     CHECK(packet_decoder);
90     packet_decoder->getRawPacketMonAttachPt()->replace_first(&packet_monitor);
91   }
92 
93   void AttachRawFramePrinter(RawFramePrinter& frame_printer) {
94     frame_decoder_.Configure(frame_decoder_.getConfigFlags() | OCSD_DFRMTR_PACKED_RAW_OUT);
95     frame_decoder_.getTrcRawFrameAttachPt()->replace_first(&frame_printer);
96   }
97 
98   ITrcDataIn& GetDataIn() { return frame_decoder_; }
99 
100   void ProcessError(const ocsdError& error) {
101     if (error.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR) {
102       // Found an invalid packet header, following packets for this trace id may also be invalid.
103       // So reset the decoder to find I_ASYNC packet in the data stream.
104       if (auto it = packet_decoders_.find(error.getErrorChanID()); it != packet_decoders_.end()) {
105         auto& packet_decoder = it->second;
106         CHECK(packet_decoder);
107         packet_decoder->TraceDataIn(OCSD_OP_RESET, error.getErrorIndex(), 0, nullptr, nullptr);
108       }
109     }
110   }
111 
112   DecodeErrorLogger& ErrorLogger() { return error_logger_; }
113 
114  private:
115   DecodeErrorLogger error_logger_;
116   TraceFormatterFrameDecoder frame_decoder_;
117   std::unordered_map<uint8_t, std::unique_ptr<TrcPktProcEtmV4I>> packet_decoders_;
118 };
119 
120 // Similar to IPktDataIn<EtmV4ITrcPacket>, but add trace id.
121 struct PacketCallback {
122   // packet callbacks are called in priority order.
123   enum Priority {
124     MAP_LOCATOR,
125     PACKET_TO_ELEMENT,
126   };
127 
128   PacketCallback(Priority prio) : priority(prio) {}
129   virtual ~PacketCallback() {}
130   virtual ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
131                                              ocsd_trc_index_t index_sop,
132                                              const EtmV4ITrcPacket* pkt) = 0;
133   const Priority priority;
134 };
135 
136 // Receives packets from a packet decoder in OpenCSD library.
137 class PacketSink : public IPktDataIn<EtmV4ITrcPacket> {
138  public:
139   PacketSink(uint8_t trace_id) : trace_id_(trace_id) {}
140 
141   void AddCallback(PacketCallback* callback) {
142     auto it = std::lower_bound(callbacks_.begin(), callbacks_.end(), callback,
143                                [](const PacketCallback* c1, const PacketCallback* c2) {
144                                  return c1->priority < c2->priority;
145                                });
146     callbacks_.insert(it, callback);
147   }
148 
149   ocsd_datapath_resp_t PacketDataIn(ocsd_datapath_op_t op, ocsd_trc_index_t index_sop,
150                                     const EtmV4ITrcPacket* pkt) override {
151     for (auto& callback : callbacks_) {
152       auto resp = callback->ProcessPacket(trace_id_, op, index_sop, pkt);
153       if (IsRespError(resp)) {
154         return resp;
155       }
156     }
157     return OCSD_RESP_CONT;
158   }
159 
160  private:
161   uint8_t trace_id_;
162   std::vector<PacketCallback*> callbacks_;
163 };
164 
165 // For each trace_id, when given an addr, find the thread and map it belongs to.
166 class MapLocator : public PacketCallback {
167  public:
168   MapLocator(ThreadTree& thread_tree)
169       : PacketCallback(PacketCallback::MAP_LOCATOR), thread_tree_(thread_tree) {}
170 
171   ThreadTree& GetThreadTree() { return thread_tree_; }
172 
173   ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
174                                      ocsd_trc_index_t index_sop,
175                                      const EtmV4ITrcPacket* pkt) override {
176     TraceData& data = trace_data_[trace_id];
177     if (op == OCSD_OP_DATA) {
178       if (pkt != nullptr && pkt->getContext().updated_c) {
179         int32_t new_tid = static_cast<int32_t>(pkt->getContext().ctxtID);
180         if (data.tid != new_tid) {
181           data.tid = new_tid;
182           data.thread = nullptr;
183           data.userspace_map = nullptr;
184         }
185       }
186     } else if (op == OCSD_OP_RESET) {
187       data.tid = -1;
188       data.thread = nullptr;
189       data.userspace_map = nullptr;
190     }
191     return OCSD_RESP_CONT;
192   }
193 
194   const MapEntry* FindMap(uint8_t trace_id, uint64_t addr) {
195     TraceData& data = trace_data_[trace_id];
196     if (data.userspace_map != nullptr && data.userspace_map->Contains(addr)) {
197       return data.userspace_map;
198     }
199     if (data.tid == -1) {
200       return nullptr;
201     }
202     if (data.thread == nullptr) {
203       data.thread = thread_tree_.FindThread(data.tid);
204       if (data.thread == nullptr) {
205         return nullptr;
206       }
207     }
208     data.userspace_map = data.thread->maps->FindMapByAddr(addr);
209     if (data.userspace_map != nullptr) {
210       return data.userspace_map;
211     }
212     // We don't cache kernel map. Because kernel map can start from 0 and overlap all userspace
213     // maps.
214     return thread_tree_.GetKernelMaps().FindMapByAddr(addr);
215   }
216 
217  private:
218   struct TraceData {
219     int32_t tid = -1;  // thread id, -1 if invalid
220     const ThreadEntry* thread = nullptr;
221     const MapEntry* userspace_map = nullptr;
222   };
223 
224   ThreadTree& thread_tree_;
225   TraceData trace_data_[256];
226 };
227 
228 // Map (trace_id, ip address) to (binary_path, binary_offset), and read binary files.
229 class MemAccess : public ITargetMemAccess {
230  public:
231   MemAccess(MapLocator& map_locator) : map_locator_(map_locator) {}
232 
233   ocsd_err_t ReadTargetMemory(const ocsd_vaddr_t address, uint8_t trace_id, ocsd_mem_space_acc_t,
234                               uint32_t* num_bytes, uint8_t* p_buffer) override {
235     TraceData& data = trace_data_[trace_id];
236     const MapEntry* map = map_locator_.FindMap(trace_id, address);
237     // fast path
238     if (map != nullptr && map == data.buffer_map && address >= data.buffer_start &&
239         address + *num_bytes <= data.buffer_end) {
240       if (data.buffer == nullptr) {
241         *num_bytes = 0;
242       } else {
243         memcpy(p_buffer, data.buffer + (address - data.buffer_start), *num_bytes);
244       }
245       return OCSD_OK;
246     }
247 
248     // slow path
249     size_t copy_size = 0;
250     if (map != nullptr) {
251       llvm::MemoryBuffer* memory = GetMemoryBuffer(map->dso);
252       if (memory != nullptr) {
253         uint64_t offset = address - map->start_addr + map->pgoff;
254         size_t file_size = memory->getBufferSize();
255         copy_size = file_size > offset ? std::min<size_t>(file_size - offset, *num_bytes) : 0;
256         if (copy_size > 0) {
257           memcpy(p_buffer, memory->getBufferStart() + offset, copy_size);
258         }
259       }
260       // Update the last buffer cache.
261       data.buffer_map = map;
262       data.buffer = memory == nullptr ? nullptr : (memory->getBufferStart() + map->pgoff);
263       data.buffer_start = map->start_addr;
264       data.buffer_end = map->get_end_addr();
265     }
266     *num_bytes = copy_size;
267     return OCSD_OK;
268   }
269 
270  private:
271   llvm::MemoryBuffer* GetMemoryBuffer(Dso* dso) {
272     auto it = elf_map_.find(dso);
273     if (it == elf_map_.end()) {
274       ElfStatus status;
275       auto res = elf_map_.emplace(dso, ElfFile::Open(dso->GetDebugFilePath(), &status));
276       it = res.first;
277     }
278     return it->second ? it->second->GetMemoryBuffer() : nullptr;
279   }
280 
281   struct TraceData {
282     const MapEntry* buffer_map = nullptr;
283     const char* buffer = nullptr;
284     uint64_t buffer_start = 0;
285     uint64_t buffer_end = 0;
286   };
287 
288   MapLocator& map_locator_;
289   std::unordered_map<Dso*, std::unique_ptr<ElfFile>> elf_map_;
290   TraceData trace_data_[256];
291 };
292 
293 class InstructionDecoder : public TrcIDecode {
294  public:
295   ocsd_err_t DecodeInstruction(ocsd_instr_info* instr_info) {
296     this->instr_info = instr_info;
297     return TrcIDecode::DecodeInstruction(instr_info);
298   }
299 
300   ocsd_instr_info* instr_info;
301 };
302 
303 // Similar to ITrcGenElemIn, but add next instruction info, which is needed to get branch to addr
304 // for an InstructionRange element.
305 struct ElementCallback {
306  public:
307   virtual ~ElementCallback(){};
308   virtual ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trace_id,
309                                               const OcsdTraceElement& elem,
310                                               const ocsd_instr_info* next_instr) = 0;
311 };
312 
313 // Decode packets into elements.
314 class PacketToElement : public PacketCallback, public ITrcGenElemIn {
315  public:
316   PacketToElement(MapLocator& map_locator, const std::unordered_map<uint8_t, EtmV4Config>& configs,
317                   DecodeErrorLogger& error_logger)
318       : PacketCallback(PacketCallback::PACKET_TO_ELEMENT), mem_access_(map_locator) {
319     for (auto& p : configs) {
320       uint8_t trace_id = p.first;
321       const EtmV4Config& config = p.second;
322       element_decoders_.emplace(trace_id, trace_id);
323       auto& decoder = element_decoders_[trace_id];
324       decoder.setProtocolConfig(&config);
325       decoder.getErrorLogAttachPt()->replace_first(&error_logger);
326       decoder.getInstrDecodeAttachPt()->replace_first(&instruction_decoder_);
327       decoder.getMemoryAccessAttachPt()->replace_first(&mem_access_);
328       decoder.getTraceElemOutAttachPt()->replace_first(this);
329     }
330   }
331 
332   void AddCallback(ElementCallback* callback) { callbacks_.push_back(callback); }
333 
334   ocsd_datapath_resp_t ProcessPacket(uint8_t trace_id, ocsd_datapath_op_t op,
335                                      ocsd_trc_index_t index_sop,
336                                      const EtmV4ITrcPacket* pkt) override {
337     return element_decoders_[trace_id].PacketDataIn(op, index_sop, pkt);
338   }
339 
340   ocsd_datapath_resp_t TraceElemIn(const ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
341                                    const OcsdTraceElement& elem) override {
342     for (auto& callback : callbacks_) {
343       auto resp =
344           callback->ProcessElement(index_sop, trc_chan_id, elem, instruction_decoder_.instr_info);
345       if (IsRespError(resp)) {
346         return resp;
347       }
348     }
349     return OCSD_RESP_CONT;
350   }
351 
352  private:
353   // map from trace id of an etm device to its element decoder
354   std::unordered_map<uint8_t, TrcPktDecodeEtmV4I> element_decoders_;
355   MemAccess mem_access_;
356   InstructionDecoder instruction_decoder_;
357   std::vector<ElementCallback*> callbacks_;
358 };
359 
360 // Dump etm data generated at different stages.
361 class DataDumper : public ElementCallback {
362  public:
363   DataDumper(ETMV4IDecodeTree& decode_tree) : decode_tree_(decode_tree) {}
364 
365   void DumpRawData() {
366     decode_tree_.AttachRawFramePrinter(frame_printer_);
367     frame_printer_.setMessageLogger(&stdout_logger_);
368   }
369 
370   void DumpPackets(const std::unordered_map<uint8_t, EtmV4Config>& configs) {
371     for (auto& p : configs) {
372       uint8_t trace_id = p.first;
373       auto result = packet_printers_.emplace(trace_id, trace_id);
374       CHECK(result.second);
375       auto& packet_printer = result.first->second;
376       decode_tree_.AttachPacketMonitor(trace_id, packet_printer);
377       packet_printer.setMessageLogger(&stdout_logger_);
378     }
379   }
380 
381   void DumpElements() { element_printer_.setMessageLogger(&stdout_logger_); }
382 
383   ocsd_datapath_resp_t ProcessElement(ocsd_trc_index_t index_sop, uint8_t trc_chan_id,
384                                       const OcsdTraceElement& elem, const ocsd_instr_info*) {
385     return element_printer_.TraceElemIn(index_sop, trc_chan_id, elem);
386   }
387 
388  private:
389   ETMV4IDecodeTree& decode_tree_;
390   RawFramePrinter frame_printer_;
391   std::unordered_map<uint8_t, PacketPrinter<EtmV4ITrcPacket>> packet_printers_;
392   TrcGenericElementPrinter element_printer_;
393   ocsdMsgLogger stdout_logger_;
394 };
395 
396 // It decodes each ETMV4IPacket into TraceElements, and generates ETMInstrRanges from TraceElements.
397 // Decoding each packet is slow, but ensures correctness.
398 class InstrRangeParser : public ElementCallback {
399  private:
400   struct TraceData {
401     ETMInstrRange instr_range;
402     bool wait_for_branch_to_addr_fix = false;
403   };
404 
405  public:
406   InstrRangeParser(MapLocator& map_locator, const ETMDecoder::CallbackFn& callback)
407       : map_locator_(map_locator), callback_(callback) {}
408 
409   ocsd_datapath_resp_t ProcessElement(const ocsd_trc_index_t, uint8_t trace_id,
410                                       const OcsdTraceElement& elem,
411                                       const ocsd_instr_info* next_instr) override {
412     if (elem.getType() == OCSD_GEN_TRC_ELEM_INSTR_RANGE) {
413       TraceData& data = trace_data_[trace_id];
414       const MapEntry* map = map_locator_.FindMap(trace_id, elem.st_addr);
415       if (map == nullptr) {
416         FlushData(data);
417         return OCSD_RESP_CONT;
418       }
419       uint64_t start_addr = map->GetVaddrInFile(elem.st_addr);
420       auto& instr_range = data.instr_range;
421 
422       if (data.wait_for_branch_to_addr_fix) {
423         // OpenCSD may cache a list of InstrRange elements, making it inaccurate to get branch to
424         // address from next_instr->branch_addr. So fix it by using the start address of the next
425         // InstrRange element.
426         instr_range.branch_to_addr = start_addr;
427       }
428       FlushData(data);
429       instr_range.dso = map->dso;
430       instr_range.start_addr = start_addr;
431       instr_range.end_addr = map->GetVaddrInFile(elem.en_addr - elem.last_instr_sz);
432       bool end_with_branch =
433           elem.last_i_type == OCSD_INSTR_BR || elem.last_i_type == OCSD_INSTR_BR_INDIRECT;
434       bool branch_taken = end_with_branch && elem.last_instr_exec;
435       if (elem.last_i_type == OCSD_INSTR_BR && branch_taken) {
436         // It is based on the assumption that we only do immediate branch inside a binary,
437         // which may not be true for all cases. TODO: http://b/151665001.
438         instr_range.branch_to_addr = map->GetVaddrInFile(next_instr->branch_addr);
439         data.wait_for_branch_to_addr_fix = true;
440       } else {
441         instr_range.branch_to_addr = 0;
442       }
443       instr_range.branch_taken_count = branch_taken ? 1 : 0;
444       instr_range.branch_not_taken_count = branch_taken ? 0 : 1;
445 
446     } else if (elem.getType() == OCSD_GEN_TRC_ELEM_TRACE_ON) {
447       // According to the ETM Specification, the Trace On element indicates a discontinuity in the
448       // instruction trace stream. So it cuts the connection between instr ranges.
449       FlushData(trace_data_[trace_id]);
450     }
451     return OCSD_RESP_CONT;
452   }
453 
454   void FinishData() {
455     for (auto& pair : trace_data_) {
456       FlushData(pair.second);
457     }
458   }
459 
460  private:
461   void FlushData(TraceData& data) {
462     if (data.instr_range.dso != nullptr) {
463       callback_(data.instr_range);
464       data.instr_range.dso = nullptr;
465     }
466     data.wait_for_branch_to_addr_fix = false;
467   }
468 
469   MapLocator& map_locator_;
470   std::unordered_map<uint8_t, TraceData> trace_data_;
471   ETMDecoder::CallbackFn callback_;
472 };
473 
474 // Etm data decoding in OpenCSD library has two steps:
475 // 1. From byte stream to etm packets. Each packet shows an event happened. For example,
476 // an Address packet shows the cpu is running the instruction at that address, an Atom
477 // packet shows whether the cpu decides to branch or not.
478 // 2. From etm packets to trace elements. To generates elements, the decoder needs both etm
479 // packets and executed binaries. For example, an InstructionRange element needs the decoder
480 // to find the next branch instruction starting from an address.
481 //
482 // ETMDecoderImpl uses OpenCSD library to decode etm data. It has the following properties:
483 // 1. Supports flexible decoding strategy. It allows installing packet callbacks and element
484 // callbacks, and decodes to either packets or elements based on requirements.
485 // 2. Supports dumping data at different stages.
486 class ETMDecoderImpl : public ETMDecoder {
487  public:
488   ETMDecoderImpl(ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
489 
490   void CreateDecodeTree(const AuxTraceInfoRecord& auxtrace_info) {
491     for (int i = 0; i < auxtrace_info.data->nr_cpu; i++) {
492       auto& etm4 = auxtrace_info.data->etm4_info[i];
493       ocsd_etmv4_cfg cfg;
494       memset(&cfg, 0, sizeof(cfg));
495       cfg.reg_idr0 = etm4.trcidr0;
496       cfg.reg_idr1 = etm4.trcidr1;
497       cfg.reg_idr2 = etm4.trcidr2;
498       cfg.reg_idr8 = etm4.trcidr8;
499       cfg.reg_configr = etm4.trcconfigr;
500       cfg.reg_traceidr = etm4.trctraceidr;
501       cfg.arch_ver = ARCH_V8;
502       cfg.core_prof = profile_CortexA;
503       uint8_t trace_id = cfg.reg_traceidr & 0x7f;
504       configs_.emplace(trace_id, &cfg);
505       decode_tree_.CreateDecoder(configs_[trace_id]);
506       auto result = packet_sinks_.emplace(trace_id, trace_id);
507       CHECK(result.second);
508       decode_tree_.AttachPacketSink(trace_id, result.first->second);
509     }
510   }
511 
512   void EnableDump(const ETMDumpOption& option) override {
513     dumper_.reset(new DataDumper(decode_tree_));
514     if (option.dump_raw_data) {
515       dumper_->DumpRawData();
516     }
517     if (option.dump_packets) {
518       dumper_->DumpPackets(configs_);
519     }
520     if (option.dump_elements) {
521       dumper_->DumpElements();
522       InstallElementCallback(dumper_.get());
523     }
524   }
525 
526   void RegisterCallback(const CallbackFn& callback) {
527     InstallMapLocator();
528     instr_range_parser_.reset(new InstrRangeParser(*map_locator_, callback));
529     InstallElementCallback(instr_range_parser_.get());
530   }
531 
532   bool ProcessData(const uint8_t* data, size_t size) override {
533     // Reset decoders before processing each data block. Because:
534     // 1. Data blocks are not continuous. So decoders shouldn't keep previous states when
535     //    processing a new block.
536     // 2. The beginning part of a data block may be truncated if kernel buffer is temporarily full.
537     //    So we may see garbage data, which can cause decoding errors if we don't reset decoders.
538     auto resp =
539         decode_tree_.GetDataIn().TraceDataIn(OCSD_OP_RESET, data_index_, 0, nullptr, nullptr);
540     if (IsRespError(resp)) {
541       LOG(ERROR) << "failed to reset decoder, resp " << resp;
542       return false;
543     }
544     size_t left_size = size;
545     while (left_size > 0) {
546       uint32_t processed;
547       auto resp = decode_tree_.GetDataIn().TraceDataIn(OCSD_OP_DATA, data_index_, left_size, data,
548                                                        &processed);
549       if (IsRespError(resp)) {
550         // A decoding error shouldn't ruin all data. Reset decoders to recover from it.
551         LOG(INFO) << "reset etm decoders for seeing a decode failure, resp " << resp;
552         decode_tree_.GetDataIn().TraceDataIn(OCSD_OP_RESET, data_index_ + processed, 0, nullptr,
553                                              nullptr);
554       }
555       data += processed;
556       left_size -= processed;
557       data_index_ += processed;
558     }
559     return true;
560   }
561 
562   bool FinishData() override {
563     if (instr_range_parser_) {
564       instr_range_parser_->FinishData();
565     }
566     return true;
567   }
568 
569  private:
570   void InstallMapLocator() {
571     if (!map_locator_) {
572       map_locator_.reset(new MapLocator(thread_tree_));
573       InstallPacketCallback(map_locator_.get());
574     }
575   }
576 
577   void InstallPacketCallback(PacketCallback* callback) {
578     for (auto& p : packet_sinks_) {
579       p.second.AddCallback(callback);
580     }
581   }
582 
583   void InstallElementCallback(ElementCallback* callback) {
584     if (!packet_to_element_) {
585       InstallMapLocator();
586       packet_to_element_.reset(
587           new PacketToElement(*map_locator_, configs_, decode_tree_.ErrorLogger()));
588       InstallPacketCallback(packet_to_element_.get());
589     }
590     packet_to_element_->AddCallback(callback);
591   }
592 
593   // map ip address to binary path and binary offset
594   ThreadTree& thread_tree_;
595   // handle to build OpenCSD decoder
596   ETMV4IDecodeTree decode_tree_;
597   // map from the trace id of an etm device to its config
598   std::unordered_map<uint8_t, EtmV4Config> configs_;
599   // map from the trace id of an etm device to its PacketSink
600   std::unordered_map<uint8_t, PacketSink> packet_sinks_;
601   std::unique_ptr<PacketToElement> packet_to_element_;
602   std::unique_ptr<DataDumper> dumper_;
603   // an index keeping processed etm data size
604   size_t data_index_ = 0;
605   std::unique_ptr<InstrRangeParser> instr_range_parser_;
606   std::unique_ptr<MapLocator> map_locator_;
607 };
608 
609 }  // namespace
610 
611 namespace simpleperf {
612 
613 bool ParseEtmDumpOption(const std::string& s, ETMDumpOption* option) {
614   for (auto& value : android::base::Split(s, ",")) {
615     if (value == "raw") {
616       option->dump_raw_data = true;
617     } else if (value == "packet") {
618       option->dump_packets = true;
619     } else if (value == "element") {
620       option->dump_elements = true;
621     } else {
622       LOG(ERROR) << "unknown etm dump option: " << value;
623       return false;
624     }
625   }
626   return true;
627 }
628 
629 std::unique_ptr<ETMDecoder> ETMDecoder::Create(const AuxTraceInfoRecord& auxtrace_info,
630                                                ThreadTree& thread_tree) {
631   auto decoder = std::make_unique<ETMDecoderImpl>(thread_tree);
632   decoder->CreateDecodeTree(auxtrace_info);
633   return std::unique_ptr<ETMDecoder>(decoder.release());
634 }
635 
636 }  // namespace simpleperf