• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "record_file.h"
18 
19 #include <fcntl.h>
20 #include <string.h>
21 #include <set>
22 #include <vector>
23 
24 #include <android-base/logging.h>
25 
26 #include "event_attr.h"
27 #include "record.h"
28 #include "system/extras/simpleperf/record_file.pb.h"
29 #include "utils.h"
30 
31 namespace simpleperf {
32 
33 using namespace PerfFileFormat;
34 
35 namespace PerfFileFormat {
36 
37 static const std::map<int, std::string> feature_name_map = {
38     {FEAT_TRACING_DATA, "tracing_data"},
39     {FEAT_BUILD_ID, "build_id"},
40     {FEAT_HOSTNAME, "hostname"},
41     {FEAT_OSRELEASE, "osrelease"},
42     {FEAT_VERSION, "version"},
43     {FEAT_ARCH, "arch"},
44     {FEAT_NRCPUS, "nrcpus"},
45     {FEAT_CPUDESC, "cpudesc"},
46     {FEAT_CPUID, "cpuid"},
47     {FEAT_TOTAL_MEM, "total_mem"},
48     {FEAT_CMDLINE, "cmdline"},
49     {FEAT_EVENT_DESC, "event_desc"},
50     {FEAT_CPU_TOPOLOGY, "cpu_topology"},
51     {FEAT_NUMA_TOPOLOGY, "numa_topology"},
52     {FEAT_BRANCH_STACK, "branch_stack"},
53     {FEAT_PMU_MAPPINGS, "pmu_mappings"},
54     {FEAT_GROUP_DESC, "group_desc"},
55     {FEAT_AUXTRACE, "auxtrace"},
56     {FEAT_FILE, "file"},
57     {FEAT_META_INFO, "meta_info"},
58     {FEAT_DEBUG_UNWIND, "debug_unwind"},
59     {FEAT_DEBUG_UNWIND_FILE, "debug_unwind_file"},
60     {FEAT_FILE2, "file2"},
61 };
62 
GetFeatureName(int feature_id)63 std::string GetFeatureName(int feature_id) {
64   auto it = feature_name_map.find(feature_id);
65   return it == feature_name_map.end() ? "" : it->second;
66 }
67 
GetFeatureId(const std::string & feature_name)68 int GetFeatureId(const std::string& feature_name) {
69   for (auto& pair : feature_name_map) {
70     if (pair.second == feature_name) {
71       return pair.first;
72     }
73   }
74   return -1;
75 }
76 
77 }  // namespace PerfFileFormat
78 
CreateInstance(const std::string & filename)79 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
80   std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
81   FILE* fp = fopen(filename.c_str(), mode.c_str());
82   if (fp == nullptr) {
83     PLOG(ERROR) << "failed to open record file '" << filename << "'";
84     return nullptr;
85   }
86   auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
87   if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
88       !reader->ReadFeatureSectionDescriptors() || !reader->ReadMetaInfoFeature()) {
89     return nullptr;
90   }
91   reader->UseRecordingEnvironment();
92   return reader;
93 }
94 
RecordFileReader(const std::string & filename,FILE * fp)95 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
96     : filename_(filename),
97       record_fp_(fp),
98       event_id_pos_in_sample_records_(0),
99       event_id_reverse_pos_in_non_sample_records_(0),
100       read_record_size_(0) {
101   file_size_ = GetFileSize(filename_);
102 }
103 
~RecordFileReader()104 RecordFileReader::~RecordFileReader() {
105   if (record_fp_ != nullptr) {
106     Close();
107   }
108 }
109 
Close()110 bool RecordFileReader::Close() {
111   bool result = true;
112   if (fclose(record_fp_) != 0) {
113     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
114     result = false;
115   }
116   record_fp_ = nullptr;
117   return result;
118 }
119 
ReadHeader()120 bool RecordFileReader::ReadHeader() {
121   if (!Read(&header_, sizeof(header_))) {
122     return false;
123   }
124   if (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) != 0) {
125     LOG(ERROR) << filename_ << " is not a valid profiling record file.";
126     return false;
127   }
128   if (header_.attr_size == 0 || !CheckSectionDesc(header_.attrs, sizeof(header_)) ||
129       !CheckSectionDesc(header_.data, sizeof(header_))) {
130     LOG(ERROR) << "invalid header in " << filename_;
131     return false;
132   }
133   return true;
134 }
135 
CheckSectionDesc(const SectionDesc & desc,uint64_t min_offset)136 bool RecordFileReader::CheckSectionDesc(const SectionDesc& desc, uint64_t min_offset) {
137   uint64_t desc_end;
138   if (desc.offset < min_offset || __builtin_add_overflow(desc.offset, desc.size, &desc_end) ||
139       desc_end > file_size_) {
140     return false;
141   }
142   return true;
143 }
144 
ReadAttrSection()145 bool RecordFileReader::ReadAttrSection() {
146   size_t attr_count = header_.attrs.size / header_.attr_size;
147   if (header_.attr_size != sizeof(FileAttr)) {
148     LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
149                << " doesn't match expected size (" << sizeof(FileAttr) << ")";
150   }
151   if (attr_count == 0) {
152     LOG(ERROR) << "no attr in file " << filename_;
153     return false;
154   }
155   if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
156     PLOG(ERROR) << "fseek() failed";
157     return false;
158   }
159   for (size_t i = 0; i < attr_count; ++i) {
160     std::vector<char> buf(header_.attr_size);
161     if (!Read(buf.data(), buf.size())) {
162       return false;
163     }
164     // The size of perf_event_attr is changing between different linux kernel versions.
165     // Make sure we copy correct data to memory.
166     FileAttr attr;
167     memset(&attr, 0, sizeof(attr));
168     size_t section_desc_size = sizeof(attr.ids);
169     size_t perf_event_attr_size = header_.attr_size - section_desc_size;
170     memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
171     memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
172     if (!CheckSectionDesc(attr.ids, 0)) {
173       LOG(ERROR) << "invalid attr section in " << filename_;
174       return false;
175     }
176     file_attrs_.push_back(attr);
177   }
178   if (file_attrs_.size() > 1) {
179     std::vector<perf_event_attr> attrs;
180     for (const auto& file_attr : file_attrs_) {
181       attrs.push_back(file_attr.attr);
182     }
183     if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
184                                            &event_id_reverse_pos_in_non_sample_records_)) {
185       return false;
186     }
187   }
188   for (size_t i = 0; i < file_attrs_.size(); ++i) {
189     std::vector<uint64_t> ids;
190     if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
191       return false;
192     }
193     event_ids_for_file_attrs_.push_back(ids);
194     for (auto id : ids) {
195       event_id_to_attr_map_[id] = i;
196     }
197   }
198   return true;
199 }
200 
ReadFeatureSectionDescriptors()201 bool RecordFileReader::ReadFeatureSectionDescriptors() {
202   std::vector<int> features;
203   for (size_t i = 0; i < sizeof(header_.features); ++i) {
204     for (size_t j = 0; j < 8; ++j) {
205       if (header_.features[i] & (1 << j)) {
206         features.push_back(i * 8 + j);
207       }
208     }
209   }
210   uint64_t feature_section_offset = header_.data.offset + header_.data.size;
211   if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
212     PLOG(ERROR) << "fseek() failed";
213     return false;
214   }
215   uint64_t min_section_data_pos = feature_section_offset + sizeof(SectionDesc) * features.size();
216   for (const auto& id : features) {
217     SectionDesc desc;
218     if (!Read(&desc, sizeof(desc))) {
219       return false;
220     }
221     if (!CheckSectionDesc(desc, min_section_data_pos)) {
222       LOG(ERROR) << "invalid feature section descriptor in " << filename_;
223       return false;
224     }
225     feature_section_descriptors_.emplace(id, desc);
226   }
227   return true;
228 }
229 
ReadIdsForAttr(const FileAttr & attr,std::vector<uint64_t> * ids)230 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
231   size_t id_count = attr.ids.size / sizeof(uint64_t);
232   if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
233     PLOG(ERROR) << "fseek() failed";
234     return false;
235   }
236   ids->resize(id_count);
237   if (!Read(ids->data(), attr.ids.size)) {
238     return false;
239   }
240   return true;
241 }
242 
UseRecordingEnvironment()243 void RecordFileReader::UseRecordingEnvironment() {
244   std::string arch = ReadFeatureString(FEAT_ARCH);
245   if (!arch.empty()) {
246     scoped_arch_.reset(new ScopedCurrentArch(GetArchType(arch)));
247   }
248   auto& meta_info = GetMetaInfoFeature();
249   if (auto it = meta_info.find("event_type_info"); it != meta_info.end()) {
250     if (EventTypeManager::Instance().GetScopedFinder() == nullptr) {
251       scoped_event_types_.reset(new ScopedEventTypes(it->second));
252     }
253   }
254 }
255 
ReadDataSection(const std::function<bool (std::unique_ptr<Record>)> & callback)256 bool RecordFileReader::ReadDataSection(
257     const std::function<bool(std::unique_ptr<Record>)>& callback) {
258   std::unique_ptr<Record> record;
259   while (ReadRecord(record)) {
260     if (record == nullptr) {
261       return true;
262     }
263     if (!callback(std::move(record))) {
264       return false;
265     }
266   }
267   return false;
268 }
269 
ReadRecord(std::unique_ptr<Record> & record)270 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record) {
271   if (read_record_size_ == 0) {
272     if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
273       PLOG(ERROR) << "fseek() failed";
274       return false;
275     }
276   }
277   record = nullptr;
278   if (read_record_size_ < header_.data.size) {
279     record = ReadRecord();
280     if (record == nullptr) {
281       return false;
282     }
283     if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
284       ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
285     }
286   }
287   return true;
288 }
289 
ReadRecord()290 std::unique_ptr<Record> RecordFileReader::ReadRecord() {
291   char header_buf[Record::header_size()];
292   if (!Read(header_buf, Record::header_size())) {
293     return nullptr;
294   }
295   RecordHeader header(header_buf);
296   std::unique_ptr<char[]> p;
297   if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
298     // Read until meeting a RECORD_SPLIT_END record.
299     std::vector<char> buf;
300     size_t cur_size = 0;
301     char header_buf[Record::header_size()];
302     while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
303       size_t bytes_to_read = header.size - Record::header_size();
304       buf.resize(cur_size + bytes_to_read);
305       if (!Read(&buf[cur_size], bytes_to_read)) {
306         return nullptr;
307       }
308       cur_size += bytes_to_read;
309       read_record_size_ += header.size;
310       if (!Read(header_buf, Record::header_size())) {
311         return nullptr;
312       }
313       header = RecordHeader(header_buf);
314     }
315     if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
316       LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
317       return nullptr;
318     }
319     read_record_size_ += header.size;
320     header = RecordHeader(buf.data());
321     p.reset(new char[header.size]);
322     memcpy(p.get(), buf.data(), buf.size());
323   } else {
324     p.reset(new char[header.size]);
325     memcpy(p.get(), header_buf, Record::header_size());
326     if (header.size > Record::header_size()) {
327       if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
328         return nullptr;
329       }
330     }
331     read_record_size_ += header.size;
332   }
333 
334   const perf_event_attr* attr = &file_attrs_[0].attr;
335   if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
336     bool has_event_id = false;
337     uint64_t event_id;
338     if (header.type == PERF_RECORD_SAMPLE) {
339       if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
340         has_event_id = true;
341         event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
342       }
343     } else {
344       if (header.size > event_id_reverse_pos_in_non_sample_records_) {
345         has_event_id = true;
346         event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size -
347                                                 event_id_reverse_pos_in_non_sample_records_);
348       }
349     }
350     if (has_event_id) {
351       auto it = event_id_to_attr_map_.find(event_id);
352       if (it != event_id_to_attr_map_.end()) {
353         attr = &file_attrs_[it->second].attr;
354       }
355     }
356   }
357   auto r = ReadRecordFromBuffer(*attr, header.type, p.get(), p.get() + header.size);
358   if (!r) {
359     return nullptr;
360   }
361   p.release();
362   r->OwnBinary();
363   if (r->type() == PERF_RECORD_AUXTRACE) {
364     auto auxtrace = static_cast<AuxTraceRecord*>(r.get());
365     auxtrace->location.file_offset = header_.data.offset + read_record_size_;
366     read_record_size_ += auxtrace->data->aux_size;
367     if (fseek(record_fp_, auxtrace->data->aux_size, SEEK_CUR) != 0) {
368       PLOG(ERROR) << "fseek() failed";
369       return nullptr;
370     }
371   }
372   return r;
373 }
374 
Read(void * buf,size_t len)375 bool RecordFileReader::Read(void* buf, size_t len) {
376   if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
377     PLOG(ERROR) << "failed to read file " << filename_;
378     return false;
379   }
380   return true;
381 }
382 
ReadAtOffset(uint64_t offset,void * buf,size_t len)383 bool RecordFileReader::ReadAtOffset(uint64_t offset, void* buf, size_t len) {
384   if (fseek(record_fp_, offset, SEEK_SET) != 0) {
385     PLOG(ERROR) << "failed to seek to " << offset;
386     return false;
387   }
388   return Read(buf, len);
389 }
390 
ProcessEventIdRecord(const EventIdRecord & r)391 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
392   for (size_t i = 0; i < r.count; ++i) {
393     event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
394     event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
395   }
396 }
397 
GetAttrIndexOfRecord(const Record * record)398 size_t RecordFileReader::GetAttrIndexOfRecord(const Record* record) {
399   auto it = event_id_to_attr_map_.find(record->Id());
400   if (it != event_id_to_attr_map_.end()) {
401     return it->second;
402   }
403   return 0;
404 }
405 
ReadFeatureSection(int feature,std::vector<char> * data)406 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
407   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
408   auto it = section_map.find(feature);
409   if (it == section_map.end()) {
410     return false;
411   }
412   SectionDesc section = it->second;
413   data->resize(section.size);
414   if (section.size == 0) {
415     return true;
416   }
417   if (!ReadAtOffset(section.offset, data->data(), data->size())) {
418     return false;
419   }
420   return true;
421 }
422 
ReadFeatureSection(int feature,std::string * data)423 bool RecordFileReader::ReadFeatureSection(int feature, std::string* data) {
424   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
425   auto it = section_map.find(feature);
426   if (it == section_map.end()) {
427     return false;
428   }
429   SectionDesc section = it->second;
430   data->resize(section.size);
431   if (section.size == 0) {
432     return true;
433   }
434   if (!ReadAtOffset(section.offset, data->data(), data->size())) {
435     return false;
436   }
437   return true;
438 }
439 
ReadCmdlineFeature()440 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
441   std::vector<char> buf;
442   if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
443     return std::vector<std::string>();
444   }
445   const char* p = buf.data();
446   const char* end = buf.data() + buf.size();
447   std::vector<std::string> cmdline;
448   uint32_t arg_count;
449   MoveFromBinaryFormat(arg_count, p);
450   CHECK_LE(p, end);
451   for (size_t i = 0; i < arg_count; ++i) {
452     uint32_t len;
453     MoveFromBinaryFormat(len, p);
454     CHECK_LE(p + len, end);
455     cmdline.push_back(p);
456     p += len;
457   }
458   return cmdline;
459 }
460 
ReadBuildIdFeature()461 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
462   std::vector<char> buf;
463   if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
464     return {};
465   }
466   const char* p = buf.data();
467   const char* end = buf.data() + buf.size();
468   std::vector<BuildIdRecord> result;
469   while (p < end) {
470     auto header = reinterpret_cast<const perf_event_header*>(p);
471     if (p + header->size > end) {
472       return {};
473     }
474     std::unique_ptr<char[]> binary(new char[header->size]);
475     memcpy(binary.get(), p, header->size);
476     p += header->size;
477     BuildIdRecord record;
478     if (!record.Parse(file_attrs_[0].attr, binary.get(), binary.get() + header->size)) {
479       return {};
480     }
481     binary.release();
482     record.OwnBinary();
483     // Set type explicitly as the perf.data produced by perf doesn't set it.
484     record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
485     result.push_back(std::move(record));
486   }
487   return result;
488 }
489 
ReadFeatureString(int feature)490 std::string RecordFileReader::ReadFeatureString(int feature) {
491   std::vector<char> buf;
492   if (!ReadFeatureSection(feature, &buf)) {
493     return std::string();
494   }
495   const char* p = buf.data();
496   const char* end = buf.data() + buf.size();
497   uint32_t len;
498   MoveFromBinaryFormat(len, p);
499   CHECK_LE(p + len, end);
500   return p;
501 }
502 
ReadAuxTraceFeature()503 std::vector<uint64_t> RecordFileReader::ReadAuxTraceFeature() {
504   std::vector<char> buf;
505   if (!ReadFeatureSection(FEAT_AUXTRACE, &buf)) {
506     return {};
507   }
508   std::vector<uint64_t> auxtrace_offset;
509   const char* p = buf.data();
510   const char* end = buf.data() + buf.size();
511   if (buf.size() / sizeof(uint64_t) % 2 == 1) {
512     // Recording files generated by linux perf contain an extra uint64 field. Skip it here.
513     p += sizeof(uint64_t);
514   }
515   while (p < end) {
516     uint64_t offset;
517     uint64_t size;
518     MoveFromBinaryFormat(offset, p);
519     auxtrace_offset.push_back(offset);
520     MoveFromBinaryFormat(size, p);
521     CHECK_EQ(size, AuxTraceRecord::Size());
522   }
523   return auxtrace_offset;
524 }
525 
ReadFileFeature(size_t & read_pos,FileFeature * file)526 bool RecordFileReader::ReadFileFeature(size_t& read_pos, FileFeature* file) {
527   file->Clear();
528   if (HasFeature(FEAT_FILE)) {
529     return ReadFileV1Feature(read_pos, file);
530   }
531   if (HasFeature(FEAT_FILE2)) {
532     return ReadFileV2Feature(read_pos, file);
533   }
534   return false;
535 }
536 
ReadFileV1Feature(size_t & read_pos,FileFeature * file)537 bool RecordFileReader::ReadFileV1Feature(size_t& read_pos, FileFeature* file) {
538   auto it = feature_section_descriptors_.find(FEAT_FILE);
539   if (it == feature_section_descriptors_.end()) {
540     return false;
541   }
542   if (read_pos >= it->second.size) {
543     return false;
544   }
545   if (read_pos == 0) {
546     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
547       PLOG(ERROR) << "fseek() failed";
548       return false;
549     }
550   }
551   uint32_t size;
552   if (!Read(&size, 4)) {
553     return false;
554   }
555   std::vector<char> buf(size);
556   if (!Read(buf.data(), size)) {
557     return false;
558   }
559   read_pos += 4 + size;
560   const char* p = buf.data();
561   file->path = p;
562   p += file->path.size() + 1;
563   uint32_t file_type;
564   MoveFromBinaryFormat(file_type, p);
565   if (file_type > DSO_UNKNOWN_FILE) {
566     LOG(ERROR) << "unknown file type for " << file->path
567                << " in file feature section: " << file_type;
568     return false;
569   }
570   file->type = static_cast<DsoType>(file_type);
571   MoveFromBinaryFormat(file->min_vaddr, p);
572   uint32_t symbol_count;
573   MoveFromBinaryFormat(symbol_count, p);
574   file->symbols.reserve(symbol_count);
575   for (uint32_t i = 0; i < symbol_count; ++i) {
576     uint64_t start_vaddr;
577     uint32_t len;
578     MoveFromBinaryFormat(start_vaddr, p);
579     MoveFromBinaryFormat(len, p);
580     std::string name = p;
581     p += name.size() + 1;
582     file->symbols.emplace_back(name, start_vaddr, len);
583   }
584   if (file->type == DSO_DEX_FILE) {
585     uint32_t offset_count;
586     MoveFromBinaryFormat(offset_count, p);
587     file->dex_file_offsets.resize(offset_count);
588     MoveFromBinaryFormat(file->dex_file_offsets.data(), offset_count, p);
589   }
590   file->file_offset_of_min_vaddr = std::numeric_limits<uint64_t>::max();
591   if ((file->type == DSO_ELF_FILE || file->type == DSO_KERNEL_MODULE) &&
592       static_cast<size_t>(p - buf.data()) < size) {
593     MoveFromBinaryFormat(file->file_offset_of_min_vaddr, p);
594   }
595   CHECK_EQ(size, static_cast<size_t>(p - buf.data()))
596       << "file " << file->path << ", type " << file->type;
597   return true;
598 }
599 
ReadFileV2Feature(size_t & read_pos,FileFeature * file)600 bool RecordFileReader::ReadFileV2Feature(size_t& read_pos, FileFeature* file) {
601   auto it = feature_section_descriptors_.find(FEAT_FILE2);
602   if (it == feature_section_descriptors_.end()) {
603     return false;
604   }
605   if (read_pos >= it->second.size) {
606     return false;
607   }
608   if (read_pos == 0) {
609     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
610       PLOG(ERROR) << "fseek() failed";
611       return false;
612     }
613   }
614   uint32_t size;
615   if (!Read(&size, 4)) {
616     return false;
617   }
618   read_pos += 4 + size;
619   std::string s(size, '\0');
620   if (!Read(s.data(), size)) {
621     return false;
622   }
623   proto::FileFeature proto_file;
624   if (!proto_file.ParseFromString(s)) {
625     return false;
626   }
627   file->path = proto_file.path();
628   file->type = static_cast<DsoType>(proto_file.type());
629   file->min_vaddr = proto_file.min_vaddr();
630   file->symbols.reserve(proto_file.symbol_size());
631   for (size_t i = 0; i < proto_file.symbol_size(); i++) {
632     const auto& proto_symbol = proto_file.symbol(i);
633     file->symbols.emplace_back(proto_symbol.name(), proto_symbol.vaddr(), proto_symbol.len());
634   }
635   if (file->type == DSO_DEX_FILE) {
636     CHECK(proto_file.has_dex_file());
637     const auto& dex_file_offsets = proto_file.dex_file().dex_file_offset();
638     file->dex_file_offsets.insert(file->dex_file_offsets.end(), dex_file_offsets.begin(),
639                                   dex_file_offsets.end());
640   } else if (file->type == DSO_ELF_FILE) {
641     CHECK(proto_file.has_elf_file());
642     file->file_offset_of_min_vaddr = proto_file.elf_file().file_offset_of_min_vaddr();
643   } else if (file->type == DSO_KERNEL_MODULE) {
644     CHECK(proto_file.has_kernel_module());
645     file->file_offset_of_min_vaddr = proto_file.kernel_module().memory_offset_of_min_vaddr();
646   }
647   return true;
648 }
649 
ReadMetaInfoFeature()650 bool RecordFileReader::ReadMetaInfoFeature() {
651   if (feature_section_descriptors_.count(FEAT_META_INFO)) {
652     std::vector<char> buf;
653     if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
654       return false;
655     }
656     const char* p = buf.data();
657     const char* end = buf.data() + buf.size();
658     while (p < end) {
659       const char* key = p;
660       const char* value = key + strlen(key) + 1;
661       CHECK(value < end);
662       meta_info_[p] = value;
663       p = value + strlen(value) + 1;
664     }
665   }
666   return true;
667 }
668 
GetClockId()669 std::string RecordFileReader::GetClockId() {
670   if (auto it = meta_info_.find("clockid"); it != meta_info_.end()) {
671     return it->second;
672   }
673   return "perf";
674 }
675 
ReadDebugUnwindFeature()676 std::optional<DebugUnwindFeature> RecordFileReader::ReadDebugUnwindFeature() {
677   if (feature_section_descriptors_.count(FEAT_DEBUG_UNWIND)) {
678     std::string s;
679     if (!ReadFeatureSection(FEAT_DEBUG_UNWIND, &s)) {
680       return std::nullopt;
681     }
682     proto::DebugUnwindFeature proto_debug_unwind;
683     proto_debug_unwind.ParseFromString(s);
684     DebugUnwindFeature debug_unwind(proto_debug_unwind.file_size());
685     for (size_t i = 0; i < proto_debug_unwind.file_size(); i++) {
686       debug_unwind[i].path = proto_debug_unwind.file(i).path();
687       debug_unwind[i].size = proto_debug_unwind.file(i).size();
688     }
689     return debug_unwind;
690   }
691   return std::nullopt;
692 }
693 
LoadBuildIdAndFileFeatures(ThreadTree & thread_tree)694 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
695   std::vector<BuildIdRecord> records = ReadBuildIdFeature();
696   std::vector<std::pair<std::string, BuildId>> build_ids;
697   for (auto& r : records) {
698     build_ids.push_back(std::make_pair(r.filename, r.build_id));
699   }
700   Dso::SetBuildIds(build_ids);
701 
702   if (HasFeature(PerfFileFormat::FEAT_FILE) || HasFeature(PerfFileFormat::FEAT_FILE2)) {
703     FileFeature file_feature;
704     size_t read_pos = 0;
705     while (ReadFileFeature(read_pos, &file_feature)) {
706       thread_tree.AddDsoInfo(file_feature);
707     }
708   }
709 }
710 
ReadAuxData(uint32_t cpu,uint64_t aux_offset,void * buf,size_t size)711 bool RecordFileReader::ReadAuxData(uint32_t cpu, uint64_t aux_offset, void* buf, size_t size) {
712   long saved_pos = ftell(record_fp_);
713   if (saved_pos == -1) {
714     PLOG(ERROR) << "ftell() failed";
715     return false;
716   }
717   if (aux_data_location_.empty() && !BuildAuxDataLocation()) {
718     return false;
719   }
720   AuxDataLocation* location = nullptr;
721   auto it = aux_data_location_.find(cpu);
722   if (it != aux_data_location_.end()) {
723     auto comp = [](uint64_t aux_offset, const AuxDataLocation& location) {
724       return aux_offset < location.aux_offset;
725     };
726     auto location_it = std::upper_bound(it->second.begin(), it->second.end(), aux_offset, comp);
727     if (location_it != it->second.begin()) {
728       --location_it;
729       if (location_it->aux_offset + location_it->aux_size >= aux_offset + size) {
730         location = &*location_it;
731       }
732     }
733   }
734   if (location == nullptr) {
735     LOG(ERROR) << "failed to find file offset of aux data: cpu " << cpu << ", aux_offset "
736                << aux_offset << ", size " << size;
737     return false;
738   }
739   if (!ReadAtOffset(aux_offset - location->aux_offset + location->file_offset, buf, size)) {
740     return false;
741   }
742   if (fseek(record_fp_, saved_pos, SEEK_SET) != 0) {
743     PLOG(ERROR) << "fseek() failed";
744     return false;
745   }
746   return true;
747 }
748 
BuildAuxDataLocation()749 bool RecordFileReader::BuildAuxDataLocation() {
750   std::vector<uint64_t> auxtrace_offset = ReadAuxTraceFeature();
751   if (auxtrace_offset.empty()) {
752     LOG(ERROR) << "failed to read auxtrace feature section";
753     return false;
754   }
755   std::unique_ptr<char[]> buf(new char[AuxTraceRecord::Size()]);
756   for (auto offset : auxtrace_offset) {
757     if (!ReadAtOffset(offset, buf.get(), AuxTraceRecord::Size())) {
758       return false;
759     }
760     AuxTraceRecord auxtrace;
761     if (!auxtrace.Parse(file_attrs_[0].attr, buf.get(), buf.get() + AuxTraceRecord::Size())) {
762       return false;
763     }
764     aux_data_location_[auxtrace.data->cpu].emplace_back(
765         auxtrace.data->offset, auxtrace.data->aux_size, offset + auxtrace.size());
766   }
767   return true;
768 }
769 
DataSection()770 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
771   std::vector<std::unique_ptr<Record>> records;
772   ReadDataSection([&](std::unique_ptr<Record> record) {
773     records.push_back(std::move(record));
774     return true;
775   });
776   return records;
777 }
778 
IsPerfDataFile(const std::string & filename)779 bool IsPerfDataFile(const std::string& filename) {
780   auto fd = FileHelper::OpenReadOnly(filename);
781   if (fd.ok()) {
782     PerfFileFormat::FileHeader header;
783     return android::base::ReadFully(fd, &header, sizeof(header)) &&
784            memcmp(header.magic, PERF_MAGIC, sizeof(header.magic)) == 0;
785   }
786   return false;
787 }
788 
789 }  // namespace simpleperf
790