Merge "simpleperf: Add support for new perf ETE files."
diff --git a/simpleperf/ETMDecoder.cpp b/simpleperf/ETMDecoder.cpp
index 463a62f..4c72331 100644
--- a/simpleperf/ETMDecoder.cpp
+++ b/simpleperf/ETMDecoder.cpp
@@ -71,10 +71,10 @@
     frame_decoder_.getErrLogAttachPt()->attach(&error_logger_);
   }
 
-  bool CreateDecoder(const EtmV4Config& config) {
-    uint8_t trace_id = config.getTraceID();
+  bool CreateDecoder(const EtmV4Config* config) {
+    uint8_t trace_id = config->getTraceID();
     auto packet_decoder = std::make_unique<TrcPktProcEtmV4I>(trace_id);
-    packet_decoder->setProtocolConfig(&config);
+    packet_decoder->setProtocolConfig(config);
     packet_decoder->getErrorLogAttachPt()->replace_first(&error_logger_);
     frame_decoder_.getIDStreamAttachPt(trace_id)->attach(packet_decoder.get());
     auto result = packet_decoders_.emplace(trace_id, packet_decoder.release());
@@ -341,15 +341,16 @@
 // Decode packets into elements.
 class PacketToElement : public PacketCallback, public ITrcGenElemIn {
  public:
-  PacketToElement(MapLocator& map_locator, const std::unordered_map<uint8_t, EtmV4Config>& configs,
+  PacketToElement(MapLocator& map_locator,
+                  const std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs,
                   DecodeErrorLogger& error_logger)
       : PacketCallback(PacketCallback::PACKET_TO_ELEMENT), mem_access_(map_locator) {
     for (auto& p : configs) {
       uint8_t trace_id = p.first;
-      const EtmV4Config& config = p.second;
+      const EtmV4Config* config = p.second.get();
       element_decoders_.emplace(trace_id, trace_id);
       auto& decoder = element_decoders_[trace_id];
-      decoder.setProtocolConfig(&config);
+      decoder.setProtocolConfig(config);
       decoder.getErrorLogAttachPt()->replace_first(&error_logger);
       decoder.getInstrDecodeAttachPt()->replace_first(&instruction_decoder_);
       decoder.getMemoryAccessAttachPt()->replace_first(&mem_access_);
@@ -395,7 +396,7 @@
     frame_printer_.setMessageLogger(&stdout_logger_);
   }
 
-  void DumpPackets(const std::unordered_map<uint8_t, EtmV4Config>& configs) {
+  void DumpPackets(const std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs) {
     for (auto& p : configs) {
       uint8_t trace_id = p.first;
       auto result = packet_printers_.emplace(trace_id, trace_id);
@@ -519,16 +520,16 @@
   BranchListParser(MapLocator& map_locator, const ETMDecoder::BranchListCallbackFn& callback)
       : PacketCallback(BRANCH_LIST_PARSER), map_locator_(map_locator), callback_(callback) {}
 
-  void CheckConfigs(std::unordered_map<uint8_t, EtmV4Config>& configs) {
+  void CheckConfigs(std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>>& configs) {
     // TODO: Current implementation doesn't support non-zero speculation length and return stack.
     for (auto& p : configs) {
-      if (p.second.MaxSpecDepth() > 0) {
+      if (p.second->MaxSpecDepth() > 0) {
         LOG(WARNING) << "branch list collection isn't accurate with non-zero speculation length";
         break;
       }
     }
     for (auto& p : configs) {
-      if (p.second.enabledRetStack()) {
+      if (p.second->enabledRetStack()) {
         LOG(WARNING) << "branch list collection will lose some data with return stack enabled";
         break;
       }
@@ -641,22 +642,45 @@
   ETMDecoderImpl(ThreadTree& thread_tree) : thread_tree_(thread_tree) {}
 
   void CreateDecodeTree(const AuxTraceInfoRecord& auxtrace_info) {
+    uint8_t trace_id = 0;
+    uint64_t* info = auxtrace_info.data->info;
     for (int i = 0; i < auxtrace_info.data->nr_cpu; i++) {
-      auto& etm4 = auxtrace_info.data->etm4_info[i];
-      ocsd_etmv4_cfg cfg;
-      memset(&cfg, 0, sizeof(cfg));
-      cfg.reg_idr0 = etm4.trcidr0;
-      cfg.reg_idr1 = etm4.trcidr1;
-      cfg.reg_idr2 = etm4.trcidr2;
-      cfg.reg_idr8 = etm4.trcidr8;
-      cfg.reg_configr = etm4.trcconfigr;
-      cfg.reg_traceidr = etm4.trctraceidr;
-      cfg.arch_ver = ARCH_V8;
-      cfg.core_prof = profile_CortexA;
-      uint8_t trace_id = cfg.reg_traceidr & 0x7f;
-      trace_ids_.emplace(etm4.cpu, trace_id);
-      configs_.emplace(trace_id, &cfg);
-      decode_tree_.CreateDecoder(configs_[trace_id]);
+      if (info[0] == AuxTraceInfoRecord::MAGIC_ETM4) {
+        auto& etm4 = *reinterpret_cast<AuxTraceInfoRecord::ETM4Info*>(info);
+        ocsd_etmv4_cfg cfg;
+        memset(&cfg, 0, sizeof(cfg));
+        cfg.reg_idr0 = etm4.trcidr0;
+        cfg.reg_idr1 = etm4.trcidr1;
+        cfg.reg_idr2 = etm4.trcidr2;
+        cfg.reg_idr8 = etm4.trcidr8;
+        cfg.reg_configr = etm4.trcconfigr;
+        cfg.reg_traceidr = etm4.trctraceidr;
+        cfg.arch_ver = ARCH_V8;
+        cfg.core_prof = profile_CortexA;
+        trace_id = cfg.reg_traceidr & 0x7f;
+        trace_ids_.emplace(etm4.cpu, trace_id);
+        configs_.emplace(trace_id, new EtmV4Config(&cfg));
+        info = reinterpret_cast<uint64_t*>(&etm4 + 1);
+      } else {
+        CHECK_EQ(info[0], AuxTraceInfoRecord::MAGIC_ETE);
+        auto& ete = *reinterpret_cast<AuxTraceInfoRecord::ETEInfo*>(info);
+        ocsd_ete_cfg cfg;
+        memset(&cfg, 0, sizeof(cfg));
+        cfg.reg_idr0 = ete.trcidr0;
+        cfg.reg_idr1 = ete.trcidr1;
+        cfg.reg_idr2 = ete.trcidr2;
+        cfg.reg_idr8 = ete.trcidr8;
+        cfg.reg_devarch = ete.trcdevarch;
+        cfg.reg_configr = ete.trcconfigr;
+        cfg.reg_traceidr = ete.trctraceidr;
+        cfg.arch_ver = ARCH_AA64;
+        cfg.core_prof = profile_CortexA;
+        trace_id = cfg.reg_traceidr & 0x7f;
+        trace_ids_.emplace(ete.cpu, trace_id);
+        configs_.emplace(trace_id, new ETEConfig(&cfg));
+        info = reinterpret_cast<uint64_t*>(&ete + 1);
+      }
+      decode_tree_.CreateDecoder(configs_[trace_id].get());
       auto result = packet_sinks_.emplace(trace_id, trace_id);
       CHECK(result.second);
       decode_tree_.AttachPacketSink(trace_id, result.first->second);
@@ -735,11 +759,11 @@
   void InstallMapLocator() {
     if (!map_locator_) {
       map_locator_.reset(new MapLocator(thread_tree_));
-
       for (auto& cfg : configs_) {
+        int64_t configr = (*(const ocsd_etmv4_cfg*)*cfg.second).reg_configr;
         map_locator_->SetUseVmid(
             cfg.first,
-            (*cfg.second).reg_configr & (1U << ETM4_CFG_BIT_VMID | 1U << ETM4_CFG_BIT_VMID_OPT));
+            configr & (1U << ETM4_CFG_BIT_VMID | 1U << ETM4_CFG_BIT_VMID_OPT));
       }
 
       InstallPacketCallback(map_locator_.get());
@@ -769,7 +793,7 @@
   // map from cpu to trace id
   std::unordered_map<uint64_t, uint8_t> trace_ids_;
   // map from the trace id of an etm device to its config
-  std::unordered_map<uint8_t, EtmV4Config> configs_;
+  std::unordered_map<uint8_t, std::unique_ptr<EtmV4Config>> configs_;
   // map from the trace id of an etm device to its PacketSink
   std::unordered_map<uint8_t, PacketSink> packet_sinks_;
   std::unique_ptr<PacketToElement> packet_to_element_;
diff --git a/simpleperf/ETMRecorder.cpp b/simpleperf/ETMRecorder.cpp
index 486e4f0..7bef4f2 100644
--- a/simpleperf/ETMRecorder.cpp
+++ b/simpleperf/ETMRecorder.cpp
@@ -154,6 +154,10 @@
                      ReadValueInEtmDir(name + "/trcidr/trcidr4", &cpu_info.trcidr4) &&
                      ReadValueInEtmDir(name + "/trcidr/trcidr8", &cpu_info.trcidr8) &&
                      ReadValueInEtmDir(name + "/mgmt/trcauthstatus", &cpu_info.trcauthstatus);
+
+      if (!ReadValueInEtmDir(name + "/mgmt/trcdevarch", &cpu_info.trcdevarch, false)) {
+        cpu_info.trcdevarch = 0;
+      }
       if (!success) {
         return false;
       }
@@ -219,13 +223,20 @@
   AuxTraceInfoRecord::DataType data;
   memset(&data, 0, sizeof(data));
   data.aux_type = AuxTraceInfoRecord::AUX_TYPE_ETM;
+  data.version = 1;
   data.nr_cpu = etm_info_.size();
   data.pmu_type = GetEtmEventType();
-  std::vector<AuxTraceInfoRecord::ETM4Info> etm4_v(etm_info_.size());
+  std::vector<AuxTraceInfoRecord::ETEInfo> ete(etm_info_.size());
   size_t pos = 0;
   for (auto& p : etm_info_) {
-    auto& e = etm4_v[pos++];
-    e.magic = AuxTraceInfoRecord::MAGIC_ETM4;
+    auto& e = ete[pos++];
+    if (p.second.trcdevarch == 0) {
+      e.magic = AuxTraceInfoRecord::MAGIC_ETM4;
+      e.nrtrcparams = sizeof(AuxTraceInfoRecord::ETM4Info) / sizeof(uint64_t) - 3;
+    } else {
+      e.magic = AuxTraceInfoRecord::MAGIC_ETE;
+      e.nrtrcparams = sizeof(AuxTraceInfoRecord::ETEInfo) / sizeof(uint64_t) - 3;
+    }
     e.cpu = p.first;
     e.trcconfigr = etm_config_reg_;
     e.trctraceidr = GetTraceId(p.first);
@@ -234,8 +245,9 @@
     e.trcidr2 = p.second.trcidr2;
     e.trcidr8 = p.second.trcidr8;
     e.trcauthstatus = p.second.trcauthstatus;
+    e.trcdevarch = p.second.trcdevarch;
   }
-  return AuxTraceInfoRecord(data, etm4_v);
+  return AuxTraceInfoRecord(data, ete);
 }
 
 size_t ETMRecorder::GetAddrFilterPairs() {
diff --git a/simpleperf/ETMRecorder.h b/simpleperf/ETMRecorder.h
index b559636..1e33ed8 100644
--- a/simpleperf/ETMRecorder.h
+++ b/simpleperf/ETMRecorder.h
@@ -34,6 +34,7 @@
   uint32_t trcidr4;
   uint32_t trcidr8;
   uint32_t trcauthstatus;
+  uint32_t trcdevarch;
 
   int GetMajorVersion() const;
   bool IsContextIDSupported() const;
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 4e8a882..218147b 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -924,25 +924,43 @@
   p += header_size();
   data = reinterpret_cast<DataType*>(p);
   CHECK_EQ(data->aux_type, AUX_TYPE_ETM);
-  CHECK_EQ(data->version, 0);
+  CHECK_EQ(data->version, 1);
+  p += sizeof(DataType);
   for (uint32_t i = 0; i < data->nr_cpu; ++i) {
-    CHECK_EQ(data->etm4_info[i].magic, MAGIC_ETM4);
+    uint64_t magic = *reinterpret_cast<uint64_t*>(p);
+    if (magic == MAGIC_ETM4) {
+      p += sizeof(ETM4Info);
+    } else {
+      CHECK_EQ(magic, MAGIC_ETE);
+      p += sizeof(ETEInfo);
+    }
   }
-  p += sizeof(DataType) + data->nr_cpu * sizeof(ETM4Info);
   CHECK_EQ(p, end);
 }
 
 AuxTraceInfoRecord::AuxTraceInfoRecord(const DataType& data,
-                                       const std::vector<ETM4Info>& etm4_info) {
+                                       const std::vector<ETEInfo>& ete_info) {
   SetTypeAndMisc(PERF_RECORD_AUXTRACE_INFO, 0);
-  SetSize(header_size() + sizeof(DataType) + sizeof(ETM4Info) * etm4_info.size());
-  char* new_binary = new char[size()];
+
+  uint32_t size = header_size() + sizeof(DataType);
+  for (auto& ete : ete_info) {
+    size += (ete.trcdevarch == 0) ? sizeof(ETM4Info) : sizeof(ETEInfo);
+  }
+  SetSize(size);
+  char* new_binary = new char[size];
   char* p = new_binary;
   MoveToBinaryFormat(header, p);
   this->data = reinterpret_cast<DataType*>(p);
   MoveToBinaryFormat(data, p);
-  for (auto& etm4 : etm4_info) {
-    MoveToBinaryFormat(etm4, p);
+  for (auto& ete : ete_info) {
+    if (ete.trcdevarch == 0) {
+      ETM4Info etm4;
+      static_assert(sizeof(ETM4Info) + sizeof(uint64_t) == sizeof(ETEInfo));
+      memcpy(&etm4, &ete, sizeof(ETM4Info));
+      MoveToBinaryFormat(etm4, p);
+    } else {
+      MoveToBinaryFormat(ete, p);
+    }
   }
   UpdateBinary(new_binary);
 }
@@ -954,17 +972,38 @@
   PrintIndented(indent, "pmu_type %u\n", data->pmu_type);
   PrintIndented(indent, "snapshot %" PRIu64 "\n", data->snapshot);
   indent++;
+  uint64_t *info = data->info;
+
   for (int i = 0; i < data->nr_cpu; i++) {
-    const ETM4Info& e = data->etm4_info[i];
-    PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic);
-    PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu);
-    PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr);
-    PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr);
-    PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0);
-    PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1);
-    PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2);
-    PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8);
-    PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus);
+    if (info[0] == MAGIC_ETM4) {
+      ETM4Info &e = *reinterpret_cast<ETM4Info *>(info);
+      PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic);
+      PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu);
+      PrintIndented(indent, "nrtrcparams %" PRIu64 "\n", e.nrtrcparams);
+      PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr);
+      PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr);
+      PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0);
+      PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1);
+      PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2);
+      PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8);
+      PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus);
+      info = reinterpret_cast<uint64_t *>(&e + 1);
+    } else {
+      CHECK_EQ(info[0], MAGIC_ETE);
+      ETEInfo &e = *reinterpret_cast<ETEInfo *>(info);
+      PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic);
+      PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu);
+      PrintIndented(indent, "nrtrcparams %" PRIu64 "\n", e.nrtrcparams);
+      PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr);
+      PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr);
+      PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0);
+      PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1);
+      PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2);
+      PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8);
+      PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus);
+      PrintIndented(indent, "trcdevarch 0x%" PRIx64 "\n", e.trcdevarch);
+      info = reinterpret_cast<uint64_t *>(&e + 1);
+    }
   }
 }
 
diff --git a/simpleperf/record.h b/simpleperf/record.h
index f3bfb2f..fad3a88 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -452,10 +452,12 @@
   // magic values to be compatible with linux perf
   static const uint32_t AUX_TYPE_ETM = 3;
   static const uint64_t MAGIC_ETM4 = 0x4040404040404040ULL;
+  static const uint64_t MAGIC_ETE = 0x5050505050505050ULL;
 
   struct ETM4Info {
     uint64_t magic;
     uint64_t cpu;
+    uint64_t nrtrcparams;
     uint64_t trcconfigr;
     uint64_t trctraceidr;
     uint64_t trcidr0;
@@ -465,6 +467,20 @@
     uint64_t trcauthstatus;
   };
 
+  struct ETEInfo {
+    uint64_t magic;
+    uint64_t cpu;
+    uint64_t nrtrcparams;
+    uint64_t trcconfigr;
+    uint64_t trctraceidr;
+    uint64_t trcidr0;
+    uint64_t trcidr1;
+    uint64_t trcidr2;
+    uint64_t trcidr8;
+    uint64_t trcauthstatus;
+    uint64_t trcdevarch;
+  };
+
   struct DataType {
     uint32_t aux_type;
     uint32_t reserved;
@@ -472,11 +488,11 @@
     uint32_t nr_cpu;
     uint32_t pmu_type;
     uint64_t snapshot;
-    ETM4Info etm4_info[0];
+    uint64_t info[0];
   } * data;
 
   explicit AuxTraceInfoRecord(char* p);
-  AuxTraceInfoRecord(const DataType& data, const std::vector<ETM4Info>& etm4_info);
+  AuxTraceInfoRecord(const DataType& data, const std::vector<ETEInfo>& ete_info);
 
  protected:
   void DumpData(size_t indent) const override;
diff --git a/simpleperf/testdata/etm/perf_with_unformatted_trace.data b/simpleperf/testdata/etm/perf_with_unformatted_trace.data
index dcd4c62..ee7ee3f 100644
--- a/simpleperf/testdata/etm/perf_with_unformatted_trace.data
+++ b/simpleperf/testdata/etm/perf_with_unformatted_trace.data
Binary files differ