• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 "src/trace_processor/importers/perf/dso_tracker.h"
18 
19 #include <cstdint>
20 
21 #include "perfetto/base/status.h"
22 #include "perfetto/ext/base/string_view.h"
23 #include "protos/third_party/simpleperf/record_file.pbzero.h"
24 #include "src/trace_processor/storage/trace_storage.h"
25 #include "src/trace_processor/tables/profiler_tables_py.h"
26 #include "src/trace_processor/types/trace_processor_context.h"
27 
28 namespace perfetto::trace_processor::perf_importer {
29 namespace {
30 
31 using third_party::simpleperf::proto::pbzero::FileFeature;
32 using DexFile = FileFeature::DexFile;
33 using ElfFile = FileFeature::ElfFile;
34 using KernelModule = FileFeature::KernelModule;
35 using DsoType = FileFeature::DsoType;
36 using Symbol = FileFeature::Symbol;
37 
InsertSymbols(const FileFeature::Decoder & file,AddressRangeMap<std::string> & out)38 void InsertSymbols(const FileFeature::Decoder& file,
39                    AddressRangeMap<std::string>& out) {
40   for (auto raw_symbol = file.symbol(); raw_symbol; ++raw_symbol) {
41     Symbol::Decoder symbol(*raw_symbol);
42     out.DeleteOverlapsAndEmplace(
43         AddressRange::FromStartAndSize(symbol.vaddr(), symbol.len()),
44         symbol.name().ToStdString());
45   }
46 }
47 }  // namespace
48 
DsoTracker(TraceProcessorContext * context)49 DsoTracker::DsoTracker(TraceProcessorContext* context)
50     : context_(context),
51       mapping_table_(context_->storage->stack_profile_mapping_table()) {}
52 DsoTracker::~DsoTracker() = default;
53 
AddSimpleperfFile2(const FileFeature::Decoder & file)54 void DsoTracker::AddSimpleperfFile2(const FileFeature::Decoder& file) {
55   Dso dso;
56   switch (file.type()) {
57     case DsoType::DSO_KERNEL:
58       InsertSymbols(file, kernel_symbols_);
59       return;
60 
61     case DsoType::DSO_ELF_FILE: {
62       ElfFile::Decoder elf(file.elf_file());
63       dso.load_bias = file.min_vaddr() - elf.file_offset_of_min_vaddr();
64       break;
65     }
66 
67     case DsoType::DSO_KERNEL_MODULE: {
68       KernelModule::Decoder module(file.kernel_module());
69       dso.load_bias = file.min_vaddr() - module.memory_offset_of_min_vaddr();
70       break;
71     }
72 
73     case DsoType::DSO_DEX_FILE:
74     case DsoType::DSO_SYMBOL_MAP_FILE:
75     case DsoType::DSO_UNKNOWN_FILE:
76       return;
77   }
78 
79   InsertSymbols(file, dso.symbols);
80   files_.Insert(context_->storage->InternString(file.path()), std::move(dso));
81 }
82 
SymbolizeFrames()83 void DsoTracker::SymbolizeFrames() {
84   const StringId kEmptyString = context_->storage->InternString("");
85   for (auto frame = context_->storage->mutable_stack_profile_frame_table()
86                         ->IterateRows();
87        frame; ++frame) {
88     if (frame.name() != kNullStringId && frame.name() != kEmptyString) {
89       continue;
90     }
91 
92     if (!TrySymbolizeFrame(frame.row_reference())) {
93       SymbolizeKernelFrame(frame.row_reference());
94     }
95   }
96 }
97 
SymbolizeKernelFrame(tables::StackProfileFrameTable::RowReference frame)98 void DsoTracker::SymbolizeKernelFrame(
99     tables::StackProfileFrameTable::RowReference frame) {
100   const auto mapping = *mapping_table_.FindById(frame.mapping());
101   uint64_t address = static_cast<uint64_t>(frame.rel_pc()) +
102                      static_cast<uint64_t>(mapping.start());
103   auto symbol = kernel_symbols_.Find(address);
104   if (symbol == kernel_symbols_.end()) {
105     return;
106   }
107   frame.set_name(
108       context_->storage->InternString(base::StringView(symbol->second)));
109 }
110 
TrySymbolizeFrame(tables::StackProfileFrameTable::RowReference frame)111 bool DsoTracker::TrySymbolizeFrame(
112     tables::StackProfileFrameTable::RowReference frame) {
113   const auto mapping = *mapping_table_.FindById(frame.mapping());
114   auto* file = files_.Find(mapping.name());
115   if (!file) {
116     return false;
117   }
118 
119   // Load bias is something we can only determine by looking at the actual elf
120   // file. Thus PERF_RECORD_MMAP{2} events do not record it. So we need to
121   // potentially do an adjustment here if the load_bias tracked in the mapping
122   // table and the one reported by the file are mismatched.
123   uint64_t adj = file->load_bias - static_cast<uint64_t>(mapping.load_bias());
124 
125   auto symbol = file->symbols.Find(static_cast<uint64_t>(frame.rel_pc()) + adj);
126   if (symbol == file->symbols.end()) {
127     return false;
128   }
129   frame.set_name(
130       context_->storage->InternString(base::StringView(symbol->second)));
131   return true;
132 }
133 
134 }  // namespace perfetto::trace_processor::perf_importer
135