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