OSDN Git Service

DO NOT MERGE verity_verifier: Support verifying images with FEC. am: 989f6a13a7 am...
[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 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
33   std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
34   FILE* fp = fopen(filename.c_str(), mode.c_str());
35   if (fp == nullptr) {
36     PLOG(ERROR) << "failed to open record file '" << filename << "'";
37     return nullptr;
38   }
39   auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
40   if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
41       !reader->ReadFeatureSectionDescriptors()) {
42     return nullptr;
43   }
44   return reader;
45 }
46
47 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
48     : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
49       event_id_reverse_pos_in_non_sample_records_(0), read_record_size_(0) {
50 }
51
52 RecordFileReader::~RecordFileReader() {
53   if (record_fp_ != nullptr) {
54     Close();
55   }
56 }
57
58 bool RecordFileReader::Close() {
59   bool result = true;
60   if (fclose(record_fp_) != 0) {
61     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
62     result = false;
63   }
64   record_fp_ = nullptr;
65   return result;
66 }
67
68 bool RecordFileReader::ReadHeader() {
69   return Read(&header_, sizeof(header_));
70 }
71
72 bool RecordFileReader::ReadAttrSection() {
73   size_t attr_count = header_.attrs.size / header_.attr_size;
74   if (header_.attr_size != sizeof(FileAttr)) {
75     LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
76                  << " doesn't match expected size (" << sizeof(FileAttr) << ")";
77   }
78   if (attr_count == 0) {
79     LOG(ERROR) << "no attr in file " << filename_;
80     return false;
81   }
82   if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
83     PLOG(ERROR) << "fseek() failed";
84     return false;
85   }
86   for (size_t i = 0; i < attr_count; ++i) {
87     std::vector<char> buf(header_.attr_size);
88     if (!Read(buf.data(), buf.size())) {
89       return false;
90     }
91     // The size of perf_event_attr is changing between different linux kernel versions.
92     // Make sure we copy correct data to memory.
93     FileAttr attr;
94     memset(&attr, 0, sizeof(attr));
95     size_t section_desc_size = sizeof(attr.ids);
96     size_t perf_event_attr_size = header_.attr_size - section_desc_size;
97     memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
98     memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
99     file_attrs_.push_back(attr);
100   }
101   if (file_attrs_.size() > 1) {
102     std::vector<perf_event_attr> attrs;
103     for (const auto& file_attr : file_attrs_) {
104       attrs.push_back(file_attr.attr);
105     }
106     if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
107                                                &event_id_reverse_pos_in_non_sample_records_)) {
108       return false;
109     }
110   }
111   for (size_t i = 0; i < file_attrs_.size(); ++i) {
112     std::vector<uint64_t> ids;
113     if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
114       return false;
115     }
116     event_ids_for_file_attrs_.push_back(ids);
117     for (auto id : ids) {
118       event_id_to_attr_map_[id] = i;
119     }
120   }
121   return true;
122 }
123
124 bool RecordFileReader::ReadFeatureSectionDescriptors() {
125   std::vector<int> features;
126   for (size_t i = 0; i < sizeof(header_.features); ++i) {
127     for (size_t j = 0; j < 8; ++j) {
128       if (header_.features[i] & (1 << j)) {
129         features.push_back(i * 8 + j);
130       }
131     }
132   }
133   uint64_t feature_section_offset = header_.data.offset + header_.data.size;
134   if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
135     PLOG(ERROR) << "fseek() failed";
136     return false;
137   }
138   for (const auto& id : features) {
139     SectionDesc desc;
140     if (!Read(&desc, sizeof(desc))) {
141       return false;
142     }
143     feature_section_descriptors_.emplace(id, desc);
144   }
145   return true;
146 }
147
148 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
149   size_t id_count = attr.ids.size / sizeof(uint64_t);
150   if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
151     PLOG(ERROR) << "fseek() failed";
152     return false;
153   }
154   ids->resize(id_count);
155   if (!Read(ids->data(), attr.ids.size)) {
156     return false;
157   }
158   return true;
159 }
160
161 bool RecordFileReader::ReadDataSection(
162     const std::function<bool(std::unique_ptr<Record>)>& callback, bool sorted) {
163   std::unique_ptr<Record> record;
164   while (ReadRecord(record, sorted)) {
165     if (record == nullptr) {
166       return true;
167     }
168     if (!callback(std::move(record))) {
169       return false;
170     }
171   }
172   return false;
173 }
174
175 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record,
176                                   bool sorted) {
177   if (read_record_size_ == 0) {
178     if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
179       PLOG(ERROR) << "fseek() failed";
180       return false;
181     }
182     bool has_timestamp = true;
183     for (const auto& attr : file_attrs_) {
184       if (!IsTimestampSupported(attr.attr)) {
185         has_timestamp = false;
186         break;
187       }
188     }
189     record_cache_.reset(new RecordCache(has_timestamp));
190   }
191   record = nullptr;
192   while (read_record_size_ < header_.data.size && record == nullptr) {
193     record = ReadRecord(&read_record_size_);
194     if (record == nullptr) {
195       return false;
196     }
197     if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
198       ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
199     }
200     if (sorted) {
201       record_cache_->Push(std::move(record));
202       record = record_cache_->Pop();
203     }
204   }
205   if (record == nullptr) {
206     record = record_cache_->ForcedPop();
207   }
208   return true;
209 }
210
211 std::unique_ptr<Record> RecordFileReader::ReadRecord(uint64_t* nbytes_read) {
212   char header_buf[Record::header_size()];
213   if (!Read(header_buf, Record::header_size())) {
214     return nullptr;
215   }
216   RecordHeader header(header_buf);
217   std::unique_ptr<char[]> p;
218   if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
219     // Read until meeting a RECORD_SPLIT_END record.
220     std::vector<char> buf;
221     size_t cur_size = 0;
222     char header_buf[Record::header_size()];
223     while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
224       size_t bytes_to_read = header.size - Record::header_size();
225       buf.resize(cur_size + bytes_to_read);
226       if (!Read(&buf[cur_size], bytes_to_read)) {
227         return nullptr;
228       }
229       cur_size += bytes_to_read;
230       *nbytes_read += header.size;
231       if (!Read(header_buf, Record::header_size())) {
232         return nullptr;
233       }
234       header = RecordHeader(header_buf);
235     }
236     if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
237       LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
238       return nullptr;
239     }
240     *nbytes_read += header.size;
241     header = RecordHeader(buf.data());
242     p.reset(new char[header.size]);
243     memcpy(p.get(), buf.data(), buf.size());
244   } else {
245     p.reset(new char[header.size]);
246     memcpy(p.get(), header_buf, Record::header_size());
247     if (header.size > Record::header_size()) {
248       if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
249         return nullptr;
250       }
251     }
252     *nbytes_read += header.size;
253   }
254
255   const perf_event_attr* attr = &file_attrs_[0].attr;
256   if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
257     bool has_event_id = false;
258     uint64_t event_id;
259     if (header.type == PERF_RECORD_SAMPLE) {
260       if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
261         has_event_id = true;
262         event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
263       }
264     } else {
265       if (header.size > event_id_reverse_pos_in_non_sample_records_) {
266         has_event_id = true;
267         event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size - event_id_reverse_pos_in_non_sample_records_);
268       }
269     }
270     if (has_event_id) {
271       auto it = event_id_to_attr_map_.find(event_id);
272       if (it != event_id_to_attr_map_.end()) {
273         attr = &file_attrs_[it->second].attr;
274       }
275     }
276   }
277   return ReadRecordFromOwnedBuffer(*attr, header.type, p.release());
278 }
279
280 bool RecordFileReader::Read(void* buf, size_t len) {
281   if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
282     PLOG(FATAL) << "failed to read file " << filename_;
283     return false;
284   }
285   return true;
286 }
287
288 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
289   for (size_t i = 0; i < r.count; ++i) {
290     event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
291     event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
292   }
293 }
294
295 size_t RecordFileReader::GetAttrIndexOfRecord(const SampleRecord& record) {
296   auto it = event_id_to_attr_map_.find(record.id_data.id);
297   if (it != event_id_to_attr_map_.end()) {
298     return it->second;
299   }
300   return 0;
301 }
302
303 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
304   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
305   auto it = section_map.find(feature);
306   if (it == section_map.end()) {
307     return false;
308   }
309   SectionDesc section = it->second;
310   data->resize(section.size);
311   if (section.size == 0) {
312     return true;
313   }
314   if (fseek(record_fp_, section.offset, SEEK_SET) != 0) {
315     PLOG(ERROR) << "fseek() failed";
316     return false;
317   }
318   if (!Read(data->data(), data->size())) {
319     return false;
320   }
321   return true;
322 }
323
324 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
325   std::vector<char> buf;
326   if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
327     return std::vector<std::string>();
328   }
329   const char* p = buf.data();
330   const char* end = buf.data() + buf.size();
331   std::vector<std::string> cmdline;
332   uint32_t arg_count;
333   MoveFromBinaryFormat(arg_count, p);
334   CHECK_LE(p, end);
335   for (size_t i = 0; i < arg_count; ++i) {
336     uint32_t len;
337     MoveFromBinaryFormat(len, p);
338     CHECK_LE(p + len, end);
339     cmdline.push_back(p);
340     p += len;
341   }
342   return cmdline;
343 }
344
345 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
346   std::vector<char> buf;
347   if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
348     return std::vector<BuildIdRecord>();
349   }
350   const char* p = buf.data();
351   const char* end = buf.data() + buf.size();
352   std::vector<BuildIdRecord> result;
353   while (p < end) {
354     auto header = reinterpret_cast<const perf_event_header*>(p);
355     CHECK_LE(p + header->size, end);
356     char* binary = new char[header->size];
357     memcpy(binary, p, header->size);
358     p += header->size;
359     BuildIdRecord record(binary);
360     record.OwnBinary();
361     // Set type explicitly as the perf.data produced by perf doesn't set it.
362     record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
363     result.push_back(std::move(record));
364   }
365   return result;
366 }
367
368 std::string RecordFileReader::ReadFeatureString(int feature) {
369   std::vector<char> buf;
370   if (!ReadFeatureSection(feature, &buf)) {
371     return std::string();
372   }
373   const char* p = buf.data();
374   const char* end = buf.data() + buf.size();
375   uint32_t len;
376   MoveFromBinaryFormat(len, p);
377   CHECK_LE(p + len, end);
378   return p;
379 }
380
381 bool RecordFileReader::ReadFileFeature(size_t& read_pos,
382                                        std::string* file_path,
383                                        uint32_t* file_type,
384                                        uint64_t* min_vaddr,
385                                        std::vector<Symbol>* symbols) {
386   auto it = feature_section_descriptors_.find(FEAT_FILE);
387   if (it == feature_section_descriptors_.end()) {
388     return false;
389   }
390   if (read_pos >= it->second.size) {
391     return false;
392   }
393   if (read_pos == 0) {
394     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
395       PLOG(ERROR) << "fseek() failed";
396       return false;
397     }
398   }
399   uint32_t size;
400   if (!Read(&size, 4)) {
401     return false;
402   }
403   std::vector<char> buf(size);
404   if (!Read(buf.data(), size)) {
405     return false;
406   }
407   read_pos += 4 + size;
408   const char* p = buf.data();
409   *file_path = p;
410   p += file_path->size() + 1;
411   MoveFromBinaryFormat(*file_type, p);
412   MoveFromBinaryFormat(*min_vaddr, p);
413   uint32_t symbol_count;
414   MoveFromBinaryFormat(symbol_count, p);
415   symbols->clear();
416   symbols->reserve(symbol_count);
417   for (uint32_t i = 0; i < symbol_count; ++i) {
418     uint64_t start_vaddr;
419     uint32_t len;
420     MoveFromBinaryFormat(start_vaddr, p);
421     MoveFromBinaryFormat(len, p);
422     std::string name = p;
423     p += name.size() + 1;
424     symbols->emplace_back(name, start_vaddr, len);
425   }
426   CHECK_EQ(size, static_cast<size_t>(p - buf.data()));
427   return true;
428 }
429
430 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
431   std::vector<BuildIdRecord> records = ReadBuildIdFeature();
432   std::vector<std::pair<std::string, BuildId>> build_ids;
433   for (auto& r : records) {
434     build_ids.push_back(std::make_pair(r.filename, r.build_id));
435   }
436   Dso::SetBuildIds(build_ids);
437
438   if (HasFeature(PerfFileFormat::FEAT_FILE)) {
439     std::string file_path;
440     uint32_t file_type;
441     uint64_t min_vaddr;
442     std::vector<Symbol> symbols;
443     size_t read_pos = 0;
444     while (ReadFileFeature(
445         read_pos, &file_path, &file_type, &min_vaddr, &symbols)) {
446       thread_tree.AddDsoInfo(file_path, file_type, min_vaddr, &symbols);
447     }
448   }
449 }
450
451 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
452   std::vector<std::unique_ptr<Record>> records;
453   ReadDataSection([&](std::unique_ptr<Record> record) {
454     records.push_back(std::move(record));
455     return true;
456   });
457   return records;
458 }