1 // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "perf_parser.h" 6 7 #include <fcntl.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 #include <unistd.h> 13 #include <algorithm> 14 15 #include <memory> 16 #include <set> 17 #include <sstream> 18 19 #include "base/logging.h" 20 21 #include "address_mapper.h" 22 #include "binary_data_utils.h" 23 #include "compat/proto.h" 24 #include "compat/string.h" 25 #include "dso.h" 26 #include "huge_page_deducer.h" 27 28 namespace quipper { 29 30 using BranchStackEntry = PerfDataProto_BranchStackEntry; 31 using CommEvent = PerfDataProto_CommEvent; 32 using ForkEvent = PerfDataProto_ForkEvent; 33 using MMapEvent = PerfDataProto_MMapEvent; 34 using SampleEvent = PerfDataProto_SampleEvent; 35 36 namespace { 37 38 // MMAPs are aligned to pages of this many bytes. 39 const uint64_t kMmapPageAlignment = sysconf(_SC_PAGESIZE); 40 41 // Name and ID of the kernel swapper process. 42 const char kSwapperCommandName[] = "swapper"; 43 const uint32_t kSwapperPid = 0; 44 45 // Returns the offset within a page of size |kMmapPageAlignment|, given an 46 // address. Requires that |kMmapPageAlignment| be a power of 2. 47 uint64_t GetPageAlignedOffset(uint64_t addr) { 48 return addr % kMmapPageAlignment; 49 } 50 51 bool IsNullBranchStackEntry(const BranchStackEntry& entry) { 52 return (!entry.from_ip() && !entry.to_ip()); 53 } 54 55 } // namespace 56 57 PerfParser::PerfParser(PerfReader* reader) : reader_(reader) {} 58 59 PerfParser::~PerfParser() {} 60 61 PerfParser::PerfParser(PerfReader* reader, const PerfParserOptions& options) 62 : reader_(reader), options_(options) {} 63 64 bool PerfParser::ParseRawEvents() { 65 if (options_.sort_events_by_time) { 66 reader_->MaybeSortEventsByTime(); 67 } 68 69 // Just in case there was data from a previous call. 70 process_mappers_.clear(); 71 72 // Find huge page mappings. 73 if (options_.deduce_huge_page_mappings) { 74 DeduceHugePages(reader_->mutable_events()); 75 } 76 77 // Combine split mappings. Because the remapping process makes addresses 78 // contiguous, we cannot try to combine mappings in these situations (as we 79 // collapse maps that were non-contiguous). 80 if (options_.combine_mappings && !options_.do_remap) { 81 CombineMappings(reader_->mutable_events()); 82 } 83 84 // Clear the parsed events to reset their fields. Otherwise, non-sample events 85 // may have residual DSO+offset info. 86 parsed_events_.clear(); 87 88 // Events of type PERF_RECORD_FINISHED_ROUND don't have a timestamp, and are 89 // not needed. 90 // use the partial-sorting of events between rounds to sort faster. 91 parsed_events_.resize(reader_->events().size()); 92 size_t write_index = 0; 93 for (int i = 0; i < reader_->events().size(); ++i) { 94 if (reader_->events().Get(i).header().type() == PERF_RECORD_FINISHED_ROUND) 95 continue; 96 parsed_events_[write_index++].event_ptr = 97 reader_->mutable_events()->Mutable(i); 98 } 99 parsed_events_.resize(write_index); 100 101 ProcessEvents(); 102 103 if (!options_.discard_unused_events) return true; 104 105 // Some MMAP/MMAP2 events' mapped regions will not have any samples. These 106 // MMAP/MMAP2 events should be dropped. |parsed_events_| should be 107 // reconstructed without these events. 108 write_index = 0; 109 size_t read_index; 110 for (read_index = 0; read_index < parsed_events_.size(); ++read_index) { 111 const ParsedEvent& event = parsed_events_[read_index]; 112 if (event.event_ptr->has_mmap_event() && 113 event.num_samples_in_mmap_region == 0) { 114 continue; 115 } 116 if (read_index != write_index) parsed_events_[write_index] = event; 117 ++write_index; 118 } 119 CHECK_LE(write_index, parsed_events_.size()); 120 parsed_events_.resize(write_index); 121 122 // Update the events in |reader_| to match the updated events. 123 UpdatePerfEventsFromParsedEvents(); 124 125 return true; 126 } 127 128 bool PerfParser::ProcessUserEvents(PerfEvent& event) { 129 // New user events from PERF-4.13 is not yet supported 130 switch (event.header().type()) { 131 case PERF_RECORD_AUXTRACE: 132 VLOG(1) << "Parsed event type: " << event.header().type() 133 << ". Doing nothing."; 134 break; 135 default: 136 VLOG(1) << "Unsupported event type: " << event.header().type(); 137 break; 138 } 139 return true; 140 } 141 142 bool PerfParser::ProcessEvents() { 143 stats_ = {0}; 144 145 stats_.did_remap = false; // Explicitly clear the remap flag. 146 147 // Pid 0 is called the swapper process. Even though perf does not record a 148 // COMM event for pid 0, we act like we did receive a COMM event for it. Perf 149 // does this itself, example: 150 // http://lxr.free-electrons.com/source/tools/perf/util/session.c#L1120 151 commands_.insert(kSwapperCommandName); 152 pidtid_to_comm_map_[std::make_pair(kSwapperPid, kSwapperPid)] = 153 &(*commands_.find(kSwapperCommandName)); 154 155 // NB: Not necessarily actually sorted by time. 156 for (size_t i = 0; i < parsed_events_.size(); ++i) { 157 ParsedEvent& parsed_event = parsed_events_[i]; 158 PerfEvent& event = *parsed_event.event_ptr; 159 160 // Process user events 161 if (event.header().type() >= PERF_RECORD_USER_TYPE_START) { 162 if (!ProcessUserEvents(event)) { 163 return false; 164 } 165 continue; 166 } 167 168 switch (event.header().type()) { 169 case PERF_RECORD_SAMPLE: 170 // SAMPLE doesn't have any fields to log at a fixed, 171 // previously-endian-swapped location. This used to log ip. 172 VLOG(1) << "SAMPLE"; 173 ++stats_.num_sample_events; 174 if (MapSampleEvent(&parsed_event)) ++stats_.num_sample_events_mapped; 175 break; 176 case PERF_RECORD_MMAP: 177 case PERF_RECORD_MMAP2: { 178 const char* mmap_type_name = 179 event.header().type() == PERF_RECORD_MMAP ? "MMAP" : "MMAP2"; 180 VLOG(1) << mmap_type_name << ": " << event.mmap_event().filename(); 181 ++stats_.num_mmap_events; 182 // Use the array index of the current mmap event as a unique identifier. 183 CHECK(MapMmapEvent(event.mutable_mmap_event(), i)) 184 << "Unable to map " << mmap_type_name << " event!"; 185 // No samples in this MMAP region yet, hopefully. 186 parsed_event.num_samples_in_mmap_region = 0; 187 DSOInfo dso_info; 188 dso_info.name = event.mmap_event().filename(); 189 if (event.header().type() == PERF_RECORD_MMAP2) { 190 dso_info.maj = event.mmap_event().maj(); 191 dso_info.min = event.mmap_event().min(); 192 dso_info.ino = event.mmap_event().ino(); 193 } 194 name_to_dso_.emplace(dso_info.name, dso_info); 195 break; 196 } 197 case PERF_RECORD_FORK: 198 // clang-format off 199 VLOG(1) << "FORK: " << event.fork_event().ppid() 200 << ":" << event.fork_event().ptid() 201 << " -> " << event.fork_event().pid() 202 << ":" << event.fork_event().tid(); 203 // clang-format on 204 ++stats_.num_fork_events; 205 CHECK(MapForkEvent(event.fork_event())) << "Unable to map FORK event!"; 206 break; 207 case PERF_RECORD_EXIT: 208 // EXIT events have the same structure as FORK events. 209 // clang-format off 210 VLOG(1) << "EXIT: " << event.fork_event().ppid() 211 << ":" << event.fork_event().ptid(); 212 // clang-format on 213 ++stats_.num_exit_events; 214 break; 215 case PERF_RECORD_COMM: 216 { 217 // clang-format off 218 VLOG(1) << "COMM: " << event.comm_event().pid() 219 << ":" << event.comm_event().tid() << ": " 220 << event.comm_event().comm(); 221 // clang-format on 222 ++stats_.num_comm_events; 223 CHECK(MapCommEvent(event.comm_event())); 224 commands_.insert(event.comm_event().comm()); 225 const PidTid pidtid = 226 std::make_pair(event.comm_event().pid(), event.comm_event().tid()); 227 pidtid_to_comm_map_[pidtid] = 228 &(*commands_.find(event.comm_event().comm())); 229 break; 230 } 231 case PERF_RECORD_LOST: 232 case PERF_RECORD_THROTTLE: 233 case PERF_RECORD_UNTHROTTLE: 234 case PERF_RECORD_READ: 235 case PERF_RECORD_AUX: 236 VLOG(1) << "Parsed event type: " << event.header().type() 237 << ". Doing nothing."; 238 break; 239 case PERF_RECORD_ITRACE_START: 240 case PERF_RECORD_LOST_SAMPLES: 241 case PERF_RECORD_SWITCH: 242 case PERF_RECORD_SWITCH_CPU_WIDE: 243 case PERF_RECORD_NAMESPACES: 244 VLOG(1) << "Parsed event type: " << event.header().type() 245 << ". Not yet supported."; 246 break; 247 default: 248 LOG(ERROR) << "Unknown event type: " << event.header().type(); 249 return false; 250 } 251 } 252 if (!FillInDsoBuildIds()) return false; 253 254 // Print stats collected from parsing. 255 // clang-format off 256 VLOG(1) << "Parser processed: " 257 << stats_.num_mmap_events << " MMAP/MMAP2 events, " 258 << stats_.num_comm_events << " COMM events, " 259 << stats_.num_fork_events << " FORK events, " 260 << stats_.num_exit_events << " EXIT events, " 261 << stats_.num_sample_events << " SAMPLE events, " 262 << stats_.num_sample_events_mapped << " of these were mapped"; 263 // clang-format on 264 265 float sample_mapping_percentage = 266 static_cast<float>(stats_.num_sample_events_mapped) / 267 stats_.num_sample_events * 100.; 268 float threshold = options_.sample_mapping_percentage_threshold; 269 if (sample_mapping_percentage < threshold) { 270 LOG(ERROR) << "Mapped " << static_cast<int>(sample_mapping_percentage) 271 << "% of samples, expected at least " 272 << static_cast<int>(threshold) << "%"; 273 return false; 274 } 275 stats_.did_remap = options_.do_remap; 276 return true; 277 } 278 279 namespace { 280 281 class FdCloser { 282 public: 283 explicit FdCloser(int fd) : fd_(fd) {} 284 ~FdCloser() { 285 if (fd_ != -1) close(fd_); 286 } 287 288 private: 289 FdCloser() = delete; 290 FdCloser(FdCloser&) = delete; 291 292 int fd_; 293 }; 294 295 // Merges two uint32_t into a uint64_t for hashing in an unordered_set because 296 // there is no default hash method for a pair. 297 uint64_t mergeTwoU32(uint32_t first, uint32_t second) { 298 return (uint64_t)first << 32 | second; 299 } 300 301 // Splits a given uint64_t into two uint32_t. This reverts the above merge 302 // operation to retrieve the two uint32_t from an unordered_set. 303 std::pair<uint32_t, uint32_t> splitU64(uint64_t value) { 304 return std::make_pair(value >> 32, 305 std::numeric_limits<uint32_t>::max() & value); 306 } 307 308 bool ReadElfBuildIdIfSameInode(const string& dso_path, const DSOInfo& dso, 309 string* buildid) { 310 int fd = open(dso_path.c_str(), O_RDONLY); 311 FdCloser fd_closer(fd); 312 if (fd == -1) { 313 if (errno != ENOENT) LOG(ERROR) << "Failed to open ELF file: " << dso_path; 314 return false; 315 } 316 317 struct stat s; 318 CHECK_GE(fstat(fd, &s), 0); 319 // Only reject based on inode if we actually have device info (from MMAP2). 320 if (dso.maj != 0 && dso.min != 0 && !SameInode(dso, &s)) return false; 321 322 return ReadElfBuildId(fd, buildid); 323 } 324 325 // Looks up build ID of a given DSO by reading directly from the file system. 326 // - Does not support reading build ID of the main kernel binary. 327 // - Reads build IDs of kernel modules and other DSOs using functions in dso.h. 328 string FindDsoBuildId(const DSOInfo& dso_info) { 329 string buildid_bin; 330 const string& dso_name = dso_info.name; 331 if (IsKernelNonModuleName(dso_name)) return buildid_bin; // still empty 332 // Does this look like a kernel module? 333 if (dso_name.size() >= 2 && dso_name[0] == '[' && dso_name.back() == ']') { 334 // This may not be successful, but either way, just return. buildid_bin 335 // will be empty if the module was not found. 336 ReadModuleBuildId(dso_name.substr(1, dso_name.size() - 2), &buildid_bin); 337 return buildid_bin; 338 } 339 // Try normal files, possibly inside containers. 340 u32 last_pid = 0; 341 std::vector<uint64_t> threads(dso_info.threads.begin(), 342 dso_info.threads.end()); 343 std::sort(threads.begin(), threads.end()); 344 for (auto pidtid_it : threads) { 345 uint32_t pid, tid; 346 std::tie(pid, tid) = splitU64(pidtid_it); 347 std::stringstream dso_path_stream; 348 dso_path_stream << "/proc/" << tid << "/root/" << dso_name; 349 string dso_path = dso_path_stream.str(); 350 if (ReadElfBuildIdIfSameInode(dso_path, dso_info, &buildid_bin)) { 351 return buildid_bin; 352 } 353 // Avoid re-trying the parent process if it's the same for multiple threads. 354 // dso_info.threads is sorted, so threads in a process should be adjacent. 355 if (pid == last_pid || pid == tid) continue; 356 last_pid = pid; 357 // Try the parent process: 358 std::stringstream parent_dso_path_stream; 359 parent_dso_path_stream << "/proc/" << pid << "/root/" << dso_name; 360 string parent_dso_path = parent_dso_path_stream.str(); 361 if (ReadElfBuildIdIfSameInode(parent_dso_path, dso_info, &buildid_bin)) { 362 return buildid_bin; 363 } 364 } 365 // Still don't have a buildid. Try our own filesystem: 366 if (ReadElfBuildIdIfSameInode(dso_name, dso_info, &buildid_bin)) { 367 return buildid_bin; 368 } 369 return buildid_bin; // still empty. 370 } 371 372 } // namespace 373 374 bool PerfParser::FillInDsoBuildIds() { 375 std::map<string, string> filenames_to_build_ids; 376 reader_->GetFilenamesToBuildIDs(&filenames_to_build_ids); 377 378 std::map<string, string> new_buildids; 379 380 for (std::pair<const string, DSOInfo>& kv : name_to_dso_) { 381 DSOInfo& dso_info = kv.second; 382 const auto it = filenames_to_build_ids.find(dso_info.name); 383 if (it != filenames_to_build_ids.end()) { 384 dso_info.build_id = it->second; 385 } 386 // If there is both an existing build ID and a new build ID returned by 387 // FindDsoBuildId(), overwrite the existing build ID. 388 if (options_.read_missing_buildids && dso_info.hit) { 389 string buildid_bin = FindDsoBuildId(dso_info); 390 if (!buildid_bin.empty()) { 391 dso_info.build_id = RawDataToHexString(buildid_bin); 392 new_buildids[dso_info.name] = dso_info.build_id; 393 } 394 } 395 } 396 397 if (new_buildids.empty()) return true; 398 return reader_->InjectBuildIDs(new_buildids); 399 } 400 401 void PerfParser::UpdatePerfEventsFromParsedEvents() { 402 // Reorder the events in |reader_| to match the order of |parsed_events_|. 403 // The |event_ptr|'s in |parsed_events_| are pointers to existing events in 404 // |reader_|. 405 RepeatedPtrField<PerfEvent> new_events; 406 new_events.Reserve(parsed_events_.size()); 407 for (ParsedEvent& parsed_event : parsed_events_) { 408 PerfEvent* new_event = new_events.Add(); 409 new_event->Swap(parsed_event.event_ptr); 410 parsed_event.event_ptr = new_event; 411 } 412 413 reader_->mutable_events()->Swap(&new_events); 414 } 415 416 bool PerfParser::MapSampleEvent(ParsedEvent* parsed_event) { 417 bool mapping_failed = false; 418 419 const PerfEvent& event = *parsed_event->event_ptr; 420 if (!event.has_sample_event() || 421 !(event.sample_event().has_ip() && event.sample_event().has_pid() && 422 event.sample_event().has_tid())) { 423 return false; 424 } 425 SampleEvent& sample_info = *parsed_event->event_ptr->mutable_sample_event(); 426 427 // Find the associated command. 428 PidTid pidtid = std::make_pair(sample_info.pid(), sample_info.tid()); 429 const auto comm_iter = pidtid_to_comm_map_.find(pidtid); 430 if (comm_iter != pidtid_to_comm_map_.end()) 431 parsed_event->set_command(comm_iter->second); 432 433 const uint64_t unmapped_event_ip = sample_info.ip(); 434 uint64_t remapped_event_ip = 0; 435 436 // Map the event IP itself. 437 if (!MapIPAndPidAndGetNameAndOffset(sample_info.ip(), pidtid, 438 &remapped_event_ip, 439 &parsed_event->dso_and_offset)) { 440 mapping_failed = true; 441 } else { 442 sample_info.set_ip(remapped_event_ip); 443 } 444 445 if (sample_info.callchain_size() && 446 !MapCallchain(sample_info.ip(), pidtid, unmapped_event_ip, 447 sample_info.mutable_callchain(), parsed_event)) { 448 mapping_failed = true; 449 } 450 451 if (sample_info.branch_stack_size() && 452 !MapBranchStack(pidtid, sample_info.mutable_branch_stack(), 453 parsed_event)) { 454 mapping_failed = true; 455 } 456 457 return !mapping_failed; 458 } 459 460 bool PerfParser::MapCallchain(const uint64_t ip, const PidTid pidtid, 461 const uint64_t original_event_addr, 462 RepeatedField<uint64>* callchain, 463 ParsedEvent* parsed_event) { 464 if (!callchain) { 465 LOG(ERROR) << "NULL call stack data."; 466 return false; 467 } 468 469 bool mapping_failed = false; 470 471 // If the callchain is empty, there is no work to do. 472 if (callchain->empty()) return true; 473 474 // Keeps track of whether the current entry is kernel or user. 475 parsed_event->callchain.resize(callchain->size()); 476 int num_entries_mapped = 0; 477 for (int i = 0; i < callchain->size(); ++i) { 478 uint64_t entry = callchain->Get(i); 479 // When a callchain context entry is found, do not attempt to symbolize it. 480 if (entry >= PERF_CONTEXT_MAX) { 481 continue; 482 } 483 // The sample address has already been mapped so no need to map it. 484 if (entry == original_event_addr) { 485 callchain->Set(i, ip); 486 continue; 487 } 488 uint64_t mapped_addr = 0; 489 if (!MapIPAndPidAndGetNameAndOffset( 490 entry, pidtid, &mapped_addr, 491 &parsed_event->callchain[num_entries_mapped++])) { 492 mapping_failed = true; 493 } else { 494 callchain->Set(i, mapped_addr); 495 } 496 } 497 // Not all the entries were mapped. Trim |parsed_event->callchain| to 498 // remove unused entries at the end. 499 parsed_event->callchain.resize(num_entries_mapped); 500 501 return !mapping_failed; 502 } 503 504 bool PerfParser::MapBranchStack( 505 const PidTid pidtid, RepeatedPtrField<BranchStackEntry>* branch_stack, 506 ParsedEvent* parsed_event) { 507 if (!branch_stack) { 508 LOG(ERROR) << "NULL branch stack data."; 509 return false; 510 } 511 512 // First, trim the branch stack to remove trailing null entries. 513 size_t trimmed_size = 0; 514 for (const BranchStackEntry& entry : *branch_stack) { 515 // Count the number of non-null entries before the first null entry. 516 if (IsNullBranchStackEntry(entry)) break; 517 ++trimmed_size; 518 } 519 520 // If a null entry was found, make sure all subsequent null entries are NULL 521 // as well. 522 for (int i = trimmed_size; i < branch_stack->size(); ++i) { 523 const BranchStackEntry& entry = branch_stack->Get(i); 524 if (!IsNullBranchStackEntry(entry)) { 525 LOG(ERROR) << "Non-null branch stack entry found after null entry: " 526 << reinterpret_cast<void*>(entry.from_ip()) << " -> " 527 << reinterpret_cast<void*>(entry.to_ip()); 528 return false; 529 } 530 } 531 532 // Map branch stack addresses. 533 parsed_event->branch_stack.resize(trimmed_size); 534 for (unsigned int i = 0; i < trimmed_size; ++i) { 535 BranchStackEntry* entry = branch_stack->Mutable(i); 536 ParsedEvent::BranchEntry& parsed_entry = parsed_event->branch_stack[i]; 537 538 uint64_t from_mapped = 0; 539 if (!MapIPAndPidAndGetNameAndOffset(entry->from_ip(), pidtid, &from_mapped, 540 &parsed_entry.from)) { 541 return false; 542 } 543 entry->set_from_ip(from_mapped); 544 545 uint64_t to_mapped = 0; 546 if (!MapIPAndPidAndGetNameAndOffset(entry->to_ip(), pidtid, &to_mapped, 547 &parsed_entry.to)) { 548 return false; 549 } 550 entry->set_to_ip(to_mapped); 551 552 parsed_entry.predicted = !entry->mispredicted(); 553 } 554 555 return true; 556 } 557 558 bool PerfParser::MapIPAndPidAndGetNameAndOffset( 559 uint64_t ip, PidTid pidtid, uint64_t* new_ip, 560 ParsedEvent::DSOAndOffset* dso_and_offset) { 561 DCHECK(dso_and_offset); 562 // Attempt to find the synthetic address of the IP sample in this order: 563 // 1. Address space of the kernel. 564 // 2. Address space of its own process. 565 // 3. Address space of the parent process. 566 567 uint64_t mapped_addr = 0; 568 569 // Sometimes the first event we see is a SAMPLE event and we don't have the 570 // time to create an address mapper for a process. Example, for pid 0. 571 AddressMapper* mapper = GetOrCreateProcessMapper(pidtid.first).first; 572 AddressMapper::MappingList::const_iterator ip_iter; 573 bool mapped = 574 mapper->GetMappedAddressAndListIterator(ip, &mapped_addr, &ip_iter); 575 if (mapped) { 576 uint64_t id = UINT64_MAX; 577 mapper->GetMappedIDAndOffset(ip, ip_iter, &id, &dso_and_offset->offset_); 578 // Make sure the ID points to a valid event. 579 CHECK_LE(id, parsed_events_.size()); 580 ParsedEvent& parsed_event = parsed_events_[id]; 581 const auto& event = parsed_event.event_ptr; 582 DCHECK(event->has_mmap_event()) << "Expected MMAP or MMAP2 event"; 583 584 // Find the mmap DSO filename in the set of known DSO names. 585 auto dso_iter = name_to_dso_.find(event->mmap_event().filename()); 586 CHECK(dso_iter != name_to_dso_.end()); 587 dso_and_offset->dso_info_ = &dso_iter->second; 588 589 dso_iter->second.hit = true; 590 dso_iter->second.threads.insert(mergeTwoU32(pidtid.first, pidtid.second)); 591 ++parsed_event.num_samples_in_mmap_region; 592 593 if (options_.do_remap) { 594 if (GetPageAlignedOffset(mapped_addr) != GetPageAlignedOffset(ip)) { 595 LOG(ERROR) << "Remapped address " << std::hex << mapped_addr << " " 596 << "does not have the same page alignment offset as " 597 << "original address " << ip; 598 return false; 599 } 600 *new_ip = mapped_addr; 601 } else { 602 *new_ip = ip; 603 } 604 } 605 return mapped; 606 } 607 608 bool PerfParser::MapMmapEvent(PerfDataProto_MMapEvent* event, uint64_t id) { 609 // We need to hide only the real kernel addresses. However, to make things 610 // more secure, and make the mapping idempotent, we should remap all 611 // addresses, both kernel and non-kernel. 612 613 AddressMapper* mapper = GetOrCreateProcessMapper(event->pid()).first; 614 615 uint64_t start = event->start(); 616 uint64_t len = event->len(); 617 uint64_t pgoff = event->pgoff(); 618 619 // |id| == 0 corresponds to the kernel mmap. We have several cases here: 620 // 621 // For ARM and x86, in sudo mode, pgoff == start, example: 622 // start=0x80008200 623 // pgoff=0x80008200 624 // len =0xfffffff7ff7dff 625 // 626 // For x86-64, in sudo mode, pgoff is between start and start + len. SAMPLE 627 // events lie between pgoff and pgoff + length of the real kernel binary, 628 // example: 629 // start=0x3bc00000 630 // pgoff=0xffffffffbcc00198 631 // len =0xffffffff843fffff 632 // SAMPLE events will be found after pgoff. For kernels with ASLR, pgoff will 633 // be something only visible to the root user, and will be randomized at 634 // startup. With |remap| set to true, we should hide pgoff in this case. So we 635 // normalize all SAMPLE events relative to pgoff. 636 // 637 // For non-sudo mode, the kernel will be mapped from 0 to the pointer limit, 638 // example: 639 // start=0x0 640 // pgoff=0x0 641 // len =0xffffffff 642 if (id == 0) { 643 // If pgoff is between start and len, we normalize the event by setting 644 // start to be pgoff just like how it is for ARM and x86. We also set len to 645 // be a much smaller number (closer to the real length of the kernel binary) 646 // because SAMPLEs are actually only seen between |event->pgoff| and 647 // |event->pgoff + kernel text size|. 648 if (pgoff > start && pgoff < start + len) { 649 len = len + start - pgoff; 650 start = pgoff; 651 } 652 // For kernels with ALSR pgoff is critical information that should not be 653 // revealed when |remap| is true. 654 pgoff = 0; 655 } 656 657 if (!mapper->MapWithID(start, len, id, pgoff, true)) { 658 mapper->DumpToLog(); 659 return false; 660 } 661 662 if (options_.do_remap) { 663 uint64_t mapped_addr; 664 AddressMapper::MappingList::const_iterator start_iter; 665 if (!mapper->GetMappedAddressAndListIterator(start, &mapped_addr, 666 &start_iter)) { 667 LOG(ERROR) << "Failed to map starting address " << std::hex << start; 668 return false; 669 } 670 if (GetPageAlignedOffset(mapped_addr) != GetPageAlignedOffset(start)) { 671 LOG(ERROR) << "Remapped address " << std::hex << mapped_addr << " " 672 << "does not have the same page alignment offset as start " 673 << "address " << start; 674 return false; 675 } 676 677 event->set_start(mapped_addr); 678 event->set_len(len); 679 event->set_pgoff(pgoff); 680 } 681 return true; 682 } 683 684 bool PerfParser::MapCommEvent(const PerfDataProto_CommEvent& event) { 685 GetOrCreateProcessMapper(event.pid()); 686 return true; 687 } 688 689 bool PerfParser::MapForkEvent(const PerfDataProto_ForkEvent& event) { 690 PidTid parent = std::make_pair(event.ppid(), event.ptid()); 691 PidTid child = std::make_pair(event.pid(), event.tid()); 692 if (parent != child) { 693 auto parent_iter = pidtid_to_comm_map_.find(parent); 694 if (parent_iter != pidtid_to_comm_map_.end()) 695 pidtid_to_comm_map_[child] = parent_iter->second; 696 } 697 698 const uint32_t pid = event.pid(); 699 700 // If the parent and child pids are the same, this is just a new thread 701 // within the same process, so don't do anything. 702 if (event.ppid() == pid) return true; 703 704 if (!GetOrCreateProcessMapper(pid, event.ppid()).second) { 705 DVLOG(1) << "Found an existing process mapper with pid: " << pid; 706 } 707 708 return true; 709 } 710 711 std::pair<AddressMapper*, bool> PerfParser::GetOrCreateProcessMapper( 712 uint32_t pid, uint32_t ppid) { 713 const auto& search = process_mappers_.find(pid); 714 if (search != process_mappers_.end()) { 715 return std::make_pair(search->second.get(), false); 716 } 717 718 auto parent_mapper = process_mappers_.find(ppid); 719 // Recent perf implementations (at least as recent as perf 4.4), add an 720 // explicit FORK event from the swapper process to the init process. There may 721 // be no explicit memory mappings created for the swapper process. In such 722 // cases, we must use the mappings from the kernel process, which are used by 723 // default for a new PID in the absence of an explicit FORK event. 724 if (parent_mapper == process_mappers_.end()) { 725 parent_mapper = process_mappers_.find(kKernelPid); 726 } 727 std::unique_ptr<AddressMapper> mapper; 728 if (parent_mapper != process_mappers_.end()) { 729 mapper.reset(new AddressMapper(*parent_mapper->second)); 730 } else { 731 mapper.reset(new AddressMapper()); 732 mapper->set_page_alignment(kMmapPageAlignment); 733 } 734 735 const auto inserted = 736 process_mappers_.insert(search, std::make_pair(pid, std::move(mapper))); 737 return std::make_pair(inserted->second.get(), true); 738 } 739 740 } // namespace quipper 741