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