xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/mapping_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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