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