• 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 };
61 
GetFeatureName(int feature_id)62 std::string GetFeatureName(int feature_id) {
63   auto it = feature_name_map.find(feature_id);
64   return it == feature_name_map.end() ? "" : it->second;
65 }
66 
GetFeatureId(const std::string & feature_name)67 int GetFeatureId(const std::string& feature_name) {
68   for (auto& pair : feature_name_map) {
69     if (pair.second == feature_name) {
70       return pair.first;
71     }
72   }
73   return -1;
74 }
75 
76 }  // namespace PerfFileFormat
77 
CreateInstance(const std::string & filename)78 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
79   std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
80   FILE* fp = fopen(filename.c_str(), mode.c_str());
81   if (fp == nullptr) {
82     PLOG(ERROR) << "failed to open record file '" << filename << "'";
83     return nullptr;
84   }
85   auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
86   if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
87       !reader->ReadFeatureSectionDescriptors() || !reader->ReadMetaInfoFeature()) {
88     return nullptr;
89   }
90   reader->UseRecordingEnvironment();
91   return reader;
92 }
93 
RecordFileReader(const std::string & filename,FILE * fp)94 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
95     : filename_(filename),
96       record_fp_(fp),
97       event_id_pos_in_sample_records_(0),
98       event_id_reverse_pos_in_non_sample_records_(0),
99       read_record_size_(0) {}
100 
~RecordFileReader()101 RecordFileReader::~RecordFileReader() {
102   if (record_fp_ != nullptr) {
103     Close();
104   }
105 }
106 
Close()107 bool RecordFileReader::Close() {
108   bool result = true;
109   if (fclose(record_fp_) != 0) {
110     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
111     result = false;
112   }
113   record_fp_ = nullptr;
114   return result;
115 }
116 
ReadHeader()117 bool RecordFileReader::ReadHeader() {
118   if (!Read(&header_, sizeof(header_))) {
119     return false;
120   }
121   if (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) != 0) {
122     LOG(ERROR) << filename_ << " is not a valid profiling record file.";
123     return false;
124   }
125   return true;
126 }
127 
ReadAttrSection()128 bool RecordFileReader::ReadAttrSection() {
129   size_t attr_count = header_.attrs.size / header_.attr_size;
130   if (header_.attr_size != sizeof(FileAttr)) {
131     LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
132                << " doesn't match expected size (" << sizeof(FileAttr) << ")";
133   }
134   if (attr_count == 0) {
135     LOG(ERROR) << "no attr in file " << filename_;
136     return false;
137   }
138   if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
139     PLOG(ERROR) << "fseek() failed";
140     return false;
141   }
142   for (size_t i = 0; i < attr_count; ++i) {
143     std::vector<char> buf(header_.attr_size);
144     if (!Read(buf.data(), buf.size())) {
145       return false;
146     }
147     // The size of perf_event_attr is changing between different linux kernel versions.
148     // Make sure we copy correct data to memory.
149     FileAttr attr;
150     memset(&attr, 0, sizeof(attr));
151     size_t section_desc_size = sizeof(attr.ids);
152     size_t perf_event_attr_size = header_.attr_size - section_desc_size;
153     memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
154     memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
155     file_attrs_.push_back(attr);
156   }
157   if (file_attrs_.size() > 1) {
158     std::vector<perf_event_attr> attrs;
159     for (const auto& file_attr : file_attrs_) {
160       attrs.push_back(file_attr.attr);
161     }
162     if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
163                                            &event_id_reverse_pos_in_non_sample_records_)) {
164       return false;
165     }
166   }
167   for (size_t i = 0; i < file_attrs_.size(); ++i) {
168     std::vector<uint64_t> ids;
169     if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
170       return false;
171     }
172     event_ids_for_file_attrs_.push_back(ids);
173     for (auto id : ids) {
174       event_id_to_attr_map_[id] = i;
175     }
176   }
177   return true;
178 }
179 
ReadFeatureSectionDescriptors()180 bool RecordFileReader::ReadFeatureSectionDescriptors() {
181   std::vector<int> features;
182   for (size_t i = 0; i < sizeof(header_.features); ++i) {
183     for (size_t j = 0; j < 8; ++j) {
184       if (header_.features[i] & (1 << j)) {
185         features.push_back(i * 8 + j);
186       }
187     }
188   }
189   uint64_t feature_section_offset = header_.data.offset + header_.data.size;
190   if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
191     PLOG(ERROR) << "fseek() failed";
192     return false;
193   }
194   for (const auto& id : features) {
195     SectionDesc desc;
196     if (!Read(&desc, sizeof(desc))) {
197       return false;
198     }
199     feature_section_descriptors_.emplace(id, desc);
200   }
201   return true;
202 }
203 
ReadIdsForAttr(const FileAttr & attr,std::vector<uint64_t> * ids)204 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
205   size_t id_count = attr.ids.size / sizeof(uint64_t);
206   if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
207     PLOG(ERROR) << "fseek() failed";
208     return false;
209   }
210   ids->resize(id_count);
211   if (!Read(ids->data(), attr.ids.size)) {
212     return false;
213   }
214   return true;
215 }
216 
UseRecordingEnvironment()217 void RecordFileReader::UseRecordingEnvironment() {
218   std::string arch = ReadFeatureString(FEAT_ARCH);
219   if (!arch.empty()) {
220     scoped_arch_.reset(new ScopedCurrentArch(GetArchType(arch)));
221   }
222   auto& meta_info = GetMetaInfoFeature();
223   if (auto it = meta_info.find("event_type_info"); it != meta_info.end()) {
224     if (EventTypeManager::Instance().GetScopedFinder() == nullptr) {
225       scoped_event_types_.reset(new ScopedEventTypes(it->second));
226     }
227   }
228 }
229 
ReadDataSection(const std::function<bool (std::unique_ptr<Record>)> & callback)230 bool RecordFileReader::ReadDataSection(
231     const std::function<bool(std::unique_ptr<Record>)>& callback) {
232   std::unique_ptr<Record> record;
233   while (ReadRecord(record)) {
234     if (record == nullptr) {
235       return true;
236     }
237     if (!callback(std::move(record))) {
238       return false;
239     }
240   }
241   return false;
242 }
243 
ReadRecord(std::unique_ptr<Record> & record)244 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record) {
245   if (read_record_size_ == 0) {
246     if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
247       PLOG(ERROR) << "fseek() failed";
248       return false;
249     }
250   }
251   record = nullptr;
252   if (read_record_size_ < header_.data.size) {
253     record = ReadRecord();
254     if (record == nullptr) {
255       return false;
256     }
257     if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
258       ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
259     }
260   }
261   return true;
262 }
263 
ReadRecord()264 std::unique_ptr<Record> RecordFileReader::ReadRecord() {
265   char header_buf[Record::header_size()];
266   if (!Read(header_buf, Record::header_size())) {
267     return nullptr;
268   }
269   RecordHeader header(header_buf);
270   std::unique_ptr<char[]> p;
271   if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
272     // Read until meeting a RECORD_SPLIT_END record.
273     std::vector<char> buf;
274     size_t cur_size = 0;
275     char header_buf[Record::header_size()];
276     while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
277       size_t bytes_to_read = header.size - Record::header_size();
278       buf.resize(cur_size + bytes_to_read);
279       if (!Read(&buf[cur_size], bytes_to_read)) {
280         return nullptr;
281       }
282       cur_size += bytes_to_read;
283       read_record_size_ += header.size;
284       if (!Read(header_buf, Record::header_size())) {
285         return nullptr;
286       }
287       header = RecordHeader(header_buf);
288     }
289     if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
290       LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
291       return nullptr;
292     }
293     read_record_size_ += header.size;
294     header = RecordHeader(buf.data());
295     p.reset(new char[header.size]);
296     memcpy(p.get(), buf.data(), buf.size());
297   } else {
298     p.reset(new char[header.size]);
299     memcpy(p.get(), header_buf, Record::header_size());
300     if (header.size > Record::header_size()) {
301       if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
302         return nullptr;
303       }
304     }
305     read_record_size_ += header.size;
306   }
307 
308   const perf_event_attr* attr = &file_attrs_[0].attr;
309   if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
310     bool has_event_id = false;
311     uint64_t event_id;
312     if (header.type == PERF_RECORD_SAMPLE) {
313       if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
314         has_event_id = true;
315         event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
316       }
317     } else {
318       if (header.size > event_id_reverse_pos_in_non_sample_records_) {
319         has_event_id = true;
320         event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size -
321                                                 event_id_reverse_pos_in_non_sample_records_);
322       }
323     }
324     if (has_event_id) {
325       auto it = event_id_to_attr_map_.find(event_id);
326       if (it != event_id_to_attr_map_.end()) {
327         attr = &file_attrs_[it->second].attr;
328       }
329     }
330   }
331   auto r = ReadRecordFromOwnedBuffer(*attr, header.type, p.release());
332   if (r->type() == PERF_RECORD_AUXTRACE) {
333     auto auxtrace = static_cast<AuxTraceRecord*>(r.get());
334     auxtrace->location.file_offset = header_.data.offset + read_record_size_;
335     read_record_size_ += auxtrace->data->aux_size;
336     if (fseek(record_fp_, auxtrace->data->aux_size, SEEK_CUR) != 0) {
337       PLOG(ERROR) << "fseek() failed";
338       return nullptr;
339     }
340   }
341   return r;
342 }
343 
Read(void * buf,size_t len)344 bool RecordFileReader::Read(void* buf, size_t len) {
345   if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
346     PLOG(FATAL) << "failed to read file " << filename_;
347     return false;
348   }
349   return true;
350 }
351 
ReadAtOffset(uint64_t offset,void * buf,size_t len)352 bool RecordFileReader::ReadAtOffset(uint64_t offset, void* buf, size_t len) {
353   if (fseek(record_fp_, offset, SEEK_SET) != 0) {
354     PLOG(ERROR) << "failed to seek to " << offset;
355     return false;
356   }
357   return Read(buf, len);
358 }
359 
ProcessEventIdRecord(const EventIdRecord & r)360 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
361   for (size_t i = 0; i < r.count; ++i) {
362     event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
363     event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
364   }
365 }
366 
GetAttrIndexOfRecord(const Record * record)367 size_t RecordFileReader::GetAttrIndexOfRecord(const Record* record) {
368   auto it = event_id_to_attr_map_.find(record->Id());
369   if (it != event_id_to_attr_map_.end()) {
370     return it->second;
371   }
372   return 0;
373 }
374 
ReadFeatureSection(int feature,std::vector<char> * data)375 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
376   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
377   auto it = section_map.find(feature);
378   if (it == section_map.end()) {
379     return false;
380   }
381   SectionDesc section = it->second;
382   data->resize(section.size);
383   if (section.size == 0) {
384     return true;
385   }
386   if (!ReadAtOffset(section.offset, data->data(), data->size())) {
387     return false;
388   }
389   return true;
390 }
391 
ReadFeatureSection(int feature,std::string * data)392 bool RecordFileReader::ReadFeatureSection(int feature, std::string* data) {
393   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
394   auto it = section_map.find(feature);
395   if (it == section_map.end()) {
396     return false;
397   }
398   SectionDesc section = it->second;
399   data->resize(section.size);
400   if (section.size == 0) {
401     return true;
402   }
403   if (!ReadAtOffset(section.offset, data->data(), data->size())) {
404     return false;
405   }
406   return true;
407 }
408 
ReadCmdlineFeature()409 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
410   std::vector<char> buf;
411   if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
412     return std::vector<std::string>();
413   }
414   const char* p = buf.data();
415   const char* end = buf.data() + buf.size();
416   std::vector<std::string> cmdline;
417   uint32_t arg_count;
418   MoveFromBinaryFormat(arg_count, p);
419   CHECK_LE(p, end);
420   for (size_t i = 0; i < arg_count; ++i) {
421     uint32_t len;
422     MoveFromBinaryFormat(len, p);
423     CHECK_LE(p + len, end);
424     cmdline.push_back(p);
425     p += len;
426   }
427   return cmdline;
428 }
429 
ReadBuildIdFeature()430 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
431   std::vector<char> buf;
432   if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
433     return std::vector<BuildIdRecord>();
434   }
435   const char* p = buf.data();
436   const char* end = buf.data() + buf.size();
437   std::vector<BuildIdRecord> result;
438   while (p < end) {
439     auto header = reinterpret_cast<const perf_event_header*>(p);
440     CHECK_LE(p + header->size, end);
441     char* binary = new char[header->size];
442     memcpy(binary, p, header->size);
443     p += header->size;
444     BuildIdRecord record(binary);
445     record.OwnBinary();
446     // Set type explicitly as the perf.data produced by perf doesn't set it.
447     record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
448     result.push_back(std::move(record));
449   }
450   return result;
451 }
452 
ReadFeatureString(int feature)453 std::string RecordFileReader::ReadFeatureString(int feature) {
454   std::vector<char> buf;
455   if (!ReadFeatureSection(feature, &buf)) {
456     return std::string();
457   }
458   const char* p = buf.data();
459   const char* end = buf.data() + buf.size();
460   uint32_t len;
461   MoveFromBinaryFormat(len, p);
462   CHECK_LE(p + len, end);
463   return p;
464 }
465 
ReadAuxTraceFeature()466 std::vector<uint64_t> RecordFileReader::ReadAuxTraceFeature() {
467   std::vector<char> buf;
468   if (!ReadFeatureSection(FEAT_AUXTRACE, &buf)) {
469     return {};
470   }
471   std::vector<uint64_t> auxtrace_offset;
472   const char* p = buf.data();
473   const char* end = buf.data() + buf.size();
474   if (buf.size() / sizeof(uint64_t) % 2 == 1) {
475     // Recording files generated by linux perf contain an extra uint64 field. Skip it here.
476     p += sizeof(uint64_t);
477   }
478   while (p < end) {
479     uint64_t offset;
480     uint64_t size;
481     MoveFromBinaryFormat(offset, p);
482     auxtrace_offset.push_back(offset);
483     MoveFromBinaryFormat(size, p);
484     CHECK_EQ(size, AuxTraceRecord::Size());
485   }
486   return auxtrace_offset;
487 }
488 
ReadFileFeature(size_t & read_pos,FileFeature * file)489 bool RecordFileReader::ReadFileFeature(size_t& read_pos, FileFeature* file) {
490   auto it = feature_section_descriptors_.find(FEAT_FILE);
491   if (it == feature_section_descriptors_.end()) {
492     return false;
493   }
494   if (read_pos >= it->second.size) {
495     return false;
496   }
497   if (read_pos == 0) {
498     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
499       PLOG(ERROR) << "fseek() failed";
500       return false;
501     }
502   }
503   uint32_t size;
504   if (!Read(&size, 4)) {
505     return false;
506   }
507   std::vector<char> buf(size);
508   if (!Read(buf.data(), size)) {
509     return false;
510   }
511   read_pos += 4 + size;
512   const char* p = buf.data();
513   file->path = p;
514   p += file->path.size() + 1;
515   uint32_t file_type;
516   MoveFromBinaryFormat(file_type, p);
517   if (file_type > DSO_UNKNOWN_FILE) {
518     LOG(ERROR) << "unknown file type for " << file->path
519                << " in file feature section: " << file_type;
520     return false;
521   }
522   file->type = static_cast<DsoType>(file_type);
523   MoveFromBinaryFormat(file->min_vaddr, p);
524   uint32_t symbol_count;
525   MoveFromBinaryFormat(symbol_count, p);
526   file->symbols.clear();
527   file->symbols.reserve(symbol_count);
528   for (uint32_t i = 0; i < symbol_count; ++i) {
529     uint64_t start_vaddr;
530     uint32_t len;
531     MoveFromBinaryFormat(start_vaddr, p);
532     MoveFromBinaryFormat(len, p);
533     std::string name = p;
534     p += name.size() + 1;
535     file->symbols.emplace_back(name, start_vaddr, len);
536   }
537   file->dex_file_offsets.clear();
538   if (file->type == DSO_DEX_FILE) {
539     uint32_t offset_count;
540     MoveFromBinaryFormat(offset_count, p);
541     file->dex_file_offsets.resize(offset_count);
542     MoveFromBinaryFormat(file->dex_file_offsets.data(), offset_count, p);
543   }
544   file->file_offset_of_min_vaddr = std::numeric_limits<uint64_t>::max();
545   if ((file->type == DSO_ELF_FILE || file->type == DSO_KERNEL_MODULE) &&
546       static_cast<size_t>(p - buf.data()) < size) {
547     MoveFromBinaryFormat(file->file_offset_of_min_vaddr, p);
548   }
549   CHECK_EQ(size, static_cast<size_t>(p - buf.data()))
550       << "file " << file->path << ", type " << file->type;
551   return true;
552 }
553 
ReadMetaInfoFeature()554 bool RecordFileReader::ReadMetaInfoFeature() {
555   if (feature_section_descriptors_.count(FEAT_META_INFO)) {
556     std::vector<char> buf;
557     if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
558       return false;
559     }
560     const char* p = buf.data();
561     const char* end = buf.data() + buf.size();
562     while (p < end) {
563       const char* key = p;
564       const char* value = key + strlen(key) + 1;
565       CHECK(value < end);
566       meta_info_[p] = value;
567       p = value + strlen(value) + 1;
568     }
569   }
570   return true;
571 }
572 
ReadDebugUnwindFeature()573 std::optional<DebugUnwindFeature> RecordFileReader::ReadDebugUnwindFeature() {
574   if (feature_section_descriptors_.count(FEAT_DEBUG_UNWIND)) {
575     std::string s;
576     if (!ReadFeatureSection(FEAT_DEBUG_UNWIND, &s)) {
577       return std::nullopt;
578     }
579     proto::DebugUnwindFeature proto_debug_unwind;
580     proto_debug_unwind.ParseFromString(s);
581     DebugUnwindFeature debug_unwind(proto_debug_unwind.file_size());
582     for (size_t i = 0; i < proto_debug_unwind.file_size(); i++) {
583       debug_unwind[i].path = proto_debug_unwind.file(i).path();
584       debug_unwind[i].size = proto_debug_unwind.file(i).size();
585     }
586     return debug_unwind;
587   }
588   return std::nullopt;
589 }
590 
LoadBuildIdAndFileFeatures(ThreadTree & thread_tree)591 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
592   std::vector<BuildIdRecord> records = ReadBuildIdFeature();
593   std::vector<std::pair<std::string, BuildId>> build_ids;
594   for (auto& r : records) {
595     build_ids.push_back(std::make_pair(r.filename, r.build_id));
596   }
597   Dso::SetBuildIds(build_ids);
598 
599   if (HasFeature(PerfFileFormat::FEAT_FILE)) {
600     FileFeature file_feature;
601     size_t read_pos = 0;
602     while (ReadFileFeature(read_pos, &file_feature)) {
603       thread_tree.AddDsoInfo(file_feature);
604     }
605   }
606 }
607 
ReadAuxData(uint32_t cpu,uint64_t aux_offset,void * buf,size_t size)608 bool RecordFileReader::ReadAuxData(uint32_t cpu, uint64_t aux_offset, void* buf, size_t size) {
609   long saved_pos = ftell(record_fp_);
610   if (saved_pos == -1) {
611     PLOG(ERROR) << "ftell() failed";
612     return false;
613   }
614   if (aux_data_location_.empty() && !BuildAuxDataLocation()) {
615     return false;
616   }
617   AuxDataLocation* location = nullptr;
618   auto it = aux_data_location_.find(cpu);
619   if (it != aux_data_location_.end()) {
620     auto comp = [](uint64_t aux_offset, const AuxDataLocation& location) {
621       return aux_offset < location.aux_offset;
622     };
623     auto location_it = std::upper_bound(it->second.begin(), it->second.end(), aux_offset, comp);
624     if (location_it != it->second.begin()) {
625       --location_it;
626       if (location_it->aux_offset + location_it->aux_size >= aux_offset + size) {
627         location = &*location_it;
628       }
629     }
630   }
631   if (location == nullptr) {
632     LOG(ERROR) << "failed to find file offset of aux data: cpu " << cpu << ", aux_offset "
633                << aux_offset << ", size " << size;
634     return false;
635   }
636   if (!ReadAtOffset(aux_offset - location->aux_offset + location->file_offset, buf, size)) {
637     return false;
638   }
639   if (fseek(record_fp_, saved_pos, SEEK_SET) != 0) {
640     PLOG(ERROR) << "fseek() failed";
641     return false;
642   }
643   return true;
644 }
645 
BuildAuxDataLocation()646 bool RecordFileReader::BuildAuxDataLocation() {
647   std::vector<uint64_t> auxtrace_offset = ReadAuxTraceFeature();
648   if (auxtrace_offset.empty()) {
649     LOG(ERROR) << "failed to read auxtrace feature section";
650     return false;
651   }
652   std::unique_ptr<char[]> buf(new char[AuxTraceRecord::Size()]);
653   for (auto offset : auxtrace_offset) {
654     if (!ReadAtOffset(offset, buf.get(), AuxTraceRecord::Size())) {
655       return false;
656     }
657     AuxTraceRecord auxtrace(buf.get());
658     aux_data_location_[auxtrace.data->cpu].emplace_back(
659         auxtrace.data->offset, auxtrace.data->aux_size, offset + auxtrace.size());
660   }
661   return true;
662 }
663 
DataSection()664 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
665   std::vector<std::unique_ptr<Record>> records;
666   ReadDataSection([&](std::unique_ptr<Record> record) {
667     records.push_back(std::move(record));
668     return true;
669   });
670   return records;
671 }
672 
IsPerfDataFile(const std::string & filename)673 bool IsPerfDataFile(const std::string& filename) {
674   auto fd = FileHelper::OpenReadOnly(filename);
675   if (fd.ok()) {
676     PerfFileFormat::FileHeader header;
677     return android::base::ReadFully(fd, &header, sizeof(header)) &&
678            memcmp(header.magic, PERF_MAGIC, sizeof(header.magic)) == 0;
679   }
680   return false;
681 }
682 
683 }  // namespace simpleperf
684