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