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/common/mapping_tracker.h"
18
19 #include <cstddef>
20 #include <cstdint>
21 #include <memory>
22 #include <utility>
23
24 #include "perfetto/ext/base/string_utils.h"
25 #include "perfetto/ext/base/string_view.h"
26 #include "src/trace_processor/importers/common/address_range.h"
27 #include "src/trace_processor/importers/common/jit_cache.h"
28 #include "src/trace_processor/storage/trace_storage.h"
29 #include "src/trace_processor/types/trace_processor_context.h"
30 #include "src/trace_processor/util/build_id.h"
31
32 namespace perfetto {
33 namespace trace_processor {
34 namespace {
35
IsKernelModule(const CreateMappingParams & params)36 bool IsKernelModule(const CreateMappingParams& params) {
37 return !base::StartsWith(params.name, "[kernel.kallsyms]") &&
38 !params.memory_range.empty();
39 }
40
41 } // namespace
42
43 template <typename MappingImpl>
AddMapping(std::unique_ptr<MappingImpl> mapping)44 MappingImpl& MappingTracker::AddMapping(std::unique_ptr<MappingImpl> mapping) {
45 auto ptr = mapping.get();
46 PERFETTO_CHECK(
47 mappings_by_id_.Insert(ptr->mapping_id(), std::move(mapping)).second);
48
49 mappings_by_name_and_build_id_[NameAndBuildId{base::StringView(ptr->name()),
50 ptr->build_id()}]
51 .push_back(ptr);
52
53 return *ptr;
54 }
55
CreateKernelMemoryMapping(CreateMappingParams params)56 KernelMemoryMapping& MappingTracker::CreateKernelMemoryMapping(
57 CreateMappingParams params) {
58 // TODO(carlscab): Guess build_id if not provided. Some tools like simpleperf
59 // add a mapping file_name ->build_id that we could use here
60
61 const bool is_module = IsKernelModule(params);
62
63 if (!is_module && kernel_ != nullptr) {
64 PERFETTO_CHECK(params.memory_range == kernel_->memory_range());
65 return *kernel_;
66 }
67
68 std::unique_ptr<KernelMemoryMapping> mapping(
69 new KernelMemoryMapping(context_, std::move(params)));
70
71 if (is_module) {
72 kernel_modules_.DeleteOverlapsAndEmplace(mapping->memory_range(),
73 mapping.get());
74 } else {
75 kernel_ = mapping.get();
76 }
77
78 return AddMapping(std::move(mapping));
79 }
80
CreateUserMemoryMapping(UniquePid upid,CreateMappingParams params)81 UserMemoryMapping& MappingTracker::CreateUserMemoryMapping(
82 UniquePid upid,
83 CreateMappingParams params) {
84 const AddressRange mapping_range = params.memory_range;
85 std::unique_ptr<UserMemoryMapping> mapping(
86 new UserMemoryMapping(context_, upid, std::move(params)));
87
88 user_memory_[upid].DeleteOverlapsAndEmplace(mapping_range, mapping.get());
89
90 jit_caches_[upid].ForOverlaps(
91 mapping_range, [&](std::pair<const AddressRange, JitCache*>& entry) {
92 const auto& jit_range = entry.first;
93 JitCache* jit_cache = entry.second;
94 PERFETTO_CHECK(jit_range.Contains(mapping_range));
95 mapping->SetJitCache(jit_cache);
96 });
97
98 return AddMapping(std::move(mapping));
99 }
100
FindKernelMappingForAddress(uint64_t address) const101 KernelMemoryMapping* MappingTracker::FindKernelMappingForAddress(
102 uint64_t address) const {
103 if (auto it = kernel_modules_.Find(address); it != kernel_modules_.end()) {
104 return it->second;
105 }
106 if (kernel_ && kernel_->memory_range().Contains(address)) {
107 return kernel_;
108 }
109 return nullptr;
110 }
111
FindUserMappingForAddress(UniquePid upid,uint64_t address) const112 UserMemoryMapping* MappingTracker::FindUserMappingForAddress(
113 UniquePid upid,
114 uint64_t address) const {
115 if (auto* vm = user_memory_.Find(upid); vm) {
116 if (auto it = vm->Find(address); it != vm->end()) {
117 return it->second;
118 }
119 }
120
121 if (auto* delegates = jit_caches_.Find(upid); delegates) {
122 if (auto it = delegates->Find(address); it != delegates->end()) {
123 return &it->second->CreateMapping();
124 }
125 }
126
127 return nullptr;
128 }
129
FindMappings(base::StringView name,const BuildId & build_id) const130 std::vector<VirtualMemoryMapping*> MappingTracker::FindMappings(
131 base::StringView name,
132 const BuildId& build_id) const {
133 if (auto res = mappings_by_name_and_build_id_.Find({name, build_id});
134 res != nullptr) {
135 return *res;
136 }
137 return {};
138 }
139
InternMemoryMapping(CreateMappingParams params)140 VirtualMemoryMapping& MappingTracker::InternMemoryMapping(
141 CreateMappingParams params) {
142 if (auto* mapping = interned_mappings_.Find(params); mapping) {
143 return **mapping;
144 }
145
146 std::unique_ptr<VirtualMemoryMapping> mapping(
147 new VirtualMemoryMapping(context_, params));
148 interned_mappings_.Insert(std::move(params), mapping.get());
149 return AddMapping(std::move(mapping));
150 }
151
AddJitRange(UniquePid upid,AddressRange jit_range,JitCache * jit_cache)152 void MappingTracker::AddJitRange(UniquePid upid,
153 AddressRange jit_range,
154 JitCache* jit_cache) {
155 // TODO(carlscab): Deal with overlaps
156 jit_caches_[upid].DeleteOverlapsAndEmplace(jit_range, jit_cache);
157 user_memory_[upid].ForOverlaps(
158 jit_range, [&](std::pair<const AddressRange, UserMemoryMapping*>& entry) {
159 PERFETTO_CHECK(jit_range.Contains(entry.first));
160 entry.second->SetJitCache(jit_cache);
161 });
162 }
163
GetDummyMapping()164 VirtualMemoryMapping* MappingTracker::GetDummyMapping() {
165 if (!dummy_mapping_) {
166 CreateMappingParams params;
167 params.memory_range =
168 AddressRange::FromStartAndSize(0, std::numeric_limits<uint64_t>::max());
169 dummy_mapping_ = &InternMemoryMapping(params);
170 }
171 return dummy_mapping_;
172 }
173
174 } // namespace trace_processor
175 } // namespace perfetto
176