xref: /aosp_15_r20/system/extras/simpleperf/BranchListFile.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include "BranchListFile.h"
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include "ETMDecoder.h"
20*288bf522SAndroid Build Coastguard Worker #include "ZstdUtil.h"
21*288bf522SAndroid Build Coastguard Worker #include "system/extras/simpleperf/branch_list.pb.h"
22*288bf522SAndroid Build Coastguard Worker 
23*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
24*288bf522SAndroid Build Coastguard Worker 
25*288bf522SAndroid Build Coastguard Worker static constexpr const char* ETM_BRANCH_LIST_PROTO_MAGIC = "simpleperf:EtmBranchList";
26*288bf522SAndroid Build Coastguard Worker 
ETMBranchToProtoString(const std::vector<bool> & branch)27*288bf522SAndroid Build Coastguard Worker std::string ETMBranchToProtoString(const std::vector<bool>& branch) {
28*288bf522SAndroid Build Coastguard Worker   size_t bytes = (branch.size() + 7) / 8;
29*288bf522SAndroid Build Coastguard Worker   std::string res(bytes, '\0');
30*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < branch.size(); i++) {
31*288bf522SAndroid Build Coastguard Worker     if (branch[i]) {
32*288bf522SAndroid Build Coastguard Worker       res[i >> 3] |= 1 << (i & 7);
33*288bf522SAndroid Build Coastguard Worker     }
34*288bf522SAndroid Build Coastguard Worker   }
35*288bf522SAndroid Build Coastguard Worker   return res;
36*288bf522SAndroid Build Coastguard Worker }
37*288bf522SAndroid Build Coastguard Worker 
ProtoStringToETMBranch(const std::string & s,size_t bit_size)38*288bf522SAndroid Build Coastguard Worker std::vector<bool> ProtoStringToETMBranch(const std::string& s, size_t bit_size) {
39*288bf522SAndroid Build Coastguard Worker   std::vector<bool> branch(bit_size, false);
40*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < bit_size; i++) {
41*288bf522SAndroid Build Coastguard Worker     if (s[i >> 3] & (1 << (i & 7))) {
42*288bf522SAndroid Build Coastguard Worker       branch[i] = true;
43*288bf522SAndroid Build Coastguard Worker     }
44*288bf522SAndroid Build Coastguard Worker   }
45*288bf522SAndroid Build Coastguard Worker   return branch;
46*288bf522SAndroid Build Coastguard Worker }
47*288bf522SAndroid Build Coastguard Worker 
ToProtoBinaryType(DsoType dso_type)48*288bf522SAndroid Build Coastguard Worker static std::optional<proto::ETMBinary::BinaryType> ToProtoBinaryType(DsoType dso_type) {
49*288bf522SAndroid Build Coastguard Worker   switch (dso_type) {
50*288bf522SAndroid Build Coastguard Worker     case DSO_ELF_FILE:
51*288bf522SAndroid Build Coastguard Worker       return proto::ETMBinary::ELF_FILE;
52*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL:
53*288bf522SAndroid Build Coastguard Worker       return proto::ETMBinary::KERNEL;
54*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL_MODULE:
55*288bf522SAndroid Build Coastguard Worker       return proto::ETMBinary::KERNEL_MODULE;
56*288bf522SAndroid Build Coastguard Worker     default:
57*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "unexpected dso type " << dso_type;
58*288bf522SAndroid Build Coastguard Worker       return std::nullopt;
59*288bf522SAndroid Build Coastguard Worker   }
60*288bf522SAndroid Build Coastguard Worker }
61*288bf522SAndroid Build Coastguard Worker 
ETMBinaryMapToString(const ETMBinaryMap & binary_map,std::string & s)62*288bf522SAndroid Build Coastguard Worker bool ETMBinaryMapToString(const ETMBinaryMap& binary_map, std::string& s) {
63*288bf522SAndroid Build Coastguard Worker   auto writer = BranchListProtoWriter::CreateForString(&s, false);
64*288bf522SAndroid Build Coastguard Worker   if (!writer) {
65*288bf522SAndroid Build Coastguard Worker     return false;
66*288bf522SAndroid Build Coastguard Worker   }
67*288bf522SAndroid Build Coastguard Worker   if (!writer->Write(binary_map)) {
68*288bf522SAndroid Build Coastguard Worker     return false;
69*288bf522SAndroid Build Coastguard Worker   }
70*288bf522SAndroid Build Coastguard Worker   return true;
71*288bf522SAndroid Build Coastguard Worker }
72*288bf522SAndroid Build Coastguard Worker 
ToDsoType(proto::ETMBinary::BinaryType binary_type)73*288bf522SAndroid Build Coastguard Worker static std::optional<DsoType> ToDsoType(proto::ETMBinary::BinaryType binary_type) {
74*288bf522SAndroid Build Coastguard Worker   switch (binary_type) {
75*288bf522SAndroid Build Coastguard Worker     case proto::ETMBinary::ELF_FILE:
76*288bf522SAndroid Build Coastguard Worker       return DSO_ELF_FILE;
77*288bf522SAndroid Build Coastguard Worker     case proto::ETMBinary::KERNEL:
78*288bf522SAndroid Build Coastguard Worker       return DSO_KERNEL;
79*288bf522SAndroid Build Coastguard Worker     case proto::ETMBinary::KERNEL_MODULE:
80*288bf522SAndroid Build Coastguard Worker       return DSO_KERNEL_MODULE;
81*288bf522SAndroid Build Coastguard Worker     default:
82*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "unexpected binary type " << binary_type;
83*288bf522SAndroid Build Coastguard Worker       return std::nullopt;
84*288bf522SAndroid Build Coastguard Worker   }
85*288bf522SAndroid Build Coastguard Worker }
86*288bf522SAndroid Build Coastguard Worker 
StringToETMBinaryMap(const std::string & s,ETMBinaryMap & binary_map)87*288bf522SAndroid Build Coastguard Worker bool StringToETMBinaryMap(const std::string& s, ETMBinaryMap& binary_map) {
88*288bf522SAndroid Build Coastguard Worker   LBRData lbr_data;
89*288bf522SAndroid Build Coastguard Worker   auto reader = BranchListProtoReader::CreateForString(s);
90*288bf522SAndroid Build Coastguard Worker   if (!reader) {
91*288bf522SAndroid Build Coastguard Worker     return false;
92*288bf522SAndroid Build Coastguard Worker   }
93*288bf522SAndroid Build Coastguard Worker   return reader->Read(binary_map, lbr_data);
94*288bf522SAndroid Build Coastguard Worker }
95*288bf522SAndroid Build Coastguard Worker 
96*288bf522SAndroid Build Coastguard Worker class ETMThreadTreeWhenRecording : public ETMThreadTree {
97*288bf522SAndroid Build Coastguard Worker  public:
ETMThreadTreeWhenRecording(bool dump_maps_from_proc)98*288bf522SAndroid Build Coastguard Worker   ETMThreadTreeWhenRecording(bool dump_maps_from_proc)
99*288bf522SAndroid Build Coastguard Worker       : dump_maps_from_proc_(dump_maps_from_proc) {}
100*288bf522SAndroid Build Coastguard Worker 
GetThreadTree()101*288bf522SAndroid Build Coastguard Worker   ThreadTree& GetThreadTree() { return thread_tree_; }
ExcludePid(pid_t pid)102*288bf522SAndroid Build Coastguard Worker   void ExcludePid(pid_t pid) { exclude_pid_ = pid; }
103*288bf522SAndroid Build Coastguard Worker 
FindThread(int tid)104*288bf522SAndroid Build Coastguard Worker   const ThreadEntry* FindThread(int tid) override {
105*288bf522SAndroid Build Coastguard Worker     const ThreadEntry* thread = thread_tree_.FindThread(tid);
106*288bf522SAndroid Build Coastguard Worker     if (thread == nullptr) {
107*288bf522SAndroid Build Coastguard Worker       if (dump_maps_from_proc_) {
108*288bf522SAndroid Build Coastguard Worker         thread = FindThreadFromProc(tid);
109*288bf522SAndroid Build Coastguard Worker       }
110*288bf522SAndroid Build Coastguard Worker       if (thread == nullptr) {
111*288bf522SAndroid Build Coastguard Worker         return nullptr;
112*288bf522SAndroid Build Coastguard Worker       }
113*288bf522SAndroid Build Coastguard Worker     }
114*288bf522SAndroid Build Coastguard Worker     if (exclude_pid_ && exclude_pid_ == thread->pid) {
115*288bf522SAndroid Build Coastguard Worker       return nullptr;
116*288bf522SAndroid Build Coastguard Worker     }
117*288bf522SAndroid Build Coastguard Worker 
118*288bf522SAndroid Build Coastguard Worker     if (dump_maps_from_proc_) {
119*288bf522SAndroid Build Coastguard Worker       DumpMapsFromProc(thread->pid);
120*288bf522SAndroid Build Coastguard Worker     }
121*288bf522SAndroid Build Coastguard Worker     return thread;
122*288bf522SAndroid Build Coastguard Worker   }
123*288bf522SAndroid Build Coastguard Worker 
DisableThreadExitRecords()124*288bf522SAndroid Build Coastguard Worker   void DisableThreadExitRecords() override { thread_tree_.DisableThreadExitRecords(); }
GetKernelMaps()125*288bf522SAndroid Build Coastguard Worker   const MapSet& GetKernelMaps() override { return thread_tree_.GetKernelMaps(); }
126*288bf522SAndroid Build Coastguard Worker 
127*288bf522SAndroid Build Coastguard Worker  private:
FindThreadFromProc(int tid)128*288bf522SAndroid Build Coastguard Worker   const ThreadEntry* FindThreadFromProc(int tid) {
129*288bf522SAndroid Build Coastguard Worker     std::string comm;
130*288bf522SAndroid Build Coastguard Worker     pid_t pid;
131*288bf522SAndroid Build Coastguard Worker     if (ReadThreadNameAndPid(tid, &comm, &pid)) {
132*288bf522SAndroid Build Coastguard Worker       thread_tree_.SetThreadName(pid, tid, comm);
133*288bf522SAndroid Build Coastguard Worker       return thread_tree_.FindThread(tid);
134*288bf522SAndroid Build Coastguard Worker     }
135*288bf522SAndroid Build Coastguard Worker     return nullptr;
136*288bf522SAndroid Build Coastguard Worker   }
137*288bf522SAndroid Build Coastguard Worker 
DumpMapsFromProc(int pid)138*288bf522SAndroid Build Coastguard Worker   void DumpMapsFromProc(int pid) {
139*288bf522SAndroid Build Coastguard Worker     if (dumped_processes_.count(pid) == 0) {
140*288bf522SAndroid Build Coastguard Worker       dumped_processes_.insert(pid);
141*288bf522SAndroid Build Coastguard Worker       std::vector<ThreadMmap> maps;
142*288bf522SAndroid Build Coastguard Worker       if (GetThreadMmapsInProcess(pid, &maps)) {
143*288bf522SAndroid Build Coastguard Worker         for (const auto& map : maps) {
144*288bf522SAndroid Build Coastguard Worker           thread_tree_.AddThreadMap(pid, pid, map.start_addr, map.len, map.pgoff, map.name);
145*288bf522SAndroid Build Coastguard Worker         }
146*288bf522SAndroid Build Coastguard Worker       }
147*288bf522SAndroid Build Coastguard Worker     }
148*288bf522SAndroid Build Coastguard Worker   }
149*288bf522SAndroid Build Coastguard Worker 
150*288bf522SAndroid Build Coastguard Worker   ThreadTree thread_tree_;
151*288bf522SAndroid Build Coastguard Worker   bool dump_maps_from_proc_;
152*288bf522SAndroid Build Coastguard Worker   std::unordered_set<int> dumped_processes_;
153*288bf522SAndroid Build Coastguard Worker   std::optional<pid_t> exclude_pid_;
154*288bf522SAndroid Build Coastguard Worker };
155*288bf522SAndroid Build Coastguard Worker 
156*288bf522SAndroid Build Coastguard Worker class ETMBranchListGeneratorImpl : public ETMBranchListGenerator {
157*288bf522SAndroid Build Coastguard Worker  public:
ETMBranchListGeneratorImpl(bool dump_maps_from_proc)158*288bf522SAndroid Build Coastguard Worker   ETMBranchListGeneratorImpl(bool dump_maps_from_proc)
159*288bf522SAndroid Build Coastguard Worker       : thread_tree_(dump_maps_from_proc), binary_filter_(nullptr) {}
160*288bf522SAndroid Build Coastguard Worker 
SetExcludePid(pid_t pid)161*288bf522SAndroid Build Coastguard Worker   void SetExcludePid(pid_t pid) override { thread_tree_.ExcludePid(pid); }
SetBinaryFilter(const RegEx * binary_name_regex)162*288bf522SAndroid Build Coastguard Worker   void SetBinaryFilter(const RegEx* binary_name_regex) override {
163*288bf522SAndroid Build Coastguard Worker     binary_filter_.SetRegex(binary_name_regex);
164*288bf522SAndroid Build Coastguard Worker   }
165*288bf522SAndroid Build Coastguard Worker 
166*288bf522SAndroid Build Coastguard Worker   bool ProcessRecord(const Record& r, bool& consumed) override;
167*288bf522SAndroid Build Coastguard Worker   ETMBinaryMap GetETMBinaryMap() override;
168*288bf522SAndroid Build Coastguard Worker 
169*288bf522SAndroid Build Coastguard Worker  private:
170*288bf522SAndroid Build Coastguard Worker   struct AuxRecordData {
171*288bf522SAndroid Build Coastguard Worker     uint64_t start;
172*288bf522SAndroid Build Coastguard Worker     uint64_t end;
173*288bf522SAndroid Build Coastguard Worker     bool formatted;
AuxRecordDatasimpleperf::ETMBranchListGeneratorImpl::AuxRecordData174*288bf522SAndroid Build Coastguard Worker     AuxRecordData(uint64_t start, uint64_t end, bool formatted)
175*288bf522SAndroid Build Coastguard Worker         : start(start), end(end), formatted(formatted) {}
176*288bf522SAndroid Build Coastguard Worker   };
177*288bf522SAndroid Build Coastguard Worker 
178*288bf522SAndroid Build Coastguard Worker   struct PerCpuData {
179*288bf522SAndroid Build Coastguard Worker     std::vector<uint8_t> aux_data;
180*288bf522SAndroid Build Coastguard Worker     uint64_t data_offset = 0;
181*288bf522SAndroid Build Coastguard Worker     std::queue<AuxRecordData> aux_records;
182*288bf522SAndroid Build Coastguard Worker   };
183*288bf522SAndroid Build Coastguard Worker 
184*288bf522SAndroid Build Coastguard Worker   bool ProcessAuxRecord(const AuxRecord& r);
185*288bf522SAndroid Build Coastguard Worker   bool ProcessAuxTraceRecord(const AuxTraceRecord& r);
186*288bf522SAndroid Build Coastguard Worker   void ProcessBranchList(const ETMBranchList& branch_list);
187*288bf522SAndroid Build Coastguard Worker 
188*288bf522SAndroid Build Coastguard Worker   ETMThreadTreeWhenRecording thread_tree_;
189*288bf522SAndroid Build Coastguard Worker   uint64_t kernel_map_start_addr_ = 0;
190*288bf522SAndroid Build Coastguard Worker   BinaryFilter binary_filter_;
191*288bf522SAndroid Build Coastguard Worker   std::map<uint32_t, PerCpuData> cpu_map_;
192*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<ETMDecoder> etm_decoder_;
193*288bf522SAndroid Build Coastguard Worker   std::unordered_map<Dso*, ETMBinary> branch_list_binary_map_;
194*288bf522SAndroid Build Coastguard Worker };
195*288bf522SAndroid Build Coastguard Worker 
ProcessRecord(const Record & r,bool & consumed)196*288bf522SAndroid Build Coastguard Worker bool ETMBranchListGeneratorImpl::ProcessRecord(const Record& r, bool& consumed) {
197*288bf522SAndroid Build Coastguard Worker   consumed = true;  // No need to store any records.
198*288bf522SAndroid Build Coastguard Worker   uint32_t type = r.type();
199*288bf522SAndroid Build Coastguard Worker   if (type == PERF_RECORD_AUXTRACE_INFO) {
200*288bf522SAndroid Build Coastguard Worker     etm_decoder_ = ETMDecoder::Create(*static_cast<const AuxTraceInfoRecord*>(&r), thread_tree_);
201*288bf522SAndroid Build Coastguard Worker     if (!etm_decoder_) {
202*288bf522SAndroid Build Coastguard Worker       return false;
203*288bf522SAndroid Build Coastguard Worker     }
204*288bf522SAndroid Build Coastguard Worker     etm_decoder_->RegisterCallback(
205*288bf522SAndroid Build Coastguard Worker         [this](const ETMBranchList& branch) { ProcessBranchList(branch); });
206*288bf522SAndroid Build Coastguard Worker     return true;
207*288bf522SAndroid Build Coastguard Worker   }
208*288bf522SAndroid Build Coastguard Worker   if (type == PERF_RECORD_AUX) {
209*288bf522SAndroid Build Coastguard Worker     return ProcessAuxRecord(*static_cast<const AuxRecord*>(&r));
210*288bf522SAndroid Build Coastguard Worker   }
211*288bf522SAndroid Build Coastguard Worker   if (type == PERF_RECORD_AUXTRACE) {
212*288bf522SAndroid Build Coastguard Worker     return ProcessAuxTraceRecord(*static_cast<const AuxTraceRecord*>(&r));
213*288bf522SAndroid Build Coastguard Worker   }
214*288bf522SAndroid Build Coastguard Worker   if (type == PERF_RECORD_MMAP && r.InKernel()) {
215*288bf522SAndroid Build Coastguard Worker     auto& mmap_r = *static_cast<const MmapRecord*>(&r);
216*288bf522SAndroid Build Coastguard Worker     if (android::base::StartsWith(mmap_r.filename, DEFAULT_KERNEL_MMAP_NAME)) {
217*288bf522SAndroid Build Coastguard Worker       kernel_map_start_addr_ = mmap_r.data->addr;
218*288bf522SAndroid Build Coastguard Worker     }
219*288bf522SAndroid Build Coastguard Worker   }
220*288bf522SAndroid Build Coastguard Worker   thread_tree_.GetThreadTree().Update(r);
221*288bf522SAndroid Build Coastguard Worker   return true;
222*288bf522SAndroid Build Coastguard Worker }
223*288bf522SAndroid Build Coastguard Worker 
ProcessAuxRecord(const AuxRecord & r)224*288bf522SAndroid Build Coastguard Worker bool ETMBranchListGeneratorImpl::ProcessAuxRecord(const AuxRecord& r) {
225*288bf522SAndroid Build Coastguard Worker   OverflowResult result = SafeAdd(r.data->aux_offset, r.data->aux_size);
226*288bf522SAndroid Build Coastguard Worker   if (result.overflow || r.data->aux_size > SIZE_MAX) {
227*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "invalid aux record";
228*288bf522SAndroid Build Coastguard Worker     return false;
229*288bf522SAndroid Build Coastguard Worker   }
230*288bf522SAndroid Build Coastguard Worker   size_t size = r.data->aux_size;
231*288bf522SAndroid Build Coastguard Worker   uint64_t start = r.data->aux_offset;
232*288bf522SAndroid Build Coastguard Worker   uint64_t end = result.value;
233*288bf522SAndroid Build Coastguard Worker   PerCpuData& data = cpu_map_[r.Cpu()];
234*288bf522SAndroid Build Coastguard Worker   if (start >= data.data_offset && end <= data.data_offset + data.aux_data.size()) {
235*288bf522SAndroid Build Coastguard Worker     // The ETM data is available. Process it now.
236*288bf522SAndroid Build Coastguard Worker     uint8_t* p = data.aux_data.data() + (start - data.data_offset);
237*288bf522SAndroid Build Coastguard Worker     if (!etm_decoder_) {
238*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "ETMDecoder isn't created";
239*288bf522SAndroid Build Coastguard Worker       return false;
240*288bf522SAndroid Build Coastguard Worker     }
241*288bf522SAndroid Build Coastguard Worker     return etm_decoder_->ProcessData(p, size, !r.Unformatted(), r.Cpu());
242*288bf522SAndroid Build Coastguard Worker   }
243*288bf522SAndroid Build Coastguard Worker   // The ETM data isn't available. Put the aux record into queue.
244*288bf522SAndroid Build Coastguard Worker   data.aux_records.emplace(start, end, !r.Unformatted());
245*288bf522SAndroid Build Coastguard Worker   return true;
246*288bf522SAndroid Build Coastguard Worker }
247*288bf522SAndroid Build Coastguard Worker 
ProcessAuxTraceRecord(const AuxTraceRecord & r)248*288bf522SAndroid Build Coastguard Worker bool ETMBranchListGeneratorImpl::ProcessAuxTraceRecord(const AuxTraceRecord& r) {
249*288bf522SAndroid Build Coastguard Worker   OverflowResult result = SafeAdd(r.data->offset, r.data->aux_size);
250*288bf522SAndroid Build Coastguard Worker   if (result.overflow || r.data->aux_size > SIZE_MAX) {
251*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "invalid auxtrace record";
252*288bf522SAndroid Build Coastguard Worker     return false;
253*288bf522SAndroid Build Coastguard Worker   }
254*288bf522SAndroid Build Coastguard Worker   size_t size = r.data->aux_size;
255*288bf522SAndroid Build Coastguard Worker   uint64_t start = r.data->offset;
256*288bf522SAndroid Build Coastguard Worker   uint64_t end = result.value;
257*288bf522SAndroid Build Coastguard Worker   PerCpuData& data = cpu_map_[r.Cpu()];
258*288bf522SAndroid Build Coastguard Worker   data.data_offset = start;
259*288bf522SAndroid Build Coastguard Worker   CHECK(r.location.addr != nullptr);
260*288bf522SAndroid Build Coastguard Worker   data.aux_data.resize(size);
261*288bf522SAndroid Build Coastguard Worker   memcpy(data.aux_data.data(), r.location.addr, size);
262*288bf522SAndroid Build Coastguard Worker 
263*288bf522SAndroid Build Coastguard Worker   // Process cached aux records.
264*288bf522SAndroid Build Coastguard Worker   while (!data.aux_records.empty() && data.aux_records.front().start < end) {
265*288bf522SAndroid Build Coastguard Worker     const AuxRecordData& aux = data.aux_records.front();
266*288bf522SAndroid Build Coastguard Worker     if (aux.start >= start && aux.end <= end) {
267*288bf522SAndroid Build Coastguard Worker       uint8_t* p = data.aux_data.data() + (aux.start - start);
268*288bf522SAndroid Build Coastguard Worker       if (!etm_decoder_) {
269*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "ETMDecoder isn't created";
270*288bf522SAndroid Build Coastguard Worker         return false;
271*288bf522SAndroid Build Coastguard Worker       }
272*288bf522SAndroid Build Coastguard Worker       if (!etm_decoder_->ProcessData(p, aux.end - aux.start, aux.formatted, r.Cpu())) {
273*288bf522SAndroid Build Coastguard Worker         return false;
274*288bf522SAndroid Build Coastguard Worker       }
275*288bf522SAndroid Build Coastguard Worker     }
276*288bf522SAndroid Build Coastguard Worker     data.aux_records.pop();
277*288bf522SAndroid Build Coastguard Worker   }
278*288bf522SAndroid Build Coastguard Worker   return true;
279*288bf522SAndroid Build Coastguard Worker }
280*288bf522SAndroid Build Coastguard Worker 
ProcessBranchList(const ETMBranchList & branch_list)281*288bf522SAndroid Build Coastguard Worker void ETMBranchListGeneratorImpl::ProcessBranchList(const ETMBranchList& branch_list) {
282*288bf522SAndroid Build Coastguard Worker   if (!binary_filter_.Filter(branch_list.dso)) {
283*288bf522SAndroid Build Coastguard Worker     return;
284*288bf522SAndroid Build Coastguard Worker   }
285*288bf522SAndroid Build Coastguard Worker   auto& branch_map = branch_list_binary_map_[branch_list.dso].branch_map;
286*288bf522SAndroid Build Coastguard Worker   ++branch_map[branch_list.addr][branch_list.branch];
287*288bf522SAndroid Build Coastguard Worker }
288*288bf522SAndroid Build Coastguard Worker 
GetETMBinaryMap()289*288bf522SAndroid Build Coastguard Worker ETMBinaryMap ETMBranchListGeneratorImpl::GetETMBinaryMap() {
290*288bf522SAndroid Build Coastguard Worker   ETMBinaryMap binary_map;
291*288bf522SAndroid Build Coastguard Worker   for (auto& p : branch_list_binary_map_) {
292*288bf522SAndroid Build Coastguard Worker     Dso* dso = p.first;
293*288bf522SAndroid Build Coastguard Worker     ETMBinary& binary = p.second;
294*288bf522SAndroid Build Coastguard Worker     binary.dso_type = dso->type();
295*288bf522SAndroid Build Coastguard Worker     BuildId build_id;
296*288bf522SAndroid Build Coastguard Worker     GetBuildId(*dso, build_id);
297*288bf522SAndroid Build Coastguard Worker     BinaryKey key(dso->Path(), build_id);
298*288bf522SAndroid Build Coastguard Worker     if (binary.dso_type == DSO_KERNEL) {
299*288bf522SAndroid Build Coastguard Worker       if (kernel_map_start_addr_ == 0) {
300*288bf522SAndroid Build Coastguard Worker         LOG(WARNING) << "Can't convert kernel ip addresses without kernel start addr. So remove "
301*288bf522SAndroid Build Coastguard Worker                         "branches for the kernel.";
302*288bf522SAndroid Build Coastguard Worker         continue;
303*288bf522SAndroid Build Coastguard Worker       }
304*288bf522SAndroid Build Coastguard Worker       key.kernel_start_addr = kernel_map_start_addr_;
305*288bf522SAndroid Build Coastguard Worker     }
306*288bf522SAndroid Build Coastguard Worker     binary_map[key] = std::move(binary);
307*288bf522SAndroid Build Coastguard Worker   }
308*288bf522SAndroid Build Coastguard Worker   return binary_map;
309*288bf522SAndroid Build Coastguard Worker }
310*288bf522SAndroid Build Coastguard Worker 
Create(bool dump_maps_from_proc)311*288bf522SAndroid Build Coastguard Worker std::unique_ptr<ETMBranchListGenerator> ETMBranchListGenerator::Create(bool dump_maps_from_proc) {
312*288bf522SAndroid Build Coastguard Worker   return std::unique_ptr<ETMBranchListGenerator>(
313*288bf522SAndroid Build Coastguard Worker       new ETMBranchListGeneratorImpl(dump_maps_from_proc));
314*288bf522SAndroid Build Coastguard Worker }
315*288bf522SAndroid Build Coastguard Worker 
~ETMBranchListGenerator()316*288bf522SAndroid Build Coastguard Worker ETMBranchListGenerator::~ETMBranchListGenerator() {}
317*288bf522SAndroid Build Coastguard Worker 
LBRDataToString(const LBRData & data,std::string & s)318*288bf522SAndroid Build Coastguard Worker bool LBRDataToString(const LBRData& data, std::string& s) {
319*288bf522SAndroid Build Coastguard Worker   auto writer = BranchListProtoWriter::CreateForString(&s, false);
320*288bf522SAndroid Build Coastguard Worker   if (!writer) {
321*288bf522SAndroid Build Coastguard Worker     return false;
322*288bf522SAndroid Build Coastguard Worker   }
323*288bf522SAndroid Build Coastguard Worker   if (!writer->Write(data)) {
324*288bf522SAndroid Build Coastguard Worker     return false;
325*288bf522SAndroid Build Coastguard Worker   }
326*288bf522SAndroid Build Coastguard Worker   return true;
327*288bf522SAndroid Build Coastguard Worker }
328*288bf522SAndroid Build Coastguard Worker 
CreateForFile(const std::string & output_filename,bool compress,size_t max_branches_per_message)329*288bf522SAndroid Build Coastguard Worker std::unique_ptr<BranchListProtoWriter> BranchListProtoWriter::CreateForFile(
330*288bf522SAndroid Build Coastguard Worker     const std::string& output_filename, bool compress, size_t max_branches_per_message) {
331*288bf522SAndroid Build Coastguard Worker   auto writer = std::unique_ptr<BranchListProtoWriter>(
332*288bf522SAndroid Build Coastguard Worker       new BranchListProtoWriter(output_filename, nullptr, compress, max_branches_per_message));
333*288bf522SAndroid Build Coastguard Worker   if (!writer->WriteHeader()) {
334*288bf522SAndroid Build Coastguard Worker     return nullptr;
335*288bf522SAndroid Build Coastguard Worker   }
336*288bf522SAndroid Build Coastguard Worker   return writer;
337*288bf522SAndroid Build Coastguard Worker }
338*288bf522SAndroid Build Coastguard Worker 
CreateForString(std::string * output_str,bool compress,size_t max_branches_per_message)339*288bf522SAndroid Build Coastguard Worker std::unique_ptr<BranchListProtoWriter> BranchListProtoWriter::CreateForString(
340*288bf522SAndroid Build Coastguard Worker     std::string* output_str, bool compress, size_t max_branches_per_message) {
341*288bf522SAndroid Build Coastguard Worker   auto writer = std::unique_ptr<BranchListProtoWriter>(
342*288bf522SAndroid Build Coastguard Worker       new BranchListProtoWriter("", output_str, compress, max_branches_per_message));
343*288bf522SAndroid Build Coastguard Worker   if (!writer->WriteHeader()) {
344*288bf522SAndroid Build Coastguard Worker     return nullptr;
345*288bf522SAndroid Build Coastguard Worker   }
346*288bf522SAndroid Build Coastguard Worker   return writer;
347*288bf522SAndroid Build Coastguard Worker }
348*288bf522SAndroid Build Coastguard Worker 
Write(const ETMBinaryMap & etm_data)349*288bf522SAndroid Build Coastguard Worker bool BranchListProtoWriter::Write(const ETMBinaryMap& etm_data) {
350*288bf522SAndroid Build Coastguard Worker   if (!output_fp_ && !WriteHeader()) {
351*288bf522SAndroid Build Coastguard Worker     return false;
352*288bf522SAndroid Build Coastguard Worker   }
353*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<proto::BranchList> proto_branch_list = std::make_unique<proto::BranchList>();
354*288bf522SAndroid Build Coastguard Worker   proto::ETMBinary* proto_binary = nullptr;
355*288bf522SAndroid Build Coastguard Worker   proto::ETMBinary_Address* proto_addr = nullptr;
356*288bf522SAndroid Build Coastguard Worker   size_t branch_count = 0;
357*288bf522SAndroid Build Coastguard Worker 
358*288bf522SAndroid Build Coastguard Worker   auto add_proto_binary = [&](const BinaryKey& key, const ETMBinary& binary) {
359*288bf522SAndroid Build Coastguard Worker     proto_binary = proto_branch_list->add_etm_data();
360*288bf522SAndroid Build Coastguard Worker     proto_binary->set_path(key.path);
361*288bf522SAndroid Build Coastguard Worker     if (!key.build_id.IsEmpty()) {
362*288bf522SAndroid Build Coastguard Worker       proto_binary->set_build_id(key.build_id.ToString().substr(2));
363*288bf522SAndroid Build Coastguard Worker     }
364*288bf522SAndroid Build Coastguard Worker     auto opt_binary_type = ToProtoBinaryType(binary.dso_type);
365*288bf522SAndroid Build Coastguard Worker     if (!opt_binary_type.has_value()) {
366*288bf522SAndroid Build Coastguard Worker       return false;
367*288bf522SAndroid Build Coastguard Worker     }
368*288bf522SAndroid Build Coastguard Worker     proto_binary->set_type(opt_binary_type.value());
369*288bf522SAndroid Build Coastguard Worker     if (binary.dso_type == DSO_KERNEL) {
370*288bf522SAndroid Build Coastguard Worker       proto_binary->mutable_kernel_info()->set_kernel_start_addr(key.kernel_start_addr);
371*288bf522SAndroid Build Coastguard Worker     }
372*288bf522SAndroid Build Coastguard Worker     return true;
373*288bf522SAndroid Build Coastguard Worker   };
374*288bf522SAndroid Build Coastguard Worker 
375*288bf522SAndroid Build Coastguard Worker   auto add_proto_addr = [&](uint64_t addr) {
376*288bf522SAndroid Build Coastguard Worker     proto_addr = proto_binary->add_addrs();
377*288bf522SAndroid Build Coastguard Worker     proto_addr->set_addr(addr);
378*288bf522SAndroid Build Coastguard Worker   };
379*288bf522SAndroid Build Coastguard Worker 
380*288bf522SAndroid Build Coastguard Worker   for (const auto& [key, binary] : etm_data) {
381*288bf522SAndroid Build Coastguard Worker     if (!add_proto_binary(key, binary)) {
382*288bf522SAndroid Build Coastguard Worker       return false;
383*288bf522SAndroid Build Coastguard Worker     }
384*288bf522SAndroid Build Coastguard Worker     for (const auto& [addr, branch_map] : binary.branch_map) {
385*288bf522SAndroid Build Coastguard Worker       add_proto_addr(addr);
386*288bf522SAndroid Build Coastguard Worker       size_t new_branch_count = 0;
387*288bf522SAndroid Build Coastguard Worker       for (const auto& [branch, _] : branch_map) {
388*288bf522SAndroid Build Coastguard Worker         new_branch_count += branch.size();
389*288bf522SAndroid Build Coastguard Worker       }
390*288bf522SAndroid Build Coastguard Worker       if (branch_count + new_branch_count > max_branches_per_message_) {
391*288bf522SAndroid Build Coastguard Worker         if (!WriteProtoBranchList(*proto_branch_list)) {
392*288bf522SAndroid Build Coastguard Worker           return false;
393*288bf522SAndroid Build Coastguard Worker         }
394*288bf522SAndroid Build Coastguard Worker         proto_branch_list.reset(new proto::BranchList);
395*288bf522SAndroid Build Coastguard Worker         if (!add_proto_binary(key, binary)) {
396*288bf522SAndroid Build Coastguard Worker           return false;
397*288bf522SAndroid Build Coastguard Worker         }
398*288bf522SAndroid Build Coastguard Worker         add_proto_addr(addr);
399*288bf522SAndroid Build Coastguard Worker         branch_count = 0;
400*288bf522SAndroid Build Coastguard Worker       }
401*288bf522SAndroid Build Coastguard Worker       branch_count += new_branch_count;
402*288bf522SAndroid Build Coastguard Worker       for (const auto& [branch, count] : branch_map) {
403*288bf522SAndroid Build Coastguard Worker         proto::ETMBinary_Address_Branch* proto_branch = proto_addr->add_branches();
404*288bf522SAndroid Build Coastguard Worker         proto_branch->set_branch(ETMBranchToProtoString(branch));
405*288bf522SAndroid Build Coastguard Worker         proto_branch->set_branch_size(branch.size());
406*288bf522SAndroid Build Coastguard Worker         proto_branch->set_count(count);
407*288bf522SAndroid Build Coastguard Worker       }
408*288bf522SAndroid Build Coastguard Worker     }
409*288bf522SAndroid Build Coastguard Worker   }
410*288bf522SAndroid Build Coastguard Worker   return WriteProtoBranchList(*proto_branch_list);
411*288bf522SAndroid Build Coastguard Worker }
412*288bf522SAndroid Build Coastguard Worker 
Write(const LBRData & lbr_data)413*288bf522SAndroid Build Coastguard Worker bool BranchListProtoWriter::Write(const LBRData& lbr_data) {
414*288bf522SAndroid Build Coastguard Worker   if (!output_fp_ && !WriteHeader()) {
415*288bf522SAndroid Build Coastguard Worker     return false;
416*288bf522SAndroid Build Coastguard Worker   }
417*288bf522SAndroid Build Coastguard Worker   proto::BranchList proto_branch_list;
418*288bf522SAndroid Build Coastguard Worker   proto_branch_list.set_magic(ETM_BRANCH_LIST_PROTO_MAGIC);
419*288bf522SAndroid Build Coastguard Worker   auto proto_lbr = proto_branch_list.mutable_lbr_data();
420*288bf522SAndroid Build Coastguard Worker   for (const LBRSample& sample : lbr_data.samples) {
421*288bf522SAndroid Build Coastguard Worker     auto proto_sample = proto_lbr->add_samples();
422*288bf522SAndroid Build Coastguard Worker     proto_sample->set_binary_id(sample.binary_id);
423*288bf522SAndroid Build Coastguard Worker     proto_sample->set_vaddr_in_file(sample.vaddr_in_file);
424*288bf522SAndroid Build Coastguard Worker     for (const LBRBranch& branch : sample.branches) {
425*288bf522SAndroid Build Coastguard Worker       auto proto_branch = proto_sample->add_branches();
426*288bf522SAndroid Build Coastguard Worker       proto_branch->set_from_binary_id(branch.from_binary_id);
427*288bf522SAndroid Build Coastguard Worker       proto_branch->set_to_binary_id(branch.to_binary_id);
428*288bf522SAndroid Build Coastguard Worker       proto_branch->set_from_vaddr_in_file(branch.from_vaddr_in_file);
429*288bf522SAndroid Build Coastguard Worker       proto_branch->set_to_vaddr_in_file(branch.to_vaddr_in_file);
430*288bf522SAndroid Build Coastguard Worker     }
431*288bf522SAndroid Build Coastguard Worker   }
432*288bf522SAndroid Build Coastguard Worker   for (const BinaryKey& binary : lbr_data.binaries) {
433*288bf522SAndroid Build Coastguard Worker     auto proto_binary = proto_lbr->add_binaries();
434*288bf522SAndroid Build Coastguard Worker     proto_binary->set_path(binary.path);
435*288bf522SAndroid Build Coastguard Worker     proto_binary->set_build_id(binary.build_id.ToString().substr(2));
436*288bf522SAndroid Build Coastguard Worker   }
437*288bf522SAndroid Build Coastguard Worker   return WriteProtoBranchList(proto_branch_list);
438*288bf522SAndroid Build Coastguard Worker }
439*288bf522SAndroid Build Coastguard Worker 
WriteHeader()440*288bf522SAndroid Build Coastguard Worker bool BranchListProtoWriter::WriteHeader() {
441*288bf522SAndroid Build Coastguard Worker   if (!output_filename_.empty()) {
442*288bf522SAndroid Build Coastguard Worker     output_fp_.reset(fopen(output_filename_.c_str(), "wbe"));
443*288bf522SAndroid Build Coastguard Worker     if (!output_fp_) {
444*288bf522SAndroid Build Coastguard Worker       PLOG(ERROR) << "failed to open " << output_filename_;
445*288bf522SAndroid Build Coastguard Worker       return false;
446*288bf522SAndroid Build Coastguard Worker     }
447*288bf522SAndroid Build Coastguard Worker   } else {
448*288bf522SAndroid Build Coastguard Worker     output_str_->clear();
449*288bf522SAndroid Build Coastguard Worker   }
450*288bf522SAndroid Build Coastguard Worker   if (!WriteData(ETM_BRANCH_LIST_PROTO_MAGIC, strlen(ETM_BRANCH_LIST_PROTO_MAGIC))) {
451*288bf522SAndroid Build Coastguard Worker     return false;
452*288bf522SAndroid Build Coastguard Worker   }
453*288bf522SAndroid Build Coastguard Worker   uint32_t version = 1;
454*288bf522SAndroid Build Coastguard Worker   if (!WriteData(&version, sizeof(version))) {
455*288bf522SAndroid Build Coastguard Worker     return false;
456*288bf522SAndroid Build Coastguard Worker   }
457*288bf522SAndroid Build Coastguard Worker   uint8_t compress = compress_ ? 1 : 0;
458*288bf522SAndroid Build Coastguard Worker   if (!WriteData(&compress, sizeof(compress))) {
459*288bf522SAndroid Build Coastguard Worker     return false;
460*288bf522SAndroid Build Coastguard Worker   }
461*288bf522SAndroid Build Coastguard Worker   return true;
462*288bf522SAndroid Build Coastguard Worker }
463*288bf522SAndroid Build Coastguard Worker 
WriteProtoBranchList(proto::BranchList & branch_list)464*288bf522SAndroid Build Coastguard Worker bool BranchListProtoWriter::WriteProtoBranchList(proto::BranchList& branch_list) {
465*288bf522SAndroid Build Coastguard Worker   std::string s;
466*288bf522SAndroid Build Coastguard Worker   if (!branch_list.SerializeToString(&s)) {
467*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "failed to serialize branch list binary map";
468*288bf522SAndroid Build Coastguard Worker     return false;
469*288bf522SAndroid Build Coastguard Worker   }
470*288bf522SAndroid Build Coastguard Worker   if (compress_ && !ZstdCompress(s.data(), s.size(), s)) {
471*288bf522SAndroid Build Coastguard Worker     return false;
472*288bf522SAndroid Build Coastguard Worker   }
473*288bf522SAndroid Build Coastguard Worker   uint32_t msg_size = s.size();
474*288bf522SAndroid Build Coastguard Worker   return WriteData(&msg_size, sizeof(msg_size)) && WriteData(s.data(), s.size());
475*288bf522SAndroid Build Coastguard Worker }
476*288bf522SAndroid Build Coastguard Worker 
WriteData(const void * data,size_t size)477*288bf522SAndroid Build Coastguard Worker bool BranchListProtoWriter::WriteData(const void* data, size_t size) {
478*288bf522SAndroid Build Coastguard Worker   if (output_fp_) {
479*288bf522SAndroid Build Coastguard Worker     if (fwrite(data, size, 1, output_fp_.get()) != 1) {
480*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "failed to write to " << output_filename_;
481*288bf522SAndroid Build Coastguard Worker       return false;
482*288bf522SAndroid Build Coastguard Worker     }
483*288bf522SAndroid Build Coastguard Worker   } else {
484*288bf522SAndroid Build Coastguard Worker     output_str_->insert(output_str_->size(), static_cast<const char*>(data), size);
485*288bf522SAndroid Build Coastguard Worker   }
486*288bf522SAndroid Build Coastguard Worker   return true;
487*288bf522SAndroid Build Coastguard Worker }
488*288bf522SAndroid Build Coastguard Worker 
CreateForFile(const std::string & input_filename)489*288bf522SAndroid Build Coastguard Worker std::unique_ptr<BranchListProtoReader> BranchListProtoReader::CreateForFile(
490*288bf522SAndroid Build Coastguard Worker     const std::string& input_filename) {
491*288bf522SAndroid Build Coastguard Worker   return std::unique_ptr<BranchListProtoReader>(new BranchListProtoReader(input_filename, ""));
492*288bf522SAndroid Build Coastguard Worker }
493*288bf522SAndroid Build Coastguard Worker 
CreateForString(const std::string & input_str)494*288bf522SAndroid Build Coastguard Worker std::unique_ptr<BranchListProtoReader> BranchListProtoReader::CreateForString(
495*288bf522SAndroid Build Coastguard Worker     const std::string& input_str) {
496*288bf522SAndroid Build Coastguard Worker   return std::unique_ptr<BranchListProtoReader>(new BranchListProtoReader("", input_str));
497*288bf522SAndroid Build Coastguard Worker }
498*288bf522SAndroid Build Coastguard Worker 
Read(ETMBinaryMap & etm_data,LBRData & lbr_data)499*288bf522SAndroid Build Coastguard Worker bool BranchListProtoReader::Read(ETMBinaryMap& etm_data, LBRData& lbr_data) {
500*288bf522SAndroid Build Coastguard Worker   if (!input_filename_.empty()) {
501*288bf522SAndroid Build Coastguard Worker     input_fp_.reset(fopen(input_filename_.c_str(), "rbe"));
502*288bf522SAndroid Build Coastguard Worker     if (!input_fp_) {
503*288bf522SAndroid Build Coastguard Worker       PLOG(ERROR) << "failed to open " << input_filename_;
504*288bf522SAndroid Build Coastguard Worker       return false;
505*288bf522SAndroid Build Coastguard Worker     }
506*288bf522SAndroid Build Coastguard Worker   }
507*288bf522SAndroid Build Coastguard Worker   char magic[24];
508*288bf522SAndroid Build Coastguard Worker   if (!ReadData(magic, sizeof(magic)) ||
509*288bf522SAndroid Build Coastguard Worker       memcmp(magic, ETM_BRANCH_LIST_PROTO_MAGIC, sizeof(magic)) != 0) {
510*288bf522SAndroid Build Coastguard Worker     return ReadOldFileFormat(etm_data, lbr_data);
511*288bf522SAndroid Build Coastguard Worker   }
512*288bf522SAndroid Build Coastguard Worker   uint32_t version;
513*288bf522SAndroid Build Coastguard Worker   if (!ReadData(&version, sizeof(version)) && version != 1) {
514*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "unsupported version in " << input_filename_;
515*288bf522SAndroid Build Coastguard Worker     return false;
516*288bf522SAndroid Build Coastguard Worker   }
517*288bf522SAndroid Build Coastguard Worker   uint8_t compress;
518*288bf522SAndroid Build Coastguard Worker   if (!ReadData(&compress, sizeof(compress))) {
519*288bf522SAndroid Build Coastguard Worker     return false;
520*288bf522SAndroid Build Coastguard Worker   }
521*288bf522SAndroid Build Coastguard Worker   compress_ = compress == 1;
522*288bf522SAndroid Build Coastguard Worker   long file_offset = ftell(input_fp_.get());
523*288bf522SAndroid Build Coastguard Worker   if (file_offset == -1) {
524*288bf522SAndroid Build Coastguard Worker     PLOG(ERROR) << "failed to call ftell";
525*288bf522SAndroid Build Coastguard Worker     return false;
526*288bf522SAndroid Build Coastguard Worker   }
527*288bf522SAndroid Build Coastguard Worker   uint64_t file_size = GetFileSize(input_filename_);
528*288bf522SAndroid Build Coastguard Worker   while (file_offset < file_size) {
529*288bf522SAndroid Build Coastguard Worker     uint32_t msg_size;
530*288bf522SAndroid Build Coastguard Worker     if (!ReadData(&msg_size, sizeof(msg_size))) {
531*288bf522SAndroid Build Coastguard Worker       return false;
532*288bf522SAndroid Build Coastguard Worker     }
533*288bf522SAndroid Build Coastguard Worker     proto::BranchList proto_branch_list;
534*288bf522SAndroid Build Coastguard Worker     if (!ReadProtoBranchList(msg_size, proto_branch_list)) {
535*288bf522SAndroid Build Coastguard Worker       return false;
536*288bf522SAndroid Build Coastguard Worker     }
537*288bf522SAndroid Build Coastguard Worker     for (size_t i = 0; i < proto_branch_list.etm_data_size(); i++) {
538*288bf522SAndroid Build Coastguard Worker       const proto::ETMBinary& proto_binary = proto_branch_list.etm_data(i);
539*288bf522SAndroid Build Coastguard Worker       if (!AddETMBinary(proto_binary, etm_data)) {
540*288bf522SAndroid Build Coastguard Worker         return false;
541*288bf522SAndroid Build Coastguard Worker       }
542*288bf522SAndroid Build Coastguard Worker     }
543*288bf522SAndroid Build Coastguard Worker     if (proto_branch_list.has_lbr_data()) {
544*288bf522SAndroid Build Coastguard Worker       AddLBRData(proto_branch_list.lbr_data(), lbr_data);
545*288bf522SAndroid Build Coastguard Worker     }
546*288bf522SAndroid Build Coastguard Worker     file_offset += 4 + msg_size;
547*288bf522SAndroid Build Coastguard Worker   }
548*288bf522SAndroid Build Coastguard Worker   return true;
549*288bf522SAndroid Build Coastguard Worker }
550*288bf522SAndroid Build Coastguard Worker 
AddETMBinary(const proto::ETMBinary & proto_binary,ETMBinaryMap & etm_data)551*288bf522SAndroid Build Coastguard Worker bool BranchListProtoReader::AddETMBinary(const proto::ETMBinary& proto_binary,
552*288bf522SAndroid Build Coastguard Worker                                          ETMBinaryMap& etm_data) {
553*288bf522SAndroid Build Coastguard Worker   BinaryKey key(proto_binary.path(), BuildId(proto_binary.build_id()));
554*288bf522SAndroid Build Coastguard Worker   if (proto_binary.has_kernel_info()) {
555*288bf522SAndroid Build Coastguard Worker     key.kernel_start_addr = proto_binary.kernel_info().kernel_start_addr();
556*288bf522SAndroid Build Coastguard Worker   }
557*288bf522SAndroid Build Coastguard Worker   ETMBinary& binary = etm_data[key];
558*288bf522SAndroid Build Coastguard Worker   auto dso_type = ToDsoType(proto_binary.type());
559*288bf522SAndroid Build Coastguard Worker   if (!dso_type) {
560*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "invalid binary type " << proto_binary.type();
561*288bf522SAndroid Build Coastguard Worker     return false;
562*288bf522SAndroid Build Coastguard Worker   }
563*288bf522SAndroid Build Coastguard Worker   binary.dso_type = dso_type.value();
564*288bf522SAndroid Build Coastguard Worker   auto& branch_map = binary.branch_map;
565*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < proto_binary.addrs_size(); i++) {
566*288bf522SAndroid Build Coastguard Worker     const auto& proto_addr = proto_binary.addrs(i);
567*288bf522SAndroid Build Coastguard Worker     auto& b_map = branch_map[proto_addr.addr()];
568*288bf522SAndroid Build Coastguard Worker     for (size_t j = 0; j < proto_addr.branches_size(); j++) {
569*288bf522SAndroid Build Coastguard Worker       const auto& proto_branch = proto_addr.branches(j);
570*288bf522SAndroid Build Coastguard Worker       std::vector<bool> branch =
571*288bf522SAndroid Build Coastguard Worker           ProtoStringToETMBranch(proto_branch.branch(), proto_branch.branch_size());
572*288bf522SAndroid Build Coastguard Worker       b_map[branch] = proto_branch.count();
573*288bf522SAndroid Build Coastguard Worker     }
574*288bf522SAndroid Build Coastguard Worker   }
575*288bf522SAndroid Build Coastguard Worker   return true;
576*288bf522SAndroid Build Coastguard Worker }
577*288bf522SAndroid Build Coastguard Worker 
AddLBRData(const proto::LBRData & proto_lbr_data,LBRData & lbr_data)578*288bf522SAndroid Build Coastguard Worker void BranchListProtoReader::AddLBRData(const proto::LBRData& proto_lbr_data, LBRData& lbr_data) {
579*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < proto_lbr_data.samples_size(); ++i) {
580*288bf522SAndroid Build Coastguard Worker     const auto& proto_sample = proto_lbr_data.samples(i);
581*288bf522SAndroid Build Coastguard Worker     lbr_data.samples.resize(lbr_data.samples.size() + 1);
582*288bf522SAndroid Build Coastguard Worker     LBRSample& sample = lbr_data.samples.back();
583*288bf522SAndroid Build Coastguard Worker     sample.binary_id = proto_sample.binary_id();
584*288bf522SAndroid Build Coastguard Worker     sample.vaddr_in_file = proto_sample.vaddr_in_file();
585*288bf522SAndroid Build Coastguard Worker     sample.branches.resize(proto_sample.branches_size());
586*288bf522SAndroid Build Coastguard Worker     for (size_t j = 0; j < proto_sample.branches_size(); ++j) {
587*288bf522SAndroid Build Coastguard Worker       const auto& proto_branch = proto_sample.branches(j);
588*288bf522SAndroid Build Coastguard Worker       LBRBranch& branch = sample.branches[j];
589*288bf522SAndroid Build Coastguard Worker       branch.from_binary_id = proto_branch.from_binary_id();
590*288bf522SAndroid Build Coastguard Worker       branch.to_binary_id = proto_branch.to_binary_id();
591*288bf522SAndroid Build Coastguard Worker       branch.from_vaddr_in_file = proto_branch.from_vaddr_in_file();
592*288bf522SAndroid Build Coastguard Worker       branch.to_vaddr_in_file = proto_branch.to_vaddr_in_file();
593*288bf522SAndroid Build Coastguard Worker     }
594*288bf522SAndroid Build Coastguard Worker   }
595*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < proto_lbr_data.binaries_size(); ++i) {
596*288bf522SAndroid Build Coastguard Worker     const auto& proto_binary = proto_lbr_data.binaries(i);
597*288bf522SAndroid Build Coastguard Worker     lbr_data.binaries.emplace_back(proto_binary.path(), BuildId(proto_binary.build_id()));
598*288bf522SAndroid Build Coastguard Worker   }
599*288bf522SAndroid Build Coastguard Worker }
600*288bf522SAndroid Build Coastguard Worker 
ReadProtoBranchList(uint32_t size,proto::BranchList & proto_branch_list)601*288bf522SAndroid Build Coastguard Worker bool BranchListProtoReader::ReadProtoBranchList(uint32_t size,
602*288bf522SAndroid Build Coastguard Worker                                                 proto::BranchList& proto_branch_list) {
603*288bf522SAndroid Build Coastguard Worker   std::string s;
604*288bf522SAndroid Build Coastguard Worker   s.resize(size);
605*288bf522SAndroid Build Coastguard Worker   if (!ReadData(s.data(), size)) {
606*288bf522SAndroid Build Coastguard Worker     return false;
607*288bf522SAndroid Build Coastguard Worker   }
608*288bf522SAndroid Build Coastguard Worker   if (compress_ && !ZstdDecompress(s.data(), s.size(), s)) {
609*288bf522SAndroid Build Coastguard Worker     return false;
610*288bf522SAndroid Build Coastguard Worker   }
611*288bf522SAndroid Build Coastguard Worker   if (!proto_branch_list.ParseFromString(s)) {
612*288bf522SAndroid Build Coastguard Worker     PLOG(ERROR) << "failed to read ETMBranchList msg";
613*288bf522SAndroid Build Coastguard Worker     return false;
614*288bf522SAndroid Build Coastguard Worker   }
615*288bf522SAndroid Build Coastguard Worker   return true;
616*288bf522SAndroid Build Coastguard Worker }
617*288bf522SAndroid Build Coastguard Worker 
Rewind()618*288bf522SAndroid Build Coastguard Worker void BranchListProtoReader::Rewind() {
619*288bf522SAndroid Build Coastguard Worker   if (input_fp_) {
620*288bf522SAndroid Build Coastguard Worker     rewind(input_fp_.get());
621*288bf522SAndroid Build Coastguard Worker   } else {
622*288bf522SAndroid Build Coastguard Worker     input_str_pos_ = 0;
623*288bf522SAndroid Build Coastguard Worker   }
624*288bf522SAndroid Build Coastguard Worker }
625*288bf522SAndroid Build Coastguard Worker 
ReadData(void * data,size_t size)626*288bf522SAndroid Build Coastguard Worker bool BranchListProtoReader::ReadData(void* data, size_t size) {
627*288bf522SAndroid Build Coastguard Worker   if (input_fp_) {
628*288bf522SAndroid Build Coastguard Worker     if (fread(data, size, 1, input_fp_.get()) != 1) {
629*288bf522SAndroid Build Coastguard Worker       PLOG(ERROR) << "failed to read " << input_filename_;
630*288bf522SAndroid Build Coastguard Worker       return false;
631*288bf522SAndroid Build Coastguard Worker     }
632*288bf522SAndroid Build Coastguard Worker   } else {
633*288bf522SAndroid Build Coastguard Worker     if (input_str_pos_ + size > input_str_.size()) {
634*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "failed to read BranchList from string";
635*288bf522SAndroid Build Coastguard Worker       return false;
636*288bf522SAndroid Build Coastguard Worker     }
637*288bf522SAndroid Build Coastguard Worker     memcpy(data, &input_str_[input_str_pos_], size);
638*288bf522SAndroid Build Coastguard Worker     input_str_pos_ += size;
639*288bf522SAndroid Build Coastguard Worker   }
640*288bf522SAndroid Build Coastguard Worker   return true;
641*288bf522SAndroid Build Coastguard Worker }
642*288bf522SAndroid Build Coastguard Worker 
ReadOldFileFormat(ETMBinaryMap & etm_data,LBRData & lbr_data)643*288bf522SAndroid Build Coastguard Worker bool BranchListProtoReader::ReadOldFileFormat(ETMBinaryMap& etm_data, LBRData& lbr_data) {
644*288bf522SAndroid Build Coastguard Worker   size_t size = 0;
645*288bf522SAndroid Build Coastguard Worker   if (!input_filename_.empty()) {
646*288bf522SAndroid Build Coastguard Worker     size = static_cast<size_t>(GetFileSize(input_filename_));
647*288bf522SAndroid Build Coastguard Worker     if (android::base::EndsWith(input_filename_, ".zst")) {
648*288bf522SAndroid Build Coastguard Worker       compress_ = true;
649*288bf522SAndroid Build Coastguard Worker     }
650*288bf522SAndroid Build Coastguard Worker   } else {
651*288bf522SAndroid Build Coastguard Worker     size = input_str_.size();
652*288bf522SAndroid Build Coastguard Worker   }
653*288bf522SAndroid Build Coastguard Worker   Rewind();
654*288bf522SAndroid Build Coastguard Worker   proto::BranchList proto_branch_list;
655*288bf522SAndroid Build Coastguard Worker   if (!ReadProtoBranchList(size, proto_branch_list)) {
656*288bf522SAndroid Build Coastguard Worker     return false;
657*288bf522SAndroid Build Coastguard Worker   }
658*288bf522SAndroid Build Coastguard Worker   if (proto_branch_list.magic() != ETM_BRANCH_LIST_PROTO_MAGIC) {
659*288bf522SAndroid Build Coastguard Worker     PLOG(ERROR) << "not in format of branch_list.proto";
660*288bf522SAndroid Build Coastguard Worker   }
661*288bf522SAndroid Build Coastguard Worker   for (size_t i = 0; i < proto_branch_list.etm_data_size(); i++) {
662*288bf522SAndroid Build Coastguard Worker     const proto::ETMBinary& proto_binary = proto_branch_list.etm_data(i);
663*288bf522SAndroid Build Coastguard Worker     if (!AddETMBinary(proto_binary, etm_data)) {
664*288bf522SAndroid Build Coastguard Worker       return false;
665*288bf522SAndroid Build Coastguard Worker     }
666*288bf522SAndroid Build Coastguard Worker   }
667*288bf522SAndroid Build Coastguard Worker   if (proto_branch_list.has_lbr_data()) {
668*288bf522SAndroid Build Coastguard Worker     AddLBRData(proto_branch_list.lbr_data(), lbr_data);
669*288bf522SAndroid Build Coastguard Worker   }
670*288bf522SAndroid Build Coastguard Worker   return true;
671*288bf522SAndroid Build Coastguard Worker }
672*288bf522SAndroid Build Coastguard Worker 
DumpBranchListFile(std::string filename)673*288bf522SAndroid Build Coastguard Worker bool DumpBranchListFile(std::string filename) {
674*288bf522SAndroid Build Coastguard Worker   ETMBinaryMap etm_data;
675*288bf522SAndroid Build Coastguard Worker   LBRData lbr_data;
676*288bf522SAndroid Build Coastguard Worker   auto reader = BranchListProtoReader::CreateForFile(filename);
677*288bf522SAndroid Build Coastguard Worker   if (!reader || !reader->Read(etm_data, lbr_data)) {
678*288bf522SAndroid Build Coastguard Worker     return false;
679*288bf522SAndroid Build Coastguard Worker   }
680*288bf522SAndroid Build Coastguard Worker 
681*288bf522SAndroid Build Coastguard Worker   if (!etm_data.empty()) {
682*288bf522SAndroid Build Coastguard Worker     std::vector<BinaryKey> sorted_keys;
683*288bf522SAndroid Build Coastguard Worker     for (const auto& [key, _] : etm_data) {
684*288bf522SAndroid Build Coastguard Worker       sorted_keys.emplace_back(key);
685*288bf522SAndroid Build Coastguard Worker     }
686*288bf522SAndroid Build Coastguard Worker     std::sort(sorted_keys.begin(), sorted_keys.end(),
687*288bf522SAndroid Build Coastguard Worker               [](const BinaryKey& key1, const BinaryKey& key2) { return key1.path < key2.path; });
688*288bf522SAndroid Build Coastguard Worker     PrintIndented(0, "etm_data:\n");
689*288bf522SAndroid Build Coastguard Worker     for (size_t i = 0; i < sorted_keys.size(); ++i) {
690*288bf522SAndroid Build Coastguard Worker       const auto& key = sorted_keys[i];
691*288bf522SAndroid Build Coastguard Worker       const auto& binary = etm_data[key];
692*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "binary[%zu].path: %s\n", i, key.path.c_str());
693*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "binary[%zu].build_id: %s\n", i, key.build_id.ToString().c_str());
694*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "binary[%zu].binary_type: %s\n", i, DsoTypeToString(binary.dso_type));
695*288bf522SAndroid Build Coastguard Worker       if (binary.dso_type == DSO_KERNEL) {
696*288bf522SAndroid Build Coastguard Worker         PrintIndented(1, "binary[%zu].kernel_start_addr: 0x%" PRIx64 "\n", i,
697*288bf522SAndroid Build Coastguard Worker                       key.kernel_start_addr);
698*288bf522SAndroid Build Coastguard Worker       }
699*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "binary[%zu].addrs:\n", i);
700*288bf522SAndroid Build Coastguard Worker       size_t addr_id = 0;
701*288bf522SAndroid Build Coastguard Worker       for (const auto& [addr, branches] : binary.GetOrderedBranchMap()) {
702*288bf522SAndroid Build Coastguard Worker         PrintIndented(2, "addr[%zu]: 0x%" PRIx64 "\n", addr_id++, addr);
703*288bf522SAndroid Build Coastguard Worker         size_t branch_id = 0;
704*288bf522SAndroid Build Coastguard Worker         for (const auto& [branch, count] : branches) {
705*288bf522SAndroid Build Coastguard Worker           std::string s = "0b";
706*288bf522SAndroid Build Coastguard Worker           for (auto it = branch.rbegin(); it != branch.rend(); ++it) {
707*288bf522SAndroid Build Coastguard Worker             s.push_back(*it ? '1' : '0');
708*288bf522SAndroid Build Coastguard Worker           }
709*288bf522SAndroid Build Coastguard Worker           PrintIndented(3, "branch[%zu].branch: %s\n", branch_id, s.c_str());
710*288bf522SAndroid Build Coastguard Worker           PrintIndented(3, "branch[%zu].count: %" PRIu64 "\n", branch_id, count);
711*288bf522SAndroid Build Coastguard Worker           ++branch_id;
712*288bf522SAndroid Build Coastguard Worker         }
713*288bf522SAndroid Build Coastguard Worker       }
714*288bf522SAndroid Build Coastguard Worker     }
715*288bf522SAndroid Build Coastguard Worker   }
716*288bf522SAndroid Build Coastguard Worker   if (!lbr_data.samples.empty()) {
717*288bf522SAndroid Build Coastguard Worker     PrintIndented(0, "lbr_data:\n");
718*288bf522SAndroid Build Coastguard Worker     for (size_t i = 0; i < lbr_data.samples.size(); ++i) {
719*288bf522SAndroid Build Coastguard Worker       const auto& sample = lbr_data.samples[i];
720*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "sample[%zu].binary_id: %u\n", i, sample.binary_id);
721*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "sample[%zu].vaddr_in_file: 0x%" PRIx64 "\n", i, sample.vaddr_in_file);
722*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "sample[%zu].branches:\n", i);
723*288bf522SAndroid Build Coastguard Worker       for (size_t j = 0; j < sample.branches.size(); ++j) {
724*288bf522SAndroid Build Coastguard Worker         const auto& branch = sample.branches[j];
725*288bf522SAndroid Build Coastguard Worker         PrintIndented(2, "branch[%zu].from_binary_id: %u\n", j, branch.from_binary_id);
726*288bf522SAndroid Build Coastguard Worker         PrintIndented(2, "branch[%zu].from_vaddr_in_file: 0x%" PRIx64 "\n", j,
727*288bf522SAndroid Build Coastguard Worker                       branch.from_vaddr_in_file);
728*288bf522SAndroid Build Coastguard Worker         PrintIndented(2, "branch[%zu].to_binary_id: %u\n", j, branch.to_binary_id);
729*288bf522SAndroid Build Coastguard Worker         PrintIndented(2, "branch[%zu].to_vaddr_in_file: 0x%" PRIx64 "\n", j,
730*288bf522SAndroid Build Coastguard Worker                       branch.to_vaddr_in_file);
731*288bf522SAndroid Build Coastguard Worker       }
732*288bf522SAndroid Build Coastguard Worker     }
733*288bf522SAndroid Build Coastguard Worker     for (size_t i = 0; i < lbr_data.binaries.size(); ++i) {
734*288bf522SAndroid Build Coastguard Worker       const auto& binary = lbr_data.binaries[i];
735*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "binary[%zu].path: %s\n", i, binary.path.c_str());
736*288bf522SAndroid Build Coastguard Worker       PrintIndented(1, "binary[%zu].build_id: %s\n", i, binary.build_id.ToString().c_str());
737*288bf522SAndroid Build Coastguard Worker     }
738*288bf522SAndroid Build Coastguard Worker   }
739*288bf522SAndroid Build Coastguard Worker   return true;
740*288bf522SAndroid Build Coastguard Worker }
741*288bf522SAndroid Build Coastguard Worker 
742*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
743