xref: /aosp_15_r20/system/extras/simpleperf/cmd_debug_unwind.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2018 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 <stdio.h>
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include <algorithm>
20*288bf522SAndroid Build Coastguard Worker #include <memory>
21*288bf522SAndroid Build Coastguard Worker #include <string>
22*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
23*288bf522SAndroid Build Coastguard Worker #include <unordered_set>
24*288bf522SAndroid Build Coastguard Worker #include <vector>
25*288bf522SAndroid Build Coastguard Worker 
26*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
27*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
28*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
29*288bf522SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
30*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
31*288bf522SAndroid Build Coastguard Worker 
32*288bf522SAndroid Build Coastguard Worker #include "JITDebugReader.h"
33*288bf522SAndroid Build Coastguard Worker #include "OfflineUnwinder.h"
34*288bf522SAndroid Build Coastguard Worker #include "command.h"
35*288bf522SAndroid Build Coastguard Worker #include "environment.h"
36*288bf522SAndroid Build Coastguard Worker #include "perf_regs.h"
37*288bf522SAndroid Build Coastguard Worker #include "record_file.h"
38*288bf522SAndroid Build Coastguard Worker #include "report_utils.h"
39*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
40*288bf522SAndroid Build Coastguard Worker #include "utils.h"
41*288bf522SAndroid Build Coastguard Worker 
42*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
43*288bf522SAndroid Build Coastguard Worker namespace {
44*288bf522SAndroid Build Coastguard Worker 
45*288bf522SAndroid Build Coastguard Worker struct MemStat {
46*288bf522SAndroid Build Coastguard Worker   std::string vm_peak;
47*288bf522SAndroid Build Coastguard Worker   std::string vm_size;
48*288bf522SAndroid Build Coastguard Worker   std::string vm_hwm;
49*288bf522SAndroid Build Coastguard Worker   std::string vm_rss;
50*288bf522SAndroid Build Coastguard Worker 
ToStringsimpleperf::__anon8518cc540111::MemStat51*288bf522SAndroid Build Coastguard Worker   std::string ToString() const {
52*288bf522SAndroid Build Coastguard Worker     return android::base::StringPrintf("VmPeak:%s;VmSize:%s;VmHWM:%s;VmRSS:%s", vm_peak.c_str(),
53*288bf522SAndroid Build Coastguard Worker                                        vm_size.c_str(), vm_hwm.c_str(), vm_rss.c_str());
54*288bf522SAndroid Build Coastguard Worker   }
55*288bf522SAndroid Build Coastguard Worker };
56*288bf522SAndroid Build Coastguard Worker 
GetMemStat(MemStat * stat)57*288bf522SAndroid Build Coastguard Worker static bool GetMemStat(MemStat* stat) {
58*288bf522SAndroid Build Coastguard Worker   std::string s;
59*288bf522SAndroid Build Coastguard Worker   if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/status", getpid()),
60*288bf522SAndroid Build Coastguard Worker                                        &s)) {
61*288bf522SAndroid Build Coastguard Worker     PLOG(ERROR) << "Failed to read process status";
62*288bf522SAndroid Build Coastguard Worker     return false;
63*288bf522SAndroid Build Coastguard Worker   }
64*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> lines = android::base::Split(s, "\n");
65*288bf522SAndroid Build Coastguard Worker   for (auto& line : lines) {
66*288bf522SAndroid Build Coastguard Worker     if (android::base::StartsWith(line, "VmPeak:")) {
67*288bf522SAndroid Build Coastguard Worker       stat->vm_peak = android::base::Trim(line.substr(strlen("VmPeak:")));
68*288bf522SAndroid Build Coastguard Worker     } else if (android::base::StartsWith(line, "VmSize:")) {
69*288bf522SAndroid Build Coastguard Worker       stat->vm_size = android::base::Trim(line.substr(strlen("VmSize:")));
70*288bf522SAndroid Build Coastguard Worker     } else if (android::base::StartsWith(line, "VmHWM:")) {
71*288bf522SAndroid Build Coastguard Worker       stat->vm_hwm = android::base::Trim(line.substr(strlen("VmHWM:")));
72*288bf522SAndroid Build Coastguard Worker     } else if (android::base::StartsWith(line, "VmRSS:")) {
73*288bf522SAndroid Build Coastguard Worker       stat->vm_rss = android::base::Trim(line.substr(strlen("VmRSS:")));
74*288bf522SAndroid Build Coastguard Worker     }
75*288bf522SAndroid Build Coastguard Worker   }
76*288bf522SAndroid Build Coastguard Worker   return true;
77*288bf522SAndroid Build Coastguard Worker }
78*288bf522SAndroid Build Coastguard Worker 
79*288bf522SAndroid Build Coastguard Worker struct UnwindingStat {
80*288bf522SAndroid Build Coastguard Worker   // For testing unwinding performance
81*288bf522SAndroid Build Coastguard Worker   uint64_t unwinding_sample_count = 0u;
82*288bf522SAndroid Build Coastguard Worker   uint64_t total_unwinding_time_in_ns = 0u;
83*288bf522SAndroid Build Coastguard Worker   uint64_t max_unwinding_time_in_ns = 0u;
84*288bf522SAndroid Build Coastguard Worker 
85*288bf522SAndroid Build Coastguard Worker   // For memory consumption
86*288bf522SAndroid Build Coastguard Worker   MemStat mem_before_unwinding;
87*288bf522SAndroid Build Coastguard Worker   MemStat mem_after_unwinding;
88*288bf522SAndroid Build Coastguard Worker 
AddUnwindingResultsimpleperf::__anon8518cc540111::UnwindingStat89*288bf522SAndroid Build Coastguard Worker   void AddUnwindingResult(const UnwindingResult& result) {
90*288bf522SAndroid Build Coastguard Worker     unwinding_sample_count++;
91*288bf522SAndroid Build Coastguard Worker     total_unwinding_time_in_ns += result.used_time;
92*288bf522SAndroid Build Coastguard Worker     max_unwinding_time_in_ns = std::max(max_unwinding_time_in_ns, result.used_time);
93*288bf522SAndroid Build Coastguard Worker   }
94*288bf522SAndroid Build Coastguard Worker 
Dumpsimpleperf::__anon8518cc540111::UnwindingStat95*288bf522SAndroid Build Coastguard Worker   void Dump(FILE* fp) {
96*288bf522SAndroid Build Coastguard Worker     if (unwinding_sample_count == 0) {
97*288bf522SAndroid Build Coastguard Worker       return;
98*288bf522SAndroid Build Coastguard Worker     }
99*288bf522SAndroid Build Coastguard Worker     fprintf(fp, "unwinding_sample_count: %" PRIu64 "\n", unwinding_sample_count);
100*288bf522SAndroid Build Coastguard Worker     fprintf(fp, "average_unwinding_time: %.3f us\n",
101*288bf522SAndroid Build Coastguard Worker             total_unwinding_time_in_ns / 1e3 / unwinding_sample_count);
102*288bf522SAndroid Build Coastguard Worker     fprintf(fp, "max_unwinding_time: %.3f us\n", max_unwinding_time_in_ns / 1e3);
103*288bf522SAndroid Build Coastguard Worker 
104*288bf522SAndroid Build Coastguard Worker     if (!mem_before_unwinding.vm_peak.empty()) {
105*288bf522SAndroid Build Coastguard Worker       fprintf(fp, "memory_change_VmPeak: %s -> %s\n", mem_before_unwinding.vm_peak.c_str(),
106*288bf522SAndroid Build Coastguard Worker               mem_after_unwinding.vm_peak.c_str());
107*288bf522SAndroid Build Coastguard Worker       fprintf(fp, "memory_change_VmSize: %s -> %s\n", mem_before_unwinding.vm_size.c_str(),
108*288bf522SAndroid Build Coastguard Worker               mem_after_unwinding.vm_size.c_str());
109*288bf522SAndroid Build Coastguard Worker       fprintf(fp, "memory_change_VmHwM: %s -> %s\n", mem_before_unwinding.vm_hwm.c_str(),
110*288bf522SAndroid Build Coastguard Worker               mem_after_unwinding.vm_hwm.c_str());
111*288bf522SAndroid Build Coastguard Worker       fprintf(fp, "memory_change_VmRSS: %s -> %s\n", mem_before_unwinding.vm_rss.c_str(),
112*288bf522SAndroid Build Coastguard Worker               mem_after_unwinding.vm_rss.c_str());
113*288bf522SAndroid Build Coastguard Worker     }
114*288bf522SAndroid Build Coastguard Worker   }
115*288bf522SAndroid Build Coastguard Worker };
116*288bf522SAndroid Build Coastguard Worker 
117*288bf522SAndroid Build Coastguard Worker class RecordFileProcessor {
118*288bf522SAndroid Build Coastguard Worker  public:
RecordFileProcessor(const std::string & output_filename,bool output_binary_mode)119*288bf522SAndroid Build Coastguard Worker   RecordFileProcessor(const std::string& output_filename, bool output_binary_mode)
120*288bf522SAndroid Build Coastguard Worker       : output_filename_(output_filename),
121*288bf522SAndroid Build Coastguard Worker         output_binary_mode_(output_binary_mode),
122*288bf522SAndroid Build Coastguard Worker         unwinder_(OfflineUnwinder::Create(true)),
123*288bf522SAndroid Build Coastguard Worker         callchain_report_builder_(thread_tree_) {}
124*288bf522SAndroid Build Coastguard Worker 
~RecordFileProcessor()125*288bf522SAndroid Build Coastguard Worker   virtual ~RecordFileProcessor() {
126*288bf522SAndroid Build Coastguard Worker     if (out_fp_ != nullptr && out_fp_ != stdout) {
127*288bf522SAndroid Build Coastguard Worker       fclose(out_fp_);
128*288bf522SAndroid Build Coastguard Worker     }
129*288bf522SAndroid Build Coastguard Worker   }
130*288bf522SAndroid Build Coastguard Worker 
ProcessFile(const std::string & input_filename)131*288bf522SAndroid Build Coastguard Worker   bool ProcessFile(const std::string& input_filename) {
132*288bf522SAndroid Build Coastguard Worker     // 1. Check input file.
133*288bf522SAndroid Build Coastguard Worker     record_filename_ = input_filename;
134*288bf522SAndroid Build Coastguard Worker     reader_ = RecordFileReader::CreateInstance(record_filename_);
135*288bf522SAndroid Build Coastguard Worker     if (!reader_) {
136*288bf522SAndroid Build Coastguard Worker       return false;
137*288bf522SAndroid Build Coastguard Worker     }
138*288bf522SAndroid Build Coastguard Worker     std::string record_cmd = android::base::Join(reader_->ReadCmdlineFeature(), " ");
139*288bf522SAndroid Build Coastguard Worker     if (record_cmd.find("-g") == std::string::npos &&
140*288bf522SAndroid Build Coastguard Worker         record_cmd.find("--call-graph dwarf") == std::string::npos) {
141*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "file isn't recorded with dwarf call graph: " << record_filename_;
142*288bf522SAndroid Build Coastguard Worker       return false;
143*288bf522SAndroid Build Coastguard Worker     }
144*288bf522SAndroid Build Coastguard Worker     if (!CheckRecordCmd(record_cmd)) {
145*288bf522SAndroid Build Coastguard Worker       return false;
146*288bf522SAndroid Build Coastguard Worker     }
147*288bf522SAndroid Build Coastguard Worker 
148*288bf522SAndroid Build Coastguard Worker     // 2. Load feature sections.
149*288bf522SAndroid Build Coastguard Worker     if (!reader_->LoadBuildIdAndFileFeatures(thread_tree_)) {
150*288bf522SAndroid Build Coastguard Worker       return false;
151*288bf522SAndroid Build Coastguard Worker     }
152*288bf522SAndroid Build Coastguard Worker     ScopedCurrentArch scoped_arch(
153*288bf522SAndroid Build Coastguard Worker         GetArchType(reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH)));
154*288bf522SAndroid Build Coastguard Worker     unwinder_->LoadMetaInfo(reader_->GetMetaInfoFeature());
155*288bf522SAndroid Build Coastguard Worker     if (reader_->HasFeature(PerfFileFormat::FEAT_DEBUG_UNWIND) &&
156*288bf522SAndroid Build Coastguard Worker         reader_->HasFeature(PerfFileFormat::FEAT_DEBUG_UNWIND_FILE)) {
157*288bf522SAndroid Build Coastguard Worker       auto debug_unwind_feature = reader_->ReadDebugUnwindFeature();
158*288bf522SAndroid Build Coastguard Worker       if (!debug_unwind_feature.has_value()) {
159*288bf522SAndroid Build Coastguard Worker         return false;
160*288bf522SAndroid Build Coastguard Worker       }
161*288bf522SAndroid Build Coastguard Worker       uint64_t offset =
162*288bf522SAndroid Build Coastguard Worker           reader_->FeatureSectionDescriptors().at(PerfFileFormat::FEAT_DEBUG_UNWIND_FILE).offset;
163*288bf522SAndroid Build Coastguard Worker       for (DebugUnwindFile& file : debug_unwind_feature.value()) {
164*288bf522SAndroid Build Coastguard Worker         auto& loc = debug_unwind_files_[file.path];
165*288bf522SAndroid Build Coastguard Worker         loc.offset = offset;
166*288bf522SAndroid Build Coastguard Worker         loc.size = file.size;
167*288bf522SAndroid Build Coastguard Worker         offset += file.size;
168*288bf522SAndroid Build Coastguard Worker       }
169*288bf522SAndroid Build Coastguard Worker     }
170*288bf522SAndroid Build Coastguard Worker     callchain_report_builder_.SetRemoveArtFrame(false);
171*288bf522SAndroid Build Coastguard Worker     callchain_report_builder_.SetConvertJITFrame(false);
172*288bf522SAndroid Build Coastguard Worker 
173*288bf522SAndroid Build Coastguard Worker     // 3. Open output file.
174*288bf522SAndroid Build Coastguard Worker     if (output_filename_.empty()) {
175*288bf522SAndroid Build Coastguard Worker       out_fp_ = stdout;
176*288bf522SAndroid Build Coastguard Worker     } else {
177*288bf522SAndroid Build Coastguard Worker       out_fp_ = fopen(output_filename_.c_str(), output_binary_mode_ ? "web+" : "we+");
178*288bf522SAndroid Build Coastguard Worker       if (out_fp_ == nullptr) {
179*288bf522SAndroid Build Coastguard Worker         PLOG(ERROR) << "failed to write to " << output_filename_;
180*288bf522SAndroid Build Coastguard Worker         return false;
181*288bf522SAndroid Build Coastguard Worker       }
182*288bf522SAndroid Build Coastguard Worker     }
183*288bf522SAndroid Build Coastguard Worker 
184*288bf522SAndroid Build Coastguard Worker     // 4. Process records.
185*288bf522SAndroid Build Coastguard Worker     return Process();
186*288bf522SAndroid Build Coastguard Worker   }
187*288bf522SAndroid Build Coastguard Worker 
188*288bf522SAndroid Build Coastguard Worker  protected:
189*288bf522SAndroid Build Coastguard Worker   struct DebugUnwindFileLocation {
190*288bf522SAndroid Build Coastguard Worker     uint64_t offset;
191*288bf522SAndroid Build Coastguard Worker     uint64_t size;
192*288bf522SAndroid Build Coastguard Worker   };
193*288bf522SAndroid Build Coastguard Worker 
194*288bf522SAndroid Build Coastguard Worker   virtual bool CheckRecordCmd(const std::string& record_cmd) = 0;
195*288bf522SAndroid Build Coastguard Worker   virtual bool Process() = 0;
196*288bf522SAndroid Build Coastguard Worker 
197*288bf522SAndroid Build Coastguard Worker   std::string record_filename_;
198*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<RecordFileReader> reader_;
199*288bf522SAndroid Build Coastguard Worker   std::string output_filename_;
200*288bf522SAndroid Build Coastguard Worker   bool output_binary_mode_;
201*288bf522SAndroid Build Coastguard Worker   FILE* out_fp_ = nullptr;
202*288bf522SAndroid Build Coastguard Worker   ThreadTree thread_tree_;
203*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<OfflineUnwinder> unwinder_;
204*288bf522SAndroid Build Coastguard Worker   // Files stored in DEBUG_UNWIND_FILE feature section in the recording file.
205*288bf522SAndroid Build Coastguard Worker   // Map from file path to offset in the recording file.
206*288bf522SAndroid Build Coastguard Worker   std::unordered_map<std::string, DebugUnwindFileLocation> debug_unwind_files_;
207*288bf522SAndroid Build Coastguard Worker   CallChainReportBuilder callchain_report_builder_;
208*288bf522SAndroid Build Coastguard Worker };
209*288bf522SAndroid Build Coastguard Worker 
DumpUnwindingResult(const UnwindingResult & result,FILE * fp)210*288bf522SAndroid Build Coastguard Worker static void DumpUnwindingResult(const UnwindingResult& result, FILE* fp) {
211*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "unwinding_used_time: %.3f us\n", result.used_time / 1e3);
212*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "unwinding_error_code: %" PRIu64 "\n", result.error_code);
213*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "unwinding_error_addr: 0x%" PRIx64 "\n", result.error_addr);
214*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "stack_start: 0x%" PRIx64 "\n", result.stack_start);
215*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "stack_end: 0x%" PRIx64 "\n", result.stack_end);
216*288bf522SAndroid Build Coastguard Worker }
217*288bf522SAndroid Build Coastguard Worker 
218*288bf522SAndroid Build Coastguard Worker class SampleUnwinder : public RecordFileProcessor {
219*288bf522SAndroid Build Coastguard Worker  public:
SampleUnwinder(const std::string & output_filename,const std::unordered_set<uint64_t> & sample_times,bool skip_sample_print)220*288bf522SAndroid Build Coastguard Worker   SampleUnwinder(const std::string& output_filename,
221*288bf522SAndroid Build Coastguard Worker                  const std::unordered_set<uint64_t>& sample_times, bool skip_sample_print)
222*288bf522SAndroid Build Coastguard Worker       : RecordFileProcessor(output_filename, false),
223*288bf522SAndroid Build Coastguard Worker         sample_times_(sample_times),
224*288bf522SAndroid Build Coastguard Worker         skip_sample_print_(skip_sample_print) {}
225*288bf522SAndroid Build Coastguard Worker 
226*288bf522SAndroid Build Coastguard Worker  protected:
CheckRecordCmd(const std::string & record_cmd)227*288bf522SAndroid Build Coastguard Worker   bool CheckRecordCmd(const std::string& record_cmd) override {
228*288bf522SAndroid Build Coastguard Worker     if (record_cmd.find("--no-unwind") == std::string::npos &&
229*288bf522SAndroid Build Coastguard Worker         record_cmd.find("--keep-failed-unwinding-debug-info") == std::string::npos) {
230*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "file isn't record with --no-unwind or --keep-failed-unwinding-debug-info: "
231*288bf522SAndroid Build Coastguard Worker                  << record_filename_;
232*288bf522SAndroid Build Coastguard Worker       return false;
233*288bf522SAndroid Build Coastguard Worker     }
234*288bf522SAndroid Build Coastguard Worker     return true;
235*288bf522SAndroid Build Coastguard Worker   }
236*288bf522SAndroid Build Coastguard Worker 
Process()237*288bf522SAndroid Build Coastguard Worker   bool Process() override {
238*288bf522SAndroid Build Coastguard Worker     if (!GetMemStat(&stat_.mem_before_unwinding)) {
239*288bf522SAndroid Build Coastguard Worker       return false;
240*288bf522SAndroid Build Coastguard Worker     }
241*288bf522SAndroid Build Coastguard Worker     if (!reader_->ReadDataSection(
242*288bf522SAndroid Build Coastguard Worker             [&](std::unique_ptr<Record> r) { return ProcessRecord(std::move(r)); })) {
243*288bf522SAndroid Build Coastguard Worker       return false;
244*288bf522SAndroid Build Coastguard Worker     }
245*288bf522SAndroid Build Coastguard Worker     if (!GetMemStat(&stat_.mem_after_unwinding)) {
246*288bf522SAndroid Build Coastguard Worker       return false;
247*288bf522SAndroid Build Coastguard Worker     }
248*288bf522SAndroid Build Coastguard Worker     stat_.Dump(out_fp_);
249*288bf522SAndroid Build Coastguard Worker     return true;
250*288bf522SAndroid Build Coastguard Worker   }
251*288bf522SAndroid Build Coastguard Worker 
ProcessRecord(std::unique_ptr<Record> r)252*288bf522SAndroid Build Coastguard Worker   bool ProcessRecord(std::unique_ptr<Record> r) {
253*288bf522SAndroid Build Coastguard Worker     UpdateRecord(r.get());
254*288bf522SAndroid Build Coastguard Worker     thread_tree_.Update(*r);
255*288bf522SAndroid Build Coastguard Worker     if (r->type() == SIMPLE_PERF_RECORD_UNWINDING_RESULT) {
256*288bf522SAndroid Build Coastguard Worker       last_unwinding_result_.reset(static_cast<UnwindingResultRecord*>(r.release()));
257*288bf522SAndroid Build Coastguard Worker     } else if (r->type() == PERF_RECORD_SAMPLE) {
258*288bf522SAndroid Build Coastguard Worker       if (sample_times_.empty() || sample_times_.count(r->Timestamp())) {
259*288bf522SAndroid Build Coastguard Worker         auto& sr = *static_cast<SampleRecord*>(r.get());
260*288bf522SAndroid Build Coastguard Worker         const PerfSampleStackUserType* stack = &sr.stack_user_data;
261*288bf522SAndroid Build Coastguard Worker         const PerfSampleRegsUserType* regs = &sr.regs_user_data;
262*288bf522SAndroid Build Coastguard Worker         if (last_unwinding_result_ && last_unwinding_result_->Timestamp() == sr.Timestamp()) {
263*288bf522SAndroid Build Coastguard Worker           stack = &last_unwinding_result_->stack_user_data;
264*288bf522SAndroid Build Coastguard Worker           regs = &last_unwinding_result_->regs_user_data;
265*288bf522SAndroid Build Coastguard Worker         }
266*288bf522SAndroid Build Coastguard Worker         if (stack->size > 0 || regs->reg_mask > 0) {
267*288bf522SAndroid Build Coastguard Worker           if (!UnwindRecord(sr, *regs, *stack)) {
268*288bf522SAndroid Build Coastguard Worker             return false;
269*288bf522SAndroid Build Coastguard Worker           }
270*288bf522SAndroid Build Coastguard Worker         }
271*288bf522SAndroid Build Coastguard Worker       }
272*288bf522SAndroid Build Coastguard Worker       last_unwinding_result_.reset();
273*288bf522SAndroid Build Coastguard Worker     }
274*288bf522SAndroid Build Coastguard Worker     return true;
275*288bf522SAndroid Build Coastguard Worker   }
276*288bf522SAndroid Build Coastguard Worker 
UpdateRecord(Record * record)277*288bf522SAndroid Build Coastguard Worker   void UpdateRecord(Record* record) {
278*288bf522SAndroid Build Coastguard Worker     if (record->type() == PERF_RECORD_MMAP) {
279*288bf522SAndroid Build Coastguard Worker       UpdateMmapRecordForEmbeddedFiles(*static_cast<MmapRecord*>(record));
280*288bf522SAndroid Build Coastguard Worker     } else if (record->type() == PERF_RECORD_MMAP2) {
281*288bf522SAndroid Build Coastguard Worker       UpdateMmapRecordForEmbeddedFiles(*static_cast<Mmap2Record*>(record));
282*288bf522SAndroid Build Coastguard Worker     }
283*288bf522SAndroid Build Coastguard Worker   }
284*288bf522SAndroid Build Coastguard Worker 
285*288bf522SAndroid Build Coastguard Worker   template <typename MmapRecordType>
UpdateMmapRecordForEmbeddedFiles(MmapRecordType & record)286*288bf522SAndroid Build Coastguard Worker   void UpdateMmapRecordForEmbeddedFiles(MmapRecordType& record) {
287*288bf522SAndroid Build Coastguard Worker     // Modify mmap records to point to files stored in DEBUG_UNWIND_FILE feature section.
288*288bf522SAndroid Build Coastguard Worker     std::string filename = record.filename;
289*288bf522SAndroid Build Coastguard Worker     if (auto it = debug_unwind_files_.find(filename); it != debug_unwind_files_.end()) {
290*288bf522SAndroid Build Coastguard Worker       auto data = *record.data;
291*288bf522SAndroid Build Coastguard Worker       uint64_t old_pgoff = data.pgoff;
292*288bf522SAndroid Build Coastguard Worker       if (JITDebugReader::IsPathInJITSymFile(filename)) {
293*288bf522SAndroid Build Coastguard Worker         data.pgoff = it->second.offset;
294*288bf522SAndroid Build Coastguard Worker       } else {
295*288bf522SAndroid Build Coastguard Worker         data.pgoff += it->second.offset;
296*288bf522SAndroid Build Coastguard Worker       }
297*288bf522SAndroid Build Coastguard Worker       debug_unwind_dsos_[data.pgoff] =
298*288bf522SAndroid Build Coastguard Worker           std::make_pair(thread_tree_.FindUserDsoOrNew(filename), old_pgoff);
299*288bf522SAndroid Build Coastguard Worker       record.SetDataAndFilename(data, record_filename_);
300*288bf522SAndroid Build Coastguard Worker     }
301*288bf522SAndroid Build Coastguard Worker   }
302*288bf522SAndroid Build Coastguard Worker 
UnwindRecord(const SampleRecord & r,const PerfSampleRegsUserType & regs,const PerfSampleStackUserType & stack)303*288bf522SAndroid Build Coastguard Worker   bool UnwindRecord(const SampleRecord& r, const PerfSampleRegsUserType& regs,
304*288bf522SAndroid Build Coastguard Worker                     const PerfSampleStackUserType& stack) {
305*288bf522SAndroid Build Coastguard Worker     ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
306*288bf522SAndroid Build Coastguard Worker 
307*288bf522SAndroid Build Coastguard Worker     RegSet reg_set(regs.abi, regs.reg_mask, regs.regs);
308*288bf522SAndroid Build Coastguard Worker     std::vector<uint64_t> ips;
309*288bf522SAndroid Build Coastguard Worker     std::vector<uint64_t> sps;
310*288bf522SAndroid Build Coastguard Worker     if (!unwinder_->UnwindCallChain(*thread, reg_set, stack.data, stack.size, &ips, &sps)) {
311*288bf522SAndroid Build Coastguard Worker       return false;
312*288bf522SAndroid Build Coastguard Worker     }
313*288bf522SAndroid Build Coastguard Worker     stat_.AddUnwindingResult(unwinder_->GetUnwindingResult());
314*288bf522SAndroid Build Coastguard Worker 
315*288bf522SAndroid Build Coastguard Worker     if (!skip_sample_print_) {
316*288bf522SAndroid Build Coastguard Worker       // Print unwinding result.
317*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "sample_time: %" PRIu64 "\n", r.Timestamp());
318*288bf522SAndroid Build Coastguard Worker       DumpUnwindingResult(unwinder_->GetUnwindingResult(), out_fp_);
319*288bf522SAndroid Build Coastguard Worker       std::vector<CallChainReportEntry> entries = callchain_report_builder_.Build(thread, ips, 0);
320*288bf522SAndroid Build Coastguard Worker       for (size_t i = 0; i < entries.size(); i++) {
321*288bf522SAndroid Build Coastguard Worker         size_t id = i + 1;
322*288bf522SAndroid Build Coastguard Worker         auto& entry = entries[i];
323*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "ip_%zu: 0x%" PRIx64 "\n", id, entry.ip);
324*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "sp_%zu: 0x%" PRIx64 "\n", id, sps[i]);
325*288bf522SAndroid Build Coastguard Worker 
326*288bf522SAndroid Build Coastguard Worker         Dso* dso = entry.map->dso;
327*288bf522SAndroid Build Coastguard Worker         uint64_t pgoff = entry.map->pgoff;
328*288bf522SAndroid Build Coastguard Worker         if (dso->Path() == record_filename_) {
329*288bf522SAndroid Build Coastguard Worker           auto it = debug_unwind_dsos_.find(entry.map->pgoff);
330*288bf522SAndroid Build Coastguard Worker           CHECK(it != debug_unwind_dsos_.end());
331*288bf522SAndroid Build Coastguard Worker           const auto& p = it->second;
332*288bf522SAndroid Build Coastguard Worker           dso = p.first;
333*288bf522SAndroid Build Coastguard Worker           pgoff = p.second;
334*288bf522SAndroid Build Coastguard Worker           if (!JITDebugReader::IsPathInJITSymFile(dso->Path())) {
335*288bf522SAndroid Build Coastguard Worker             entry.vaddr_in_file = dso->IpToVaddrInFile(entry.ip, entry.map->start_addr, pgoff);
336*288bf522SAndroid Build Coastguard Worker           }
337*288bf522SAndroid Build Coastguard Worker           entry.symbol = dso->FindSymbol(entry.vaddr_in_file);
338*288bf522SAndroid Build Coastguard Worker         }
339*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "map_%zu: [0x%" PRIx64 "-0x%" PRIx64 "], pgoff 0x%" PRIx64 "\n", id,
340*288bf522SAndroid Build Coastguard Worker                 entry.map->start_addr, entry.map->get_end_addr(), pgoff);
341*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "dso_%zu: %s\n", id, dso->Path().c_str());
342*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "vaddr_in_file_%zu: 0x%" PRIx64 "\n", id, entry.vaddr_in_file);
343*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "symbol_%zu: %s\n", id, entry.symbol->DemangledName());
344*288bf522SAndroid Build Coastguard Worker       }
345*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "\n");
346*288bf522SAndroid Build Coastguard Worker     }
347*288bf522SAndroid Build Coastguard Worker     return true;
348*288bf522SAndroid Build Coastguard Worker   }
349*288bf522SAndroid Build Coastguard Worker 
350*288bf522SAndroid Build Coastguard Worker  private:
351*288bf522SAndroid Build Coastguard Worker   const std::unordered_set<uint64_t> sample_times_;
352*288bf522SAndroid Build Coastguard Worker   bool skip_sample_print_;
353*288bf522SAndroid Build Coastguard Worker   // Map from offset in recording file to the corresponding debug_unwind_file.
354*288bf522SAndroid Build Coastguard Worker   std::unordered_map<uint64_t, std::pair<Dso*, uint64_t>> debug_unwind_dsos_;
355*288bf522SAndroid Build Coastguard Worker   UnwindingStat stat_;
356*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<UnwindingResultRecord> last_unwinding_result_;
357*288bf522SAndroid Build Coastguard Worker };
358*288bf522SAndroid Build Coastguard Worker 
359*288bf522SAndroid Build Coastguard Worker class TestFileGenerator : public RecordFileProcessor {
360*288bf522SAndroid Build Coastguard Worker  public:
TestFileGenerator(const std::string & output_filename,const std::unordered_set<uint64_t> & sample_times,const std::unordered_set<std::string> & kept_binaries)361*288bf522SAndroid Build Coastguard Worker   TestFileGenerator(const std::string& output_filename,
362*288bf522SAndroid Build Coastguard Worker                     const std::unordered_set<uint64_t>& sample_times,
363*288bf522SAndroid Build Coastguard Worker                     const std::unordered_set<std::string>& kept_binaries)
364*288bf522SAndroid Build Coastguard Worker       : RecordFileProcessor(output_filename, true),
365*288bf522SAndroid Build Coastguard Worker         sample_times_(sample_times),
366*288bf522SAndroid Build Coastguard Worker         kept_binaries_(kept_binaries) {}
367*288bf522SAndroid Build Coastguard Worker 
368*288bf522SAndroid Build Coastguard Worker  protected:
CheckRecordCmd(const std::string &)369*288bf522SAndroid Build Coastguard Worker   bool CheckRecordCmd(const std::string&) override { return true; }
370*288bf522SAndroid Build Coastguard Worker 
Process()371*288bf522SAndroid Build Coastguard Worker   bool Process() override {
372*288bf522SAndroid Build Coastguard Worker     writer_.reset(new RecordFileWriter(output_filename_, out_fp_, false));
373*288bf522SAndroid Build Coastguard Worker     if (!writer_ || !writer_->WriteAttrSection(reader_->AttrSection())) {
374*288bf522SAndroid Build Coastguard Worker       return false;
375*288bf522SAndroid Build Coastguard Worker     }
376*288bf522SAndroid Build Coastguard Worker     if (!reader_->ReadDataSection(
377*288bf522SAndroid Build Coastguard Worker             [&](std::unique_ptr<Record> r) { return ProcessRecord(std::move(r)); })) {
378*288bf522SAndroid Build Coastguard Worker       return false;
379*288bf522SAndroid Build Coastguard Worker     }
380*288bf522SAndroid Build Coastguard Worker     return WriteFeatureSections();
381*288bf522SAndroid Build Coastguard Worker   }
382*288bf522SAndroid Build Coastguard Worker 
ProcessRecord(std::unique_ptr<Record> r)383*288bf522SAndroid Build Coastguard Worker   bool ProcessRecord(std::unique_ptr<Record> r) {
384*288bf522SAndroid Build Coastguard Worker     thread_tree_.Update(*r);
385*288bf522SAndroid Build Coastguard Worker     bool keep_record = false;
386*288bf522SAndroid Build Coastguard Worker     if (r->type() == SIMPLE_PERF_RECORD_UNWINDING_RESULT) {
387*288bf522SAndroid Build Coastguard Worker       keep_record = (sample_times_.count(r->Timestamp()) > 0);
388*288bf522SAndroid Build Coastguard Worker     } else if (r->type() == PERF_RECORD_SAMPLE) {
389*288bf522SAndroid Build Coastguard Worker       keep_record = (sample_times_.count(r->Timestamp()) > 0);
390*288bf522SAndroid Build Coastguard Worker       if (keep_record) {
391*288bf522SAndroid Build Coastguard Worker         // Dump maps needed to unwind this sample.
392*288bf522SAndroid Build Coastguard Worker         if (!WriteMapsForSample(*static_cast<SampleRecord*>(r.get()))) {
393*288bf522SAndroid Build Coastguard Worker           return false;
394*288bf522SAndroid Build Coastguard Worker         }
395*288bf522SAndroid Build Coastguard Worker       }
396*288bf522SAndroid Build Coastguard Worker     }
397*288bf522SAndroid Build Coastguard Worker     if (keep_record) {
398*288bf522SAndroid Build Coastguard Worker       return writer_->WriteRecord(*r);
399*288bf522SAndroid Build Coastguard Worker     }
400*288bf522SAndroid Build Coastguard Worker     return true;
401*288bf522SAndroid Build Coastguard Worker   }
402*288bf522SAndroid Build Coastguard Worker 
WriteMapsForSample(const SampleRecord & r)403*288bf522SAndroid Build Coastguard Worker   bool WriteMapsForSample(const SampleRecord& r) {
404*288bf522SAndroid Build Coastguard Worker     ThreadEntry* thread = thread_tree_.FindThread(r.tid_data.tid);
405*288bf522SAndroid Build Coastguard Worker     if (thread != nullptr && thread->maps) {
406*288bf522SAndroid Build Coastguard Worker       const EventAttrIds& attrs = reader_->AttrSection();
407*288bf522SAndroid Build Coastguard Worker       const perf_event_attr& attr = attrs[0].attr;
408*288bf522SAndroid Build Coastguard Worker       uint64_t event_id = attrs[0].ids[0];
409*288bf522SAndroid Build Coastguard Worker 
410*288bf522SAndroid Build Coastguard Worker       for (const auto& p : thread->maps->maps) {
411*288bf522SAndroid Build Coastguard Worker         const MapEntry* map = p.second;
412*288bf522SAndroid Build Coastguard Worker         Mmap2Record map_record(attr, false, r.tid_data.pid, r.tid_data.tid, map->start_addr,
413*288bf522SAndroid Build Coastguard Worker                                map->len, map->pgoff, map->flags, map->dso->Path(), event_id,
414*288bf522SAndroid Build Coastguard Worker                                r.Timestamp());
415*288bf522SAndroid Build Coastguard Worker         if (!writer_->WriteRecord(map_record)) {
416*288bf522SAndroid Build Coastguard Worker           return false;
417*288bf522SAndroid Build Coastguard Worker         }
418*288bf522SAndroid Build Coastguard Worker       }
419*288bf522SAndroid Build Coastguard Worker     }
420*288bf522SAndroid Build Coastguard Worker     return true;
421*288bf522SAndroid Build Coastguard Worker   }
422*288bf522SAndroid Build Coastguard Worker 
WriteFeatureSections()423*288bf522SAndroid Build Coastguard Worker   bool WriteFeatureSections() {
424*288bf522SAndroid Build Coastguard Worker     if (!writer_->BeginWriteFeatures(reader_->FeatureSectionDescriptors().size())) {
425*288bf522SAndroid Build Coastguard Worker       return false;
426*288bf522SAndroid Build Coastguard Worker     }
427*288bf522SAndroid Build Coastguard Worker     std::unordered_set<int> feature_types_to_copy = {
428*288bf522SAndroid Build Coastguard Worker         PerfFileFormat::FEAT_ARCH, PerfFileFormat::FEAT_CMDLINE, PerfFileFormat::FEAT_META_INFO};
429*288bf522SAndroid Build Coastguard Worker     const size_t BUFFER_SIZE = 64 * kKilobyte;
430*288bf522SAndroid Build Coastguard Worker     std::string buffer(BUFFER_SIZE, '\0');
431*288bf522SAndroid Build Coastguard Worker     for (const auto& p : reader_->FeatureSectionDescriptors()) {
432*288bf522SAndroid Build Coastguard Worker       auto feat_type = p.first;
433*288bf522SAndroid Build Coastguard Worker       if (feat_type == PerfFileFormat::FEAT_DEBUG_UNWIND) {
434*288bf522SAndroid Build Coastguard Worker         DebugUnwindFeature feature;
435*288bf522SAndroid Build Coastguard Worker         buffer.resize(BUFFER_SIZE);
436*288bf522SAndroid Build Coastguard Worker         for (const auto& file_p : debug_unwind_files_) {
437*288bf522SAndroid Build Coastguard Worker           if (kept_binaries_.count(file_p.first)) {
438*288bf522SAndroid Build Coastguard Worker             feature.resize(feature.size() + 1);
439*288bf522SAndroid Build Coastguard Worker             feature.back().path = file_p.first;
440*288bf522SAndroid Build Coastguard Worker             feature.back().size = file_p.second.size;
441*288bf522SAndroid Build Coastguard Worker             if (!CopyDebugUnwindFile(file_p.second, buffer)) {
442*288bf522SAndroid Build Coastguard Worker               return false;
443*288bf522SAndroid Build Coastguard Worker             }
444*288bf522SAndroid Build Coastguard Worker           }
445*288bf522SAndroid Build Coastguard Worker         }
446*288bf522SAndroid Build Coastguard Worker         if (!writer_->WriteDebugUnwindFeature(feature)) {
447*288bf522SAndroid Build Coastguard Worker           return false;
448*288bf522SAndroid Build Coastguard Worker         }
449*288bf522SAndroid Build Coastguard Worker       } else if (feat_type == PerfFileFormat::FEAT_FILE ||
450*288bf522SAndroid Build Coastguard Worker                  feat_type == PerfFileFormat::FEAT_FILE2) {
451*288bf522SAndroid Build Coastguard Worker         uint64_t read_pos = 0;
452*288bf522SAndroid Build Coastguard Worker         FileFeature file_feature;
453*288bf522SAndroid Build Coastguard Worker         bool error = false;
454*288bf522SAndroid Build Coastguard Worker         while (reader_->ReadFileFeature(read_pos, file_feature, error)) {
455*288bf522SAndroid Build Coastguard Worker           if (kept_binaries_.count(file_feature.path) && !writer_->WriteFileFeature(file_feature)) {
456*288bf522SAndroid Build Coastguard Worker             return false;
457*288bf522SAndroid Build Coastguard Worker           }
458*288bf522SAndroid Build Coastguard Worker         }
459*288bf522SAndroid Build Coastguard Worker         if (error) {
460*288bf522SAndroid Build Coastguard Worker           return false;
461*288bf522SAndroid Build Coastguard Worker         }
462*288bf522SAndroid Build Coastguard Worker       } else if (feat_type == PerfFileFormat::FEAT_BUILD_ID) {
463*288bf522SAndroid Build Coastguard Worker         std::vector<BuildIdRecord> build_ids = reader_->ReadBuildIdFeature();
464*288bf522SAndroid Build Coastguard Worker         std::vector<BuildIdRecord> write_build_ids;
465*288bf522SAndroid Build Coastguard Worker         for (auto& build_id : build_ids) {
466*288bf522SAndroid Build Coastguard Worker           if (kept_binaries_.count(build_id.filename)) {
467*288bf522SAndroid Build Coastguard Worker             write_build_ids.emplace_back(std::move(build_id));
468*288bf522SAndroid Build Coastguard Worker           }
469*288bf522SAndroid Build Coastguard Worker         }
470*288bf522SAndroid Build Coastguard Worker         if (!writer_->WriteBuildIdFeature(write_build_ids)) {
471*288bf522SAndroid Build Coastguard Worker           return false;
472*288bf522SAndroid Build Coastguard Worker         }
473*288bf522SAndroid Build Coastguard Worker       } else if (feature_types_to_copy.count(feat_type)) {
474*288bf522SAndroid Build Coastguard Worker         if (!reader_->ReadFeatureSection(feat_type, &buffer) ||
475*288bf522SAndroid Build Coastguard Worker             !writer_->WriteFeature(feat_type, buffer.data(), buffer.size())) {
476*288bf522SAndroid Build Coastguard Worker           return false;
477*288bf522SAndroid Build Coastguard Worker         }
478*288bf522SAndroid Build Coastguard Worker       }
479*288bf522SAndroid Build Coastguard Worker     }
480*288bf522SAndroid Build Coastguard Worker     return writer_->EndWriteFeatures() && writer_->Close();
481*288bf522SAndroid Build Coastguard Worker   }
482*288bf522SAndroid Build Coastguard Worker 
CopyDebugUnwindFile(const DebugUnwindFileLocation & loc,std::string & buffer)483*288bf522SAndroid Build Coastguard Worker   bool CopyDebugUnwindFile(const DebugUnwindFileLocation& loc, std::string& buffer) {
484*288bf522SAndroid Build Coastguard Worker     uint64_t offset = loc.offset;
485*288bf522SAndroid Build Coastguard Worker     uint64_t left_size = loc.size;
486*288bf522SAndroid Build Coastguard Worker     while (left_size > 0) {
487*288bf522SAndroid Build Coastguard Worker       size_t nread = std::min<size_t>(left_size, buffer.size());
488*288bf522SAndroid Build Coastguard Worker       if (!reader_->ReadAtOffset(offset, buffer.data(), nread) ||
489*288bf522SAndroid Build Coastguard Worker           !writer_->WriteFeature(PerfFileFormat::FEAT_DEBUG_UNWIND_FILE, buffer.data(), nread)) {
490*288bf522SAndroid Build Coastguard Worker         return false;
491*288bf522SAndroid Build Coastguard Worker       }
492*288bf522SAndroid Build Coastguard Worker       offset += nread;
493*288bf522SAndroid Build Coastguard Worker       left_size -= nread;
494*288bf522SAndroid Build Coastguard Worker     }
495*288bf522SAndroid Build Coastguard Worker     return true;
496*288bf522SAndroid Build Coastguard Worker   }
497*288bf522SAndroid Build Coastguard Worker 
498*288bf522SAndroid Build Coastguard Worker  private:
499*288bf522SAndroid Build Coastguard Worker   const std::unordered_set<uint64_t> sample_times_;
500*288bf522SAndroid Build Coastguard Worker   const std::unordered_set<std::string> kept_binaries_;
501*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<RecordFileWriter> writer_;
502*288bf522SAndroid Build Coastguard Worker };
503*288bf522SAndroid Build Coastguard Worker 
504*288bf522SAndroid Build Coastguard Worker class ReportGenerator : public RecordFileProcessor {
505*288bf522SAndroid Build Coastguard Worker  public:
ReportGenerator(const std::string & output_filename)506*288bf522SAndroid Build Coastguard Worker   ReportGenerator(const std::string& output_filename)
507*288bf522SAndroid Build Coastguard Worker       : RecordFileProcessor(output_filename, false) {}
508*288bf522SAndroid Build Coastguard Worker 
509*288bf522SAndroid Build Coastguard Worker  protected:
CheckRecordCmd(const std::string & record_cmd)510*288bf522SAndroid Build Coastguard Worker   bool CheckRecordCmd(const std::string& record_cmd) override {
511*288bf522SAndroid Build Coastguard Worker     if (record_cmd.find("--keep-failed-unwinding-debug-info") == std::string::npos &&
512*288bf522SAndroid Build Coastguard Worker         record_cmd.find("--keep-failed-unwinding-result") == std::string::npos) {
513*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "file isn't record with --keep-failed-unwinding-debug-info or "
514*288bf522SAndroid Build Coastguard Worker                  << "--keep-failed-unwinding-result: " << record_filename_;
515*288bf522SAndroid Build Coastguard Worker       return false;
516*288bf522SAndroid Build Coastguard Worker     }
517*288bf522SAndroid Build Coastguard Worker     return true;
518*288bf522SAndroid Build Coastguard Worker   }
519*288bf522SAndroid Build Coastguard Worker 
Process()520*288bf522SAndroid Build Coastguard Worker   bool Process() override {
521*288bf522SAndroid Build Coastguard Worker     if (!reader_->ReadDataSection(
522*288bf522SAndroid Build Coastguard Worker             [&](std::unique_ptr<Record> r) { return ProcessRecord(std::move(r)); })) {
523*288bf522SAndroid Build Coastguard Worker       return false;
524*288bf522SAndroid Build Coastguard Worker     }
525*288bf522SAndroid Build Coastguard Worker     return true;
526*288bf522SAndroid Build Coastguard Worker   }
527*288bf522SAndroid Build Coastguard Worker 
528*288bf522SAndroid Build Coastguard Worker  private:
ProcessRecord(std::unique_ptr<Record> r)529*288bf522SAndroid Build Coastguard Worker   bool ProcessRecord(std::unique_ptr<Record> r) {
530*288bf522SAndroid Build Coastguard Worker     thread_tree_.Update(*r);
531*288bf522SAndroid Build Coastguard Worker     if (r->type() == SIMPLE_PERF_RECORD_UNWINDING_RESULT) {
532*288bf522SAndroid Build Coastguard Worker       last_unwinding_result_.reset(static_cast<UnwindingResultRecord*>(r.release()));
533*288bf522SAndroid Build Coastguard Worker     } else if (r->type() == PERF_RECORD_SAMPLE) {
534*288bf522SAndroid Build Coastguard Worker       if (last_unwinding_result_) {
535*288bf522SAndroid Build Coastguard Worker         ReportUnwindingResult(*static_cast<SampleRecord*>(r.get()), *last_unwinding_result_);
536*288bf522SAndroid Build Coastguard Worker         last_unwinding_result_.reset();
537*288bf522SAndroid Build Coastguard Worker       }
538*288bf522SAndroid Build Coastguard Worker     }
539*288bf522SAndroid Build Coastguard Worker     return true;
540*288bf522SAndroid Build Coastguard Worker   }
541*288bf522SAndroid Build Coastguard Worker 
ReportUnwindingResult(const SampleRecord & sr,const UnwindingResultRecord & unwinding_r)542*288bf522SAndroid Build Coastguard Worker   void ReportUnwindingResult(const SampleRecord& sr, const UnwindingResultRecord& unwinding_r) {
543*288bf522SAndroid Build Coastguard Worker     ThreadEntry* thread = thread_tree_.FindThreadOrNew(sr.tid_data.pid, sr.tid_data.tid);
544*288bf522SAndroid Build Coastguard Worker     size_t kernel_ip_count;
545*288bf522SAndroid Build Coastguard Worker     std::vector<uint64_t> ips = sr.GetCallChain(&kernel_ip_count);
546*288bf522SAndroid Build Coastguard Worker     if (kernel_ip_count != 0) {
547*288bf522SAndroid Build Coastguard Worker       ips.erase(ips.begin(), ips.begin() + kernel_ip_count);
548*288bf522SAndroid Build Coastguard Worker     }
549*288bf522SAndroid Build Coastguard Worker 
550*288bf522SAndroid Build Coastguard Worker     fprintf(out_fp_, "sample_time: %" PRIu64 "\n", sr.Timestamp());
551*288bf522SAndroid Build Coastguard Worker     DumpUnwindingResult(unwinding_r.unwinding_result, out_fp_);
552*288bf522SAndroid Build Coastguard Worker     // Print callchain.
553*288bf522SAndroid Build Coastguard Worker     std::vector<CallChainReportEntry> entries = callchain_report_builder_.Build(thread, ips, 0);
554*288bf522SAndroid Build Coastguard Worker     for (size_t i = 0; i < entries.size(); i++) {
555*288bf522SAndroid Build Coastguard Worker       size_t id = i + 1;
556*288bf522SAndroid Build Coastguard Worker       const auto& entry = entries[i];
557*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "ip_%zu: 0x%" PRIx64 "\n", id, entry.ip);
558*288bf522SAndroid Build Coastguard Worker       if (i < unwinding_r.callchain.length) {
559*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "unwinding_ip_%zu: 0x%" PRIx64 "\n", id, unwinding_r.callchain.ips[i]);
560*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "unwinding_sp_%zu: 0x%" PRIx64 "\n", id, unwinding_r.callchain.sps[i]);
561*288bf522SAndroid Build Coastguard Worker       }
562*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "map_%zu: [0x%" PRIx64 "-0x%" PRIx64 "], pgoff 0x%" PRIx64 "\n", id,
563*288bf522SAndroid Build Coastguard Worker               entry.map->start_addr, entry.map->get_end_addr(), entry.map->pgoff);
564*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "dso_%zu: %s\n", id, entry.map->dso->Path().c_str());
565*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "vaddr_in_file_%zu: 0x%" PRIx64 "\n", id, entry.vaddr_in_file);
566*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "symbol_%zu: %s\n", id, entry.symbol->DemangledName());
567*288bf522SAndroid Build Coastguard Worker     }
568*288bf522SAndroid Build Coastguard Worker     // Print regs.
569*288bf522SAndroid Build Coastguard Worker     uint64_t stack_addr = 0;
570*288bf522SAndroid Build Coastguard Worker     if (unwinding_r.regs_user_data.reg_nr > 0) {
571*288bf522SAndroid Build Coastguard Worker       auto& reg_data = unwinding_r.regs_user_data;
572*288bf522SAndroid Build Coastguard Worker       RegSet regs(reg_data.abi, reg_data.reg_mask, reg_data.regs);
573*288bf522SAndroid Build Coastguard Worker       uint64_t value;
574*288bf522SAndroid Build Coastguard Worker       if (regs.GetSpRegValue(&value)) {
575*288bf522SAndroid Build Coastguard Worker         stack_addr = value;
576*288bf522SAndroid Build Coastguard Worker         for (size_t i = 0; i < 64; i++) {
577*288bf522SAndroid Build Coastguard Worker           if (regs.GetRegValue(i, &value)) {
578*288bf522SAndroid Build Coastguard Worker             fprintf(out_fp_, "reg_%s: 0x%" PRIx64 "\n", GetRegName(i, regs.arch).c_str(), value);
579*288bf522SAndroid Build Coastguard Worker           }
580*288bf522SAndroid Build Coastguard Worker         }
581*288bf522SAndroid Build Coastguard Worker       }
582*288bf522SAndroid Build Coastguard Worker     }
583*288bf522SAndroid Build Coastguard Worker     // Print stack.
584*288bf522SAndroid Build Coastguard Worker     if (unwinding_r.stack_user_data.size > 0) {
585*288bf522SAndroid Build Coastguard Worker       auto& stack = unwinding_r.stack_user_data;
586*288bf522SAndroid Build Coastguard Worker       const char* p = stack.data;
587*288bf522SAndroid Build Coastguard Worker       const char* end = stack.data + stack.size;
588*288bf522SAndroid Build Coastguard Worker       uint64_t value;
589*288bf522SAndroid Build Coastguard Worker       while (p + 8 <= end) {
590*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "stack_%" PRIx64 ":", stack_addr);
591*288bf522SAndroid Build Coastguard Worker         for (size_t i = 0; i < 4 && p + 8 <= end; ++i) {
592*288bf522SAndroid Build Coastguard Worker           MoveFromBinaryFormat(value, p);
593*288bf522SAndroid Build Coastguard Worker           fprintf(out_fp_, " %016" PRIx64, value);
594*288bf522SAndroid Build Coastguard Worker         }
595*288bf522SAndroid Build Coastguard Worker         fprintf(out_fp_, "\n");
596*288bf522SAndroid Build Coastguard Worker         stack_addr += 32;
597*288bf522SAndroid Build Coastguard Worker       }
598*288bf522SAndroid Build Coastguard Worker       fprintf(out_fp_, "\n");
599*288bf522SAndroid Build Coastguard Worker     }
600*288bf522SAndroid Build Coastguard Worker   }
601*288bf522SAndroid Build Coastguard Worker 
602*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<UnwindingResultRecord> last_unwinding_result_;
603*288bf522SAndroid Build Coastguard Worker };
604*288bf522SAndroid Build Coastguard Worker 
605*288bf522SAndroid Build Coastguard Worker class DebugUnwindCommand : public Command {
606*288bf522SAndroid Build Coastguard Worker  public:
DebugUnwindCommand()607*288bf522SAndroid Build Coastguard Worker   DebugUnwindCommand()
608*288bf522SAndroid Build Coastguard Worker       : Command(
609*288bf522SAndroid Build Coastguard Worker             "debug-unwind", "Debug/test offline unwinding.",
610*288bf522SAndroid Build Coastguard Worker             // clang-format off
611*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf debug-unwind [options]\n"
612*288bf522SAndroid Build Coastguard Worker "--generate-report         Generate a failed unwinding report.\n"
613*288bf522SAndroid Build Coastguard Worker "--generate-test-file      Generate a test file with only one sample.\n"
614*288bf522SAndroid Build Coastguard Worker "-i <file>                 Input recording file. Default is perf.data.\n"
615*288bf522SAndroid Build Coastguard Worker "-o <file>                 Output file. Default is stdout.\n"
616*288bf522SAndroid Build Coastguard Worker "--keep-binaries-in-test-file  binary1,binary2...   Keep binaries in test file.\n"
617*288bf522SAndroid Build Coastguard Worker "--sample-time time1,time2...      Only process samples recorded at selected times.\n"
618*288bf522SAndroid Build Coastguard Worker "--symfs <dir>                     Look for files with symbols relative to this directory.\n"
619*288bf522SAndroid Build Coastguard Worker "--unwind-sample                   Unwind samples.\n"
620*288bf522SAndroid Build Coastguard Worker "--skip-sample-print               Skip printing unwound samples.\n"
621*288bf522SAndroid Build Coastguard Worker "\n"
622*288bf522SAndroid Build Coastguard Worker "Examples:\n"
623*288bf522SAndroid Build Coastguard Worker "1. Unwind a sample.\n"
624*288bf522SAndroid Build Coastguard Worker "$ simpleperf debug-unwind -i perf.data --unwind-sample --sample-time 626970493946976\n"
625*288bf522SAndroid Build Coastguard Worker "  perf.data should be generated with \"--no-unwind\" or \"--keep-failed-unwinding-debug-info\".\n"
626*288bf522SAndroid Build Coastguard Worker "2. Generate a test file.\n"
627*288bf522SAndroid Build Coastguard Worker "$ simpleperf debug-unwind -i perf.data --generate-test-file -o test.data --sample-time \\\n"
628*288bf522SAndroid Build Coastguard Worker "     626970493946976 --keep-binaries-in-test-file perf.data_jit_app_cache:255984-259968\n"
629*288bf522SAndroid Build Coastguard Worker "3. Generate a failed unwinding report.\n"
630*288bf522SAndroid Build Coastguard Worker "$ simpleperf debug-unwind -i perf.data --generate-report -o report.txt\n"
631*288bf522SAndroid Build Coastguard Worker "  perf.data should be generated with \"--keep-failed-unwinding-debug-info\" or \\\n"
632*288bf522SAndroid Build Coastguard Worker "  \"--keep-failed-unwinding-result\".\n"
633*288bf522SAndroid Build Coastguard Worker "\n"
634*288bf522SAndroid Build Coastguard Worker             // clang-format on
635*288bf522SAndroid Build Coastguard Worker         ) {}
636*288bf522SAndroid Build Coastguard Worker 
637*288bf522SAndroid Build Coastguard Worker   bool Run(const std::vector<std::string>& args);
638*288bf522SAndroid Build Coastguard Worker 
639*288bf522SAndroid Build Coastguard Worker  private:
640*288bf522SAndroid Build Coastguard Worker   bool ParseOptions(const std::vector<std::string>& args);
641*288bf522SAndroid Build Coastguard Worker 
642*288bf522SAndroid Build Coastguard Worker   std::string input_filename_ = "perf.data";
643*288bf522SAndroid Build Coastguard Worker   std::string output_filename_;
644*288bf522SAndroid Build Coastguard Worker   bool unwind_sample_ = false;
645*288bf522SAndroid Build Coastguard Worker   bool skip_sample_print_ = false;
646*288bf522SAndroid Build Coastguard Worker   bool generate_report_ = false;
647*288bf522SAndroid Build Coastguard Worker   bool generate_test_file_;
648*288bf522SAndroid Build Coastguard Worker   std::unordered_set<std::string> kept_binaries_in_test_file_;
649*288bf522SAndroid Build Coastguard Worker   std::unordered_set<uint64_t> sample_times_;
650*288bf522SAndroid Build Coastguard Worker };
651*288bf522SAndroid Build Coastguard Worker 
Run(const std::vector<std::string> & args)652*288bf522SAndroid Build Coastguard Worker bool DebugUnwindCommand::Run(const std::vector<std::string>& args) {
653*288bf522SAndroid Build Coastguard Worker   // 1. Parse options.
654*288bf522SAndroid Build Coastguard Worker   if (!ParseOptions(args)) {
655*288bf522SAndroid Build Coastguard Worker     return false;
656*288bf522SAndroid Build Coastguard Worker   }
657*288bf522SAndroid Build Coastguard Worker 
658*288bf522SAndroid Build Coastguard Worker   // 2. Distribute sub commands.
659*288bf522SAndroid Build Coastguard Worker   if (unwind_sample_) {
660*288bf522SAndroid Build Coastguard Worker     SampleUnwinder sample_unwinder(output_filename_, sample_times_, skip_sample_print_);
661*288bf522SAndroid Build Coastguard Worker     return sample_unwinder.ProcessFile(input_filename_);
662*288bf522SAndroid Build Coastguard Worker   }
663*288bf522SAndroid Build Coastguard Worker   if (generate_test_file_) {
664*288bf522SAndroid Build Coastguard Worker     TestFileGenerator test_file_generator(output_filename_, sample_times_,
665*288bf522SAndroid Build Coastguard Worker                                           kept_binaries_in_test_file_);
666*288bf522SAndroid Build Coastguard Worker     return test_file_generator.ProcessFile(input_filename_);
667*288bf522SAndroid Build Coastguard Worker   }
668*288bf522SAndroid Build Coastguard Worker   if (generate_report_) {
669*288bf522SAndroid Build Coastguard Worker     ReportGenerator report_generator(output_filename_);
670*288bf522SAndroid Build Coastguard Worker     return report_generator.ProcessFile(input_filename_);
671*288bf522SAndroid Build Coastguard Worker   }
672*288bf522SAndroid Build Coastguard Worker   return true;
673*288bf522SAndroid Build Coastguard Worker }
674*288bf522SAndroid Build Coastguard Worker 
ParseOptions(const std::vector<std::string> & args)675*288bf522SAndroid Build Coastguard Worker bool DebugUnwindCommand::ParseOptions(const std::vector<std::string>& args) {
676*288bf522SAndroid Build Coastguard Worker   const OptionFormatMap option_formats = {
677*288bf522SAndroid Build Coastguard Worker       {"--generate-report", {OptionValueType::NONE, OptionType::SINGLE}},
678*288bf522SAndroid Build Coastguard Worker       {"--generate-test-file", {OptionValueType::NONE, OptionType::SINGLE}},
679*288bf522SAndroid Build Coastguard Worker       {"-i", {OptionValueType::STRING, OptionType::SINGLE}},
680*288bf522SAndroid Build Coastguard Worker       {"--keep-binaries-in-test-file", {OptionValueType::STRING, OptionType::MULTIPLE}},
681*288bf522SAndroid Build Coastguard Worker       {"-o", {OptionValueType::STRING, OptionType::SINGLE}},
682*288bf522SAndroid Build Coastguard Worker       {"--sample-time", {OptionValueType::STRING, OptionType::MULTIPLE}},
683*288bf522SAndroid Build Coastguard Worker       {"--skip-sample-print", {OptionValueType::NONE, OptionType::SINGLE}},
684*288bf522SAndroid Build Coastguard Worker       {"--symfs", {OptionValueType::STRING, OptionType::MULTIPLE}},
685*288bf522SAndroid Build Coastguard Worker       {"--unwind-sample", {OptionValueType::NONE, OptionType::SINGLE}},
686*288bf522SAndroid Build Coastguard Worker   };
687*288bf522SAndroid Build Coastguard Worker   OptionValueMap options;
688*288bf522SAndroid Build Coastguard Worker   std::vector<std::pair<OptionName, OptionValue>> ordered_options;
689*288bf522SAndroid Build Coastguard Worker   if (!PreprocessOptions(args, option_formats, &options, &ordered_options)) {
690*288bf522SAndroid Build Coastguard Worker     return false;
691*288bf522SAndroid Build Coastguard Worker   }
692*288bf522SAndroid Build Coastguard Worker   generate_report_ = options.PullBoolValue("--generate-report");
693*288bf522SAndroid Build Coastguard Worker   generate_test_file_ = options.PullBoolValue("--generate-test-file");
694*288bf522SAndroid Build Coastguard Worker   options.PullStringValue("-i", &input_filename_);
695*288bf522SAndroid Build Coastguard Worker   for (auto& value : options.PullValues("--keep-binaries-in-test-file")) {
696*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> binaries = android::base::Split(value.str_value, ",");
697*288bf522SAndroid Build Coastguard Worker     kept_binaries_in_test_file_.insert(binaries.begin(), binaries.end());
698*288bf522SAndroid Build Coastguard Worker   }
699*288bf522SAndroid Build Coastguard Worker   skip_sample_print_ = options.PullBoolValue("--skip-sample-print");
700*288bf522SAndroid Build Coastguard Worker   options.PullStringValue("-o", &output_filename_);
701*288bf522SAndroid Build Coastguard Worker   for (auto& value : options.PullValues("--sample-time")) {
702*288bf522SAndroid Build Coastguard Worker     auto times = ParseUintVector<uint64_t>(value.str_value);
703*288bf522SAndroid Build Coastguard Worker     if (!times) {
704*288bf522SAndroid Build Coastguard Worker       return false;
705*288bf522SAndroid Build Coastguard Worker     }
706*288bf522SAndroid Build Coastguard Worker     sample_times_.insert(times.value().begin(), times.value().end());
707*288bf522SAndroid Build Coastguard Worker   }
708*288bf522SAndroid Build Coastguard Worker   if (auto value = options.PullValue("--symfs"); value) {
709*288bf522SAndroid Build Coastguard Worker     if (!Dso::SetSymFsDir(value->str_value)) {
710*288bf522SAndroid Build Coastguard Worker       return false;
711*288bf522SAndroid Build Coastguard Worker     }
712*288bf522SAndroid Build Coastguard Worker   }
713*288bf522SAndroid Build Coastguard Worker   unwind_sample_ = options.PullBoolValue("--unwind-sample");
714*288bf522SAndroid Build Coastguard Worker   CHECK(options.values.empty());
715*288bf522SAndroid Build Coastguard Worker 
716*288bf522SAndroid Build Coastguard Worker   if (generate_test_file_) {
717*288bf522SAndroid Build Coastguard Worker     if (output_filename_.empty()) {
718*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "no output path for generated test file";
719*288bf522SAndroid Build Coastguard Worker       return false;
720*288bf522SAndroid Build Coastguard Worker     }
721*288bf522SAndroid Build Coastguard Worker     if (sample_times_.empty()) {
722*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "no samples are selected via --sample-time";
723*288bf522SAndroid Build Coastguard Worker       return false;
724*288bf522SAndroid Build Coastguard Worker     }
725*288bf522SAndroid Build Coastguard Worker   }
726*288bf522SAndroid Build Coastguard Worker 
727*288bf522SAndroid Build Coastguard Worker   return true;
728*288bf522SAndroid Build Coastguard Worker }
729*288bf522SAndroid Build Coastguard Worker 
730*288bf522SAndroid Build Coastguard Worker }  // namespace
731*288bf522SAndroid Build Coastguard Worker 
RegisterDebugUnwindCommand()732*288bf522SAndroid Build Coastguard Worker void RegisterDebugUnwindCommand() {
733*288bf522SAndroid Build Coastguard Worker   RegisterCommand("debug-unwind",
734*288bf522SAndroid Build Coastguard Worker                   [] { return std::unique_ptr<Command>(new DebugUnwindCommand()); });
735*288bf522SAndroid Build Coastguard Worker }
736*288bf522SAndroid Build Coastguard Worker 
737*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
738