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