OSDN Git Service

Remove verify_boot_signature.
[android-x86/system-extras.git] / simpleperf / record_file_reader.cpp
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_FILE, "file"},
53     {FEAT_META_INFO, "meta_info"},
54 };
55
56 std::string GetFeatureName(int feature_id) {
57   auto it = feature_name_map.find(feature_id);
58   return it == feature_name_map.end() ? "" : it->second;
59 }
60
61 int GetFeatureId(const std::string& feature_name) {
62   for (auto& pair : feature_name_map) {
63     if (pair.second == feature_name) {
64       return pair.first;
65     }
66   }
67   return -1;
68 }
69
70 } // namespace PerfFileFormat
71
72 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
73   std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
74   FILE* fp = fopen(filename.c_str(), mode.c_str());
75   if (fp == nullptr) {
76     PLOG(ERROR) << "failed to open record file '" << filename << "'";
77     return nullptr;
78   }
79   auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
80   if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
81       !reader->ReadFeatureSectionDescriptors()) {
82     return nullptr;
83   }
84   return reader;
85 }
86
87 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
88     : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
89       event_id_reverse_pos_in_non_sample_records_(0), read_record_size_(0) {
90 }
91
92 RecordFileReader::~RecordFileReader() {
93   if (record_fp_ != nullptr) {
94     Close();
95   }
96 }
97
98 bool RecordFileReader::Close() {
99   bool result = true;
100   if (fclose(record_fp_) != 0) {
101     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
102     result = false;
103   }
104   record_fp_ = nullptr;
105   return result;
106 }
107
108 bool RecordFileReader::ReadHeader() {
109   if (!Read(&header_, sizeof(header_))) {
110     return false;
111   }
112   if (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) != 0) {
113     LOG(ERROR) << filename_ << " is not a valid profiling record file.";
114     return false;
115   }
116   return true;
117 }
118
119 bool RecordFileReader::ReadAttrSection() {
120   size_t attr_count = header_.attrs.size / header_.attr_size;
121   if (header_.attr_size != sizeof(FileAttr)) {
122     LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
123                  << " doesn't match expected size (" << sizeof(FileAttr) << ")";
124   }
125   if (attr_count == 0) {
126     LOG(ERROR) << "no attr in file " << filename_;
127     return false;
128   }
129   if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
130     PLOG(ERROR) << "fseek() failed";
131     return false;
132   }
133   for (size_t i = 0; i < attr_count; ++i) {
134     std::vector<char> buf(header_.attr_size);
135     if (!Read(buf.data(), buf.size())) {
136       return false;
137     }
138     // The size of perf_event_attr is changing between different linux kernel versions.
139     // Make sure we copy correct data to memory.
140     FileAttr attr;
141     memset(&attr, 0, sizeof(attr));
142     size_t section_desc_size = sizeof(attr.ids);
143     size_t perf_event_attr_size = header_.attr_size - section_desc_size;
144     memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
145     memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
146     file_attrs_.push_back(attr);
147   }
148   if (file_attrs_.size() > 1) {
149     std::vector<perf_event_attr> attrs;
150     for (const auto& file_attr : file_attrs_) {
151       attrs.push_back(file_attr.attr);
152     }
153     if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
154                                                &event_id_reverse_pos_in_non_sample_records_)) {
155       return false;
156     }
157   }
158   for (size_t i = 0; i < file_attrs_.size(); ++i) {
159     std::vector<uint64_t> ids;
160     if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
161       return false;
162     }
163     event_ids_for_file_attrs_.push_back(ids);
164     for (auto id : ids) {
165       event_id_to_attr_map_[id] = i;
166     }
167   }
168   return true;
169 }
170
171 bool RecordFileReader::ReadFeatureSectionDescriptors() {
172   std::vector<int> features;
173   for (size_t i = 0; i < sizeof(header_.features); ++i) {
174     for (size_t j = 0; j < 8; ++j) {
175       if (header_.features[i] & (1 << j)) {
176         features.push_back(i * 8 + j);
177       }
178     }
179   }
180   uint64_t feature_section_offset = header_.data.offset + header_.data.size;
181   if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
182     PLOG(ERROR) << "fseek() failed";
183     return false;
184   }
185   for (const auto& id : features) {
186     SectionDesc desc;
187     if (!Read(&desc, sizeof(desc))) {
188       return false;
189     }
190     feature_section_descriptors_.emplace(id, desc);
191   }
192   return true;
193 }
194
195 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
196   size_t id_count = attr.ids.size / sizeof(uint64_t);
197   if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
198     PLOG(ERROR) << "fseek() failed";
199     return false;
200   }
201   ids->resize(id_count);
202   if (!Read(ids->data(), attr.ids.size)) {
203     return false;
204   }
205   return true;
206 }
207
208 bool RecordFileReader::ReadDataSection(
209     const std::function<bool(std::unique_ptr<Record>)>& callback, bool sorted) {
210   std::unique_ptr<Record> record;
211   while (ReadRecord(record, sorted)) {
212     if (record == nullptr) {
213       return true;
214     }
215     if (!callback(std::move(record))) {
216       return false;
217     }
218   }
219   return false;
220 }
221
222 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record,
223                                   bool sorted) {
224   if (read_record_size_ == 0) {
225     if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
226       PLOG(ERROR) << "fseek() failed";
227       return false;
228     }
229     bool has_timestamp = true;
230     for (const auto& attr : file_attrs_) {
231       if (!IsTimestampSupported(attr.attr)) {
232         has_timestamp = false;
233         break;
234       }
235     }
236     record_cache_.reset(new RecordCache(has_timestamp));
237   }
238   record = nullptr;
239   while (read_record_size_ < header_.data.size && record == nullptr) {
240     record = ReadRecord(&read_record_size_);
241     if (record == nullptr) {
242       return false;
243     }
244     if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
245       ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
246     } else if (record->type() == PERF_RECORD_SAMPLE) {
247       SampleRecord* r = static_cast<SampleRecord*>(record.get());
248       // Although we have removed ip == 0 callchains when recording dwarf based callgraph,
249       // stack frame based callgraph can also generate ip == 0 callchains. Remove them here
250       // to avoid caller's effort.
251       if (r->sample_type & PERF_SAMPLE_CALLCHAIN) {
252         size_t i;
253         for (i = 0; i < r->callchain_data.ip_nr; ++i) {
254           if (r->callchain_data.ips[i] == 0) {
255             break;
256           }
257         }
258         r->callchain_data.ip_nr = i;
259       }
260     }
261     if (sorted) {
262       record_cache_->Push(std::move(record));
263       record = record_cache_->Pop();
264     }
265   }
266   if (record == nullptr) {
267     record = record_cache_->ForcedPop();
268   }
269   return true;
270 }
271
272 std::unique_ptr<Record> RecordFileReader::ReadRecord(uint64_t* nbytes_read) {
273   char header_buf[Record::header_size()];
274   if (!Read(header_buf, Record::header_size())) {
275     return nullptr;
276   }
277   RecordHeader header(header_buf);
278   std::unique_ptr<char[]> p;
279   if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
280     // Read until meeting a RECORD_SPLIT_END record.
281     std::vector<char> buf;
282     size_t cur_size = 0;
283     char header_buf[Record::header_size()];
284     while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
285       size_t bytes_to_read = header.size - Record::header_size();
286       buf.resize(cur_size + bytes_to_read);
287       if (!Read(&buf[cur_size], bytes_to_read)) {
288         return nullptr;
289       }
290       cur_size += bytes_to_read;
291       *nbytes_read += header.size;
292       if (!Read(header_buf, Record::header_size())) {
293         return nullptr;
294       }
295       header = RecordHeader(header_buf);
296     }
297     if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
298       LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
299       return nullptr;
300     }
301     *nbytes_read += header.size;
302     header = RecordHeader(buf.data());
303     p.reset(new char[header.size]);
304     memcpy(p.get(), buf.data(), buf.size());
305   } else {
306     p.reset(new char[header.size]);
307     memcpy(p.get(), header_buf, Record::header_size());
308     if (header.size > Record::header_size()) {
309       if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
310         return nullptr;
311       }
312     }
313     *nbytes_read += header.size;
314   }
315
316   const perf_event_attr* attr = &file_attrs_[0].attr;
317   if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
318     bool has_event_id = false;
319     uint64_t event_id;
320     if (header.type == PERF_RECORD_SAMPLE) {
321       if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
322         has_event_id = true;
323         event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
324       }
325     } else {
326       if (header.size > event_id_reverse_pos_in_non_sample_records_) {
327         has_event_id = true;
328         event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size - event_id_reverse_pos_in_non_sample_records_);
329       }
330     }
331     if (has_event_id) {
332       auto it = event_id_to_attr_map_.find(event_id);
333       if (it != event_id_to_attr_map_.end()) {
334         attr = &file_attrs_[it->second].attr;
335       }
336     }
337   }
338   return ReadRecordFromOwnedBuffer(*attr, header.type, p.release());
339 }
340
341 bool RecordFileReader::Read(void* buf, size_t len) {
342   if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
343     PLOG(FATAL) << "failed to read file " << filename_;
344     return false;
345   }
346   return true;
347 }
348
349 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
350   for (size_t i = 0; i < r.count; ++i) {
351     event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
352     event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
353   }
354 }
355
356 size_t RecordFileReader::GetAttrIndexOfRecord(const Record* record) {
357   auto it = event_id_to_attr_map_.find(record->Id());
358   if (it != event_id_to_attr_map_.end()) {
359     return it->second;
360   }
361   return 0;
362 }
363
364 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
365   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
366   auto it = section_map.find(feature);
367   if (it == section_map.end()) {
368     return false;
369   }
370   SectionDesc section = it->second;
371   data->resize(section.size);
372   if (section.size == 0) {
373     return true;
374   }
375   if (fseek(record_fp_, section.offset, SEEK_SET) != 0) {
376     PLOG(ERROR) << "fseek() failed";
377     return false;
378   }
379   if (!Read(data->data(), data->size())) {
380     return false;
381   }
382   return true;
383 }
384
385 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
386   std::vector<char> buf;
387   if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
388     return std::vector<std::string>();
389   }
390   const char* p = buf.data();
391   const char* end = buf.data() + buf.size();
392   std::vector<std::string> cmdline;
393   uint32_t arg_count;
394   MoveFromBinaryFormat(arg_count, p);
395   CHECK_LE(p, end);
396   for (size_t i = 0; i < arg_count; ++i) {
397     uint32_t len;
398     MoveFromBinaryFormat(len, p);
399     CHECK_LE(p + len, end);
400     cmdline.push_back(p);
401     p += len;
402   }
403   return cmdline;
404 }
405
406 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
407   std::vector<char> buf;
408   if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
409     return std::vector<BuildIdRecord>();
410   }
411   const char* p = buf.data();
412   const char* end = buf.data() + buf.size();
413   std::vector<BuildIdRecord> result;
414   while (p < end) {
415     auto header = reinterpret_cast<const perf_event_header*>(p);
416     CHECK_LE(p + header->size, end);
417     char* binary = new char[header->size];
418     memcpy(binary, p, header->size);
419     p += header->size;
420     BuildIdRecord record(binary);
421     record.OwnBinary();
422     // Set type explicitly as the perf.data produced by perf doesn't set it.
423     record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
424     result.push_back(std::move(record));
425   }
426   return result;
427 }
428
429 std::string RecordFileReader::ReadFeatureString(int feature) {
430   std::vector<char> buf;
431   if (!ReadFeatureSection(feature, &buf)) {
432     return std::string();
433   }
434   const char* p = buf.data();
435   const char* end = buf.data() + buf.size();
436   uint32_t len;
437   MoveFromBinaryFormat(len, p);
438   CHECK_LE(p + len, end);
439   return p;
440 }
441
442 bool RecordFileReader::ReadFileFeature(size_t& read_pos,
443                                        std::string* file_path,
444                                        uint32_t* file_type,
445                                        uint64_t* min_vaddr,
446                                        std::vector<Symbol>* symbols) {
447   auto it = feature_section_descriptors_.find(FEAT_FILE);
448   if (it == feature_section_descriptors_.end()) {
449     return false;
450   }
451   if (read_pos >= it->second.size) {
452     return false;
453   }
454   if (read_pos == 0) {
455     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
456       PLOG(ERROR) << "fseek() failed";
457       return false;
458     }
459   }
460   uint32_t size;
461   if (!Read(&size, 4)) {
462     return false;
463   }
464   std::vector<char> buf(size);
465   if (!Read(buf.data(), size)) {
466     return false;
467   }
468   read_pos += 4 + size;
469   const char* p = buf.data();
470   *file_path = p;
471   p += file_path->size() + 1;
472   MoveFromBinaryFormat(*file_type, p);
473   MoveFromBinaryFormat(*min_vaddr, p);
474   uint32_t symbol_count;
475   MoveFromBinaryFormat(symbol_count, p);
476   symbols->clear();
477   symbols->reserve(symbol_count);
478   for (uint32_t i = 0; i < symbol_count; ++i) {
479     uint64_t start_vaddr;
480     uint32_t len;
481     MoveFromBinaryFormat(start_vaddr, p);
482     MoveFromBinaryFormat(len, p);
483     std::string name = p;
484     p += name.size() + 1;
485     symbols->emplace_back(name, start_vaddr, len);
486   }
487   CHECK_EQ(size, static_cast<size_t>(p - buf.data()));
488   return true;
489 }
490
491 bool RecordFileReader::ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map) {
492   std::vector<char> buf;
493   if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
494     return false;
495   }
496   const char* p = buf.data();
497   const char* end = buf.data() + buf.size();
498   while (p < end) {
499     const char* key = p;
500     const char* value = key + strlen(key) + 1;
501     CHECK(value < end);
502     (*info_map)[p] = value;
503     p = value + strlen(value) + 1;
504   }
505   return true;
506 }
507
508 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
509   std::vector<BuildIdRecord> records = ReadBuildIdFeature();
510   std::vector<std::pair<std::string, BuildId>> build_ids;
511   for (auto& r : records) {
512     build_ids.push_back(std::make_pair(r.filename, r.build_id));
513   }
514   Dso::SetBuildIds(build_ids);
515
516   if (HasFeature(PerfFileFormat::FEAT_FILE)) {
517     std::string file_path;
518     uint32_t file_type;
519     uint64_t min_vaddr;
520     std::vector<Symbol> symbols;
521     size_t read_pos = 0;
522     while (ReadFileFeature(
523         read_pos, &file_path, &file_type, &min_vaddr, &symbols)) {
524       thread_tree.AddDsoInfo(file_path, file_type, min_vaddr, &symbols);
525     }
526   }
527 }
528
529 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
530   std::vector<std::unique_ptr<Record>> records;
531   ReadDataSection([&](std::unique_ptr<Record> record) {
532     records.push_back(std::move(record));
533     return true;
534   });
535   return records;
536 }