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