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