Home | History | Annotate | Download | only in quipper
      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