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