xref: /aosp_15_r20/external/cronet/base/profiler/module_cache_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/profiler/module_cache.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <iomanip>
8*6777b538SAndroid Build Coastguard Worker #include <map>
9*6777b538SAndroid Build Coastguard Worker #include <memory>
10*6777b538SAndroid Build Coastguard Worker #include <string_view>
11*6777b538SAndroid Build Coastguard Worker #include <utility>
12*6777b538SAndroid Build Coastguard Worker #include <vector>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/containers/adapters.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/test/bind.h"
19*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
20*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
23*6777b538SAndroid Build Coastguard Worker #include "base/debug/proc_maps_linux.h"
24*6777b538SAndroid Build Coastguard Worker #endif
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker // Note: The special-case IS_CHROMEOS code inside GetDebugBasenameForModule to
27*6777b538SAndroid Build Coastguard Worker // handle the interaction between that function and
28*6777b538SAndroid Build Coastguard Worker // SetProcessTitleFromCommandLine() is tested in
29*6777b538SAndroid Build Coastguard Worker // base/process/set_process_title_linux_unittest.cc due to dependency issues.
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker namespace base {
32*6777b538SAndroid Build Coastguard Worker namespace {
33*6777b538SAndroid Build Coastguard Worker 
AFunctionForTest()34*6777b538SAndroid Build Coastguard Worker int AFunctionForTest() {
35*6777b538SAndroid Build Coastguard Worker   return 42;
36*6777b538SAndroid Build Coastguard Worker }
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker // Provides a module that is guaranteed to be isolated from (and non-contiguous
39*6777b538SAndroid Build Coastguard Worker // with) any other module, by placing the module in the middle of a block of
40*6777b538SAndroid Build Coastguard Worker // heap memory.
41*6777b538SAndroid Build Coastguard Worker class IsolatedModule : public ModuleCache::Module {
42*6777b538SAndroid Build Coastguard Worker  public:
IsolatedModule(bool is_native=true)43*6777b538SAndroid Build Coastguard Worker   explicit IsolatedModule(bool is_native = true)
44*6777b538SAndroid Build Coastguard Worker       : is_native_(is_native), memory_region_(new char[kRegionSize]) {}
45*6777b538SAndroid Build Coastguard Worker 
46*6777b538SAndroid Build Coastguard Worker   // ModuleCache::Module
GetBaseAddress() const47*6777b538SAndroid Build Coastguard Worker   uintptr_t GetBaseAddress() const override {
48*6777b538SAndroid Build Coastguard Worker     // Place the module in the middle of the region.
49*6777b538SAndroid Build Coastguard Worker     return reinterpret_cast<uintptr_t>(&memory_region_[kRegionSize / 4]);
50*6777b538SAndroid Build Coastguard Worker   }
51*6777b538SAndroid Build Coastguard Worker 
GetId() const52*6777b538SAndroid Build Coastguard Worker   std::string GetId() const override { return ""; }
GetDebugBasename() const53*6777b538SAndroid Build Coastguard Worker   FilePath GetDebugBasename() const override { return FilePath(); }
GetSize() const54*6777b538SAndroid Build Coastguard Worker   size_t GetSize() const override { return kRegionSize / 2; }
IsNative() const55*6777b538SAndroid Build Coastguard Worker   bool IsNative() const override { return is_native_; }
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker  private:
58*6777b538SAndroid Build Coastguard Worker   static const int kRegionSize = 100;
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   bool is_native_;
61*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<char[]> memory_region_;
62*6777b538SAndroid Build Coastguard Worker };
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker // Provides a fake module with configurable base address and size.
65*6777b538SAndroid Build Coastguard Worker class FakeModule : public ModuleCache::Module {
66*6777b538SAndroid Build Coastguard Worker  public:
FakeModule(uintptr_t base_address,size_t size,bool is_native=true,OnceClosure destruction_closure=OnceClosure ())67*6777b538SAndroid Build Coastguard Worker   FakeModule(uintptr_t base_address,
68*6777b538SAndroid Build Coastguard Worker              size_t size,
69*6777b538SAndroid Build Coastguard Worker              bool is_native = true,
70*6777b538SAndroid Build Coastguard Worker              OnceClosure destruction_closure = OnceClosure())
71*6777b538SAndroid Build Coastguard Worker       : base_address_(base_address),
72*6777b538SAndroid Build Coastguard Worker         size_(size),
73*6777b538SAndroid Build Coastguard Worker         is_native_(is_native),
74*6777b538SAndroid Build Coastguard Worker         destruction_closure_runner_(std::move(destruction_closure)) {}
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   FakeModule(const FakeModule&) = delete;
77*6777b538SAndroid Build Coastguard Worker   FakeModule& operator=(const FakeModule&) = delete;
78*6777b538SAndroid Build Coastguard Worker 
GetBaseAddress() const79*6777b538SAndroid Build Coastguard Worker   uintptr_t GetBaseAddress() const override { return base_address_; }
GetId() const80*6777b538SAndroid Build Coastguard Worker   std::string GetId() const override { return ""; }
GetDebugBasename() const81*6777b538SAndroid Build Coastguard Worker   FilePath GetDebugBasename() const override { return FilePath(); }
GetSize() const82*6777b538SAndroid Build Coastguard Worker   size_t GetSize() const override { return size_; }
IsNative() const83*6777b538SAndroid Build Coastguard Worker   bool IsNative() const override { return is_native_; }
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker  private:
86*6777b538SAndroid Build Coastguard Worker   uintptr_t base_address_;
87*6777b538SAndroid Build Coastguard Worker   size_t size_;
88*6777b538SAndroid Build Coastguard Worker   bool is_native_;
89*6777b538SAndroid Build Coastguard Worker   ScopedClosureRunner destruction_closure_runner_;
90*6777b538SAndroid Build Coastguard Worker };
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker // Utility function to add a single non-native module during test setup. Returns
93*6777b538SAndroid Build Coastguard Worker // a pointer to the provided module.
AddNonNativeModule(ModuleCache * cache,std::unique_ptr<const ModuleCache::Module> module)94*6777b538SAndroid Build Coastguard Worker const ModuleCache::Module* AddNonNativeModule(
95*6777b538SAndroid Build Coastguard Worker     ModuleCache* cache,
96*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<const ModuleCache::Module> module) {
97*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module_ptr = module.get();
98*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules;
99*6777b538SAndroid Build Coastguard Worker   modules.push_back(std::move(module));
100*6777b538SAndroid Build Coastguard Worker   cache->UpdateNonNativeModules({}, std::move(modules));
101*6777b538SAndroid Build Coastguard Worker   return module_ptr;
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_IOS) && !defined(ARCH_CPU_ARM64)) || \
105*6777b538SAndroid Build Coastguard Worker     BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_WIN)
106*6777b538SAndroid Build Coastguard Worker #define MAYBE_TEST(TestSuite, TestName) TEST(TestSuite, TestName)
107*6777b538SAndroid Build Coastguard Worker #else
108*6777b538SAndroid Build Coastguard Worker #define MAYBE_TEST(TestSuite, TestName) TEST(TestSuite, DISABLED_##TestName)
109*6777b538SAndroid Build Coastguard Worker #endif
110*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,GetDebugBasename)111*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, GetDebugBasename) {
112*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
113*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module =
114*6777b538SAndroid Build Coastguard Worker       cache.GetModuleForAddress(reinterpret_cast<uintptr_t>(&AFunctionForTest));
115*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, module);
116*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
117*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("libbase_unittests__library",
118*6777b538SAndroid Build Coastguard Worker             module->GetDebugBasename().RemoveFinalExtension().value());
119*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_POSIX)
120*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("base_unittests", module->GetDebugBasename().value());
121*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_WIN)
122*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(L"base_unittests.exe.pdb", module->GetDebugBasename().value());
123*6777b538SAndroid Build Coastguard Worker #endif
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker // Checks that ModuleCache returns the same module instance for
127*6777b538SAndroid Build Coastguard Worker // addresses within the module.
MAYBE_TEST(ModuleCacheTest,LookupCodeAddresses)128*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, LookupCodeAddresses) {
129*6777b538SAndroid Build Coastguard Worker   uintptr_t ptr1 = reinterpret_cast<uintptr_t>(&AFunctionForTest);
130*6777b538SAndroid Build Coastguard Worker   uintptr_t ptr2 = ptr1 + 1;
131*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
132*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module1 = cache.GetModuleForAddress(ptr1);
133*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module2 = cache.GetModuleForAddress(ptr2);
134*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module1, module2);
135*6777b538SAndroid Build Coastguard Worker   EXPECT_NE(nullptr, module1);
136*6777b538SAndroid Build Coastguard Worker   EXPECT_GT(module1->GetSize(), 0u);
137*6777b538SAndroid Build Coastguard Worker   EXPECT_LE(module1->GetBaseAddress(), ptr1);
138*6777b538SAndroid Build Coastguard Worker   EXPECT_GT(module1->GetBaseAddress() + module1->GetSize(), ptr2);
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,LookupRange)141*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, LookupRange) {
142*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
143*6777b538SAndroid Build Coastguard Worker   auto to_inject = std::make_unique<IsolatedModule>();
144*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module = to_inject.get();
145*6777b538SAndroid Build Coastguard Worker   cache.AddCustomNativeModule(std::move(to_inject));
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(module->GetBaseAddress() - 1));
148*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module, cache.GetModuleForAddress(module->GetBaseAddress()));
149*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module, cache.GetModuleForAddress(module->GetBaseAddress() +
150*6777b538SAndroid Build Coastguard Worker                                               module->GetSize() - 1));
151*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(module->GetBaseAddress() +
152*6777b538SAndroid Build Coastguard Worker                                                module->GetSize()));
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,LookupNonNativeModule)155*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, LookupNonNativeModule) {
156*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
157*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module =
158*6777b538SAndroid Build Coastguard Worker       AddNonNativeModule(&cache, std::make_unique<IsolatedModule>(false));
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(module->GetBaseAddress() - 1));
161*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module, cache.GetModuleForAddress(module->GetBaseAddress()));
162*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module, cache.GetModuleForAddress(module->GetBaseAddress() +
163*6777b538SAndroid Build Coastguard Worker                                               module->GetSize() - 1));
164*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(module->GetBaseAddress() +
165*6777b538SAndroid Build Coastguard Worker                                                module->GetSize()));
166*6777b538SAndroid Build Coastguard Worker }
167*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,LookupOverlaidNonNativeModule)168*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, LookupOverlaidNonNativeModule) {
169*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker   auto native_module_to_inject = std::make_unique<IsolatedModule>();
172*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* native_module = native_module_to_inject.get();
173*6777b538SAndroid Build Coastguard Worker   cache.AddCustomNativeModule(std::move(native_module_to_inject));
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker   // Overlay the native module with the non-native module, starting 8 bytes into
176*6777b538SAndroid Build Coastguard Worker   // the native modules and ending 8 bytes before the end of the module.
177*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* non_native_module = AddNonNativeModule(
178*6777b538SAndroid Build Coastguard Worker       &cache,
179*6777b538SAndroid Build Coastguard Worker       std::make_unique<FakeModule>(native_module->GetBaseAddress() + 8,
180*6777b538SAndroid Build Coastguard Worker                                    native_module->GetSize() - 16, false));
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(native_module,
183*6777b538SAndroid Build Coastguard Worker             cache.GetModuleForAddress(non_native_module->GetBaseAddress() - 1));
184*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(non_native_module,
185*6777b538SAndroid Build Coastguard Worker             cache.GetModuleForAddress(non_native_module->GetBaseAddress()));
186*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(non_native_module,
187*6777b538SAndroid Build Coastguard Worker             cache.GetModuleForAddress(non_native_module->GetBaseAddress() +
188*6777b538SAndroid Build Coastguard Worker                                       non_native_module->GetSize() - 1));
189*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(native_module,
190*6777b538SAndroid Build Coastguard Worker             cache.GetModuleForAddress(non_native_module->GetBaseAddress() +
191*6777b538SAndroid Build Coastguard Worker                                       non_native_module->GetSize()));
192*6777b538SAndroid Build Coastguard Worker }
193*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesAdd)194*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, UpdateNonNativeModulesAdd) {
195*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
196*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules;
197*6777b538SAndroid Build Coastguard Worker   modules.push_back(std::make_unique<FakeModule>(1, 1, false));
198*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module = modules.back().get();
199*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({}, std::move(modules));
200*6777b538SAndroid Build Coastguard Worker 
201*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module, cache.GetModuleForAddress(1));
202*6777b538SAndroid Build Coastguard Worker }
203*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesRemove)204*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, UpdateNonNativeModulesRemove) {
205*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
206*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules;
207*6777b538SAndroid Build Coastguard Worker   modules.push_back(std::make_unique<FakeModule>(1, 1, false));
208*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module = modules.back().get();
209*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({}, std::move(modules));
210*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({module}, {});
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(1));
213*6777b538SAndroid Build Coastguard Worker }
214*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesRemoveModuleIsNotDestroyed)215*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, UpdateNonNativeModulesRemoveModuleIsNotDestroyed) {
216*6777b538SAndroid Build Coastguard Worker   bool was_destroyed = false;
217*6777b538SAndroid Build Coastguard Worker   {
218*6777b538SAndroid Build Coastguard Worker     ModuleCache cache;
219*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<const ModuleCache::Module>> modules;
220*6777b538SAndroid Build Coastguard Worker     modules.push_back(std::make_unique<FakeModule>(
221*6777b538SAndroid Build Coastguard Worker         1, 1, false,
222*6777b538SAndroid Build Coastguard Worker         BindLambdaForTesting([&was_destroyed]() { was_destroyed = true; })));
223*6777b538SAndroid Build Coastguard Worker     const ModuleCache::Module* module = modules.back().get();
224*6777b538SAndroid Build Coastguard Worker     cache.UpdateNonNativeModules({}, std::move(modules));
225*6777b538SAndroid Build Coastguard Worker     cache.UpdateNonNativeModules({module}, {});
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker     EXPECT_FALSE(was_destroyed);
228*6777b538SAndroid Build Coastguard Worker   }
229*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(was_destroyed);
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker // Regression test to validate that when modules are partitioned into modules to
233*6777b538SAndroid Build Coastguard Worker // keep and modules to remove, the modules to remove are not destroyed.
234*6777b538SAndroid Build Coastguard Worker // https://crbug.com/1127466 case 2.
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesPartitioning)235*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, UpdateNonNativeModulesPartitioning) {
236*6777b538SAndroid Build Coastguard Worker   int destroyed_count = 0;
237*6777b538SAndroid Build Coastguard Worker   const auto record_destroyed = [&destroyed_count]() { ++destroyed_count; };
238*6777b538SAndroid Build Coastguard Worker   {
239*6777b538SAndroid Build Coastguard Worker     ModuleCache cache;
240*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<const ModuleCache::Module>> modules;
241*6777b538SAndroid Build Coastguard Worker     modules.push_back(std::make_unique<FakeModule>(
242*6777b538SAndroid Build Coastguard Worker         1, 1, false, BindLambdaForTesting(record_destroyed)));
243*6777b538SAndroid Build Coastguard Worker     const ModuleCache::Module* module1 = modules.back().get();
244*6777b538SAndroid Build Coastguard Worker     modules.push_back(std::make_unique<FakeModule>(
245*6777b538SAndroid Build Coastguard Worker         2, 1, false, BindLambdaForTesting(record_destroyed)));
246*6777b538SAndroid Build Coastguard Worker     cache.UpdateNonNativeModules({}, std::move(modules));
247*6777b538SAndroid Build Coastguard Worker     cache.UpdateNonNativeModules({module1}, {});
248*6777b538SAndroid Build Coastguard Worker 
249*6777b538SAndroid Build Coastguard Worker     EXPECT_EQ(0, destroyed_count);
250*6777b538SAndroid Build Coastguard Worker   }
251*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(2, destroyed_count);
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesReplace)254*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, UpdateNonNativeModulesReplace) {
255*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
256*6777b538SAndroid Build Coastguard Worker   // Replace a module with another larger module at the same base address.
257*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules1;
258*6777b538SAndroid Build Coastguard Worker   modules1.push_back(std::make_unique<FakeModule>(1, 1, false));
259*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module1 = modules1.back().get();
260*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules2;
261*6777b538SAndroid Build Coastguard Worker   modules2.push_back(std::make_unique<FakeModule>(1, 2, false));
262*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module2 = modules2.back().get();
263*6777b538SAndroid Build Coastguard Worker 
264*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({}, std::move(modules1));
265*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({module1}, std::move(modules2));
266*6777b538SAndroid Build Coastguard Worker 
267*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module2, cache.GetModuleForAddress(2));
268*6777b538SAndroid Build Coastguard Worker }
269*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesMultipleRemovedModulesAtSameAddress)270*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest,
271*6777b538SAndroid Build Coastguard Worker            UpdateNonNativeModulesMultipleRemovedModulesAtSameAddress) {
272*6777b538SAndroid Build Coastguard Worker   int destroyed_count = 0;
273*6777b538SAndroid Build Coastguard Worker   const auto record_destroyed = [&destroyed_count]() { ++destroyed_count; };
274*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
275*6777b538SAndroid Build Coastguard Worker 
276*6777b538SAndroid Build Coastguard Worker   // Checks that non-native modules can be repeatedly added and removed at the
277*6777b538SAndroid Build Coastguard Worker   // same addresses, and that all are retained in the cache.
278*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules1;
279*6777b538SAndroid Build Coastguard Worker   modules1.push_back(std::make_unique<FakeModule>(
280*6777b538SAndroid Build Coastguard Worker       1, 1, false, BindLambdaForTesting(record_destroyed)));
281*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module1 = modules1.back().get();
282*6777b538SAndroid Build Coastguard Worker 
283*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> modules2;
284*6777b538SAndroid Build Coastguard Worker   modules2.push_back(std::make_unique<FakeModule>(
285*6777b538SAndroid Build Coastguard Worker       1, 1, false, BindLambdaForTesting(record_destroyed)));
286*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module2 = modules2.back().get();
287*6777b538SAndroid Build Coastguard Worker 
288*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({}, std::move(modules1));
289*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({module1}, std::move(modules2));
290*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({module2}, {});
291*6777b538SAndroid Build Coastguard Worker 
292*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0, destroyed_count);
293*6777b538SAndroid Build Coastguard Worker }
294*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,UpdateNonNativeModulesCorrectModulesRemoved)295*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, UpdateNonNativeModulesCorrectModulesRemoved) {
296*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
297*6777b538SAndroid Build Coastguard Worker 
298*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<const ModuleCache::Module>> to_add;
299*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < 5; ++i) {
300*6777b538SAndroid Build Coastguard Worker     to_add.push_back(std::make_unique<FakeModule>(i + 1, 1, false));
301*6777b538SAndroid Build Coastguard Worker   }
302*6777b538SAndroid Build Coastguard Worker 
303*6777b538SAndroid Build Coastguard Worker   std::vector<const ModuleCache::Module*> to_remove = {to_add[1].get(),
304*6777b538SAndroid Build Coastguard Worker                                                        to_add[3].get()};
305*6777b538SAndroid Build Coastguard Worker 
306*6777b538SAndroid Build Coastguard Worker   // Checks that the correct modules are removed when removing some but not all
307*6777b538SAndroid Build Coastguard Worker   // modules.
308*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({}, std::move(to_add));
309*6777b538SAndroid Build Coastguard Worker   cache.UpdateNonNativeModules({to_remove}, {});
310*6777b538SAndroid Build Coastguard Worker 
311*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(nullptr, cache.GetModuleForAddress(1));
312*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(nullptr, cache.GetModuleForAddress(2));
313*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(nullptr, cache.GetModuleForAddress(3));
314*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(nullptr, cache.GetModuleForAddress(4));
315*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(nullptr, cache.GetModuleForAddress(5));
316*6777b538SAndroid Build Coastguard Worker }
317*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,ModulesList)318*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, ModulesList) {
319*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
320*6777b538SAndroid Build Coastguard Worker   uintptr_t ptr = reinterpret_cast<uintptr_t>(&AFunctionForTest);
321*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* native_module = cache.GetModuleForAddress(ptr);
322*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* non_native_module =
323*6777b538SAndroid Build Coastguard Worker       AddNonNativeModule(&cache, std::make_unique<FakeModule>(1, 2, false));
324*6777b538SAndroid Build Coastguard Worker 
325*6777b538SAndroid Build Coastguard Worker   EXPECT_NE(nullptr, native_module);
326*6777b538SAndroid Build Coastguard Worker   std::vector<const ModuleCache::Module*> modules = cache.GetModules();
327*6777b538SAndroid Build Coastguard Worker   ASSERT_EQ(2u, modules.size());
328*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(native_module, modules[0]);
329*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(non_native_module, modules[1]);
330*6777b538SAndroid Build Coastguard Worker }
331*6777b538SAndroid Build Coastguard Worker 
MAYBE_TEST(ModuleCacheTest,InvalidModule)332*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, InvalidModule) {
333*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
334*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(1));
335*6777b538SAndroid Build Coastguard Worker }
336*6777b538SAndroid Build Coastguard Worker 
337*6777b538SAndroid Build Coastguard Worker // arm64 module support is not implemented.
338*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
339*6777b538SAndroid Build Coastguard Worker     (BUILDFLAG(IS_ANDROID) && !defined(ARCH_CPU_ARM64))
340*6777b538SAndroid Build Coastguard Worker // Validates that, for the memory regions listed in /proc/self/maps, the modules
341*6777b538SAndroid Build Coastguard Worker // found via ModuleCache are consistent with those regions' extents.
TEST(ModuleCacheTest,CheckAgainstProcMaps)342*6777b538SAndroid Build Coastguard Worker TEST(ModuleCacheTest, CheckAgainstProcMaps) {
343*6777b538SAndroid Build Coastguard Worker   std::string proc_maps;
344*6777b538SAndroid Build Coastguard Worker   debug::ReadProcMaps(&proc_maps);
345*6777b538SAndroid Build Coastguard Worker   std::vector<debug::MappedMemoryRegion> regions;
346*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(debug::ParseProcMaps(proc_maps, &regions));
347*6777b538SAndroid Build Coastguard Worker 
348*6777b538SAndroid Build Coastguard Worker   // Map distinct paths to lists of regions for the path in increasing memory
349*6777b538SAndroid Build Coastguard Worker   // order.
350*6777b538SAndroid Build Coastguard Worker   using RegionVector = std::vector<const debug::MappedMemoryRegion*>;
351*6777b538SAndroid Build Coastguard Worker   using PathRegionsMap = std::map<std::string_view, RegionVector>;
352*6777b538SAndroid Build Coastguard Worker   PathRegionsMap path_regions;
353*6777b538SAndroid Build Coastguard Worker   for (const debug::MappedMemoryRegion& region : regions)
354*6777b538SAndroid Build Coastguard Worker     path_regions[region.path].push_back(&region);
355*6777b538SAndroid Build Coastguard Worker 
356*6777b538SAndroid Build Coastguard Worker   const auto find_last_executable_region = [](const RegionVector& regions) {
357*6777b538SAndroid Build Coastguard Worker     const auto rloc = base::ranges::find_if(
358*6777b538SAndroid Build Coastguard Worker         base::Reversed(regions), [](const debug::MappedMemoryRegion* region) {
359*6777b538SAndroid Build Coastguard Worker           return static_cast<bool>(region->permissions &
360*6777b538SAndroid Build Coastguard Worker                                    debug::MappedMemoryRegion::EXECUTE);
361*6777b538SAndroid Build Coastguard Worker         });
362*6777b538SAndroid Build Coastguard Worker     return rloc == regions.rend() ? nullptr : *rloc;
363*6777b538SAndroid Build Coastguard Worker   };
364*6777b538SAndroid Build Coastguard Worker 
365*6777b538SAndroid Build Coastguard Worker   int module_count = 0;
366*6777b538SAndroid Build Coastguard Worker 
367*6777b538SAndroid Build Coastguard Worker   // Loop through each distinct path.
368*6777b538SAndroid Build Coastguard Worker   for (const auto& path_regions_pair : path_regions) {
369*6777b538SAndroid Build Coastguard Worker     // Regions that aren't associated with absolute paths are unlikely to be
370*6777b538SAndroid Build Coastguard Worker     // part of modules.
371*6777b538SAndroid Build Coastguard Worker     if (path_regions_pair.first.empty() || path_regions_pair.first[0] != '/')
372*6777b538SAndroid Build Coastguard Worker       continue;
373*6777b538SAndroid Build Coastguard Worker 
374*6777b538SAndroid Build Coastguard Worker     const debug::MappedMemoryRegion* const last_executable_region =
375*6777b538SAndroid Build Coastguard Worker         find_last_executable_region(path_regions_pair.second);
376*6777b538SAndroid Build Coastguard Worker     // The region isn't part of a module if no executable regions are associated
377*6777b538SAndroid Build Coastguard Worker     // with the same path.
378*6777b538SAndroid Build Coastguard Worker     if (!last_executable_region)
379*6777b538SAndroid Build Coastguard Worker       continue;
380*6777b538SAndroid Build Coastguard Worker 
381*6777b538SAndroid Build Coastguard Worker     // Loop through all the regions associated with the path, checking that
382*6777b538SAndroid Build Coastguard Worker     // modules created for addresses in each region have the expected extents.
383*6777b538SAndroid Build Coastguard Worker     const uintptr_t expected_base_address =
384*6777b538SAndroid Build Coastguard Worker         path_regions_pair.second.front()->start;
385*6777b538SAndroid Build Coastguard Worker     for (const auto* region : path_regions_pair.second) {
386*6777b538SAndroid Build Coastguard Worker       ModuleCache cache;
387*6777b538SAndroid Build Coastguard Worker       const ModuleCache::Module* module =
388*6777b538SAndroid Build Coastguard Worker           cache.GetModuleForAddress(region->start);
389*6777b538SAndroid Build Coastguard Worker       // Not all regions matching the prior conditions are necessarily modules;
390*6777b538SAndroid Build Coastguard Worker       // things like resources are also mmapped into memory from files. Ignore
391*6777b538SAndroid Build Coastguard Worker       // any region isn't part of a module.
392*6777b538SAndroid Build Coastguard Worker       if (!module)
393*6777b538SAndroid Build Coastguard Worker         continue;
394*6777b538SAndroid Build Coastguard Worker 
395*6777b538SAndroid Build Coastguard Worker       ++module_count;
396*6777b538SAndroid Build Coastguard Worker 
397*6777b538SAndroid Build Coastguard Worker       EXPECT_EQ(expected_base_address, module->GetBaseAddress());
398*6777b538SAndroid Build Coastguard Worker       // This needs an inequality comparison because the module size is computed
399*6777b538SAndroid Build Coastguard Worker       // based on the ELF section's actual extent, while the |proc_maps| region
400*6777b538SAndroid Build Coastguard Worker       // is aligned to a larger boundary.
401*6777b538SAndroid Build Coastguard Worker       EXPECT_LE(module->GetSize(),
402*6777b538SAndroid Build Coastguard Worker                 last_executable_region->end - expected_base_address)
403*6777b538SAndroid Build Coastguard Worker           << "base address: " << std::hex << module->GetBaseAddress()
404*6777b538SAndroid Build Coastguard Worker           << std::endl
405*6777b538SAndroid Build Coastguard Worker           << "region start: " << std::hex << region->start << std::endl
406*6777b538SAndroid Build Coastguard Worker           << "region end: " << std::hex << region->end << std::endl;
407*6777b538SAndroid Build Coastguard Worker     }
408*6777b538SAndroid Build Coastguard Worker   }
409*6777b538SAndroid Build Coastguard Worker 
410*6777b538SAndroid Build Coastguard Worker   // Linux should have at least this module and ld-linux.so. Android should have
411*6777b538SAndroid Build Coastguard Worker   // at least this module and system libraries.
412*6777b538SAndroid Build Coastguard Worker   EXPECT_GE(module_count, 2);
413*6777b538SAndroid Build Coastguard Worker }
414*6777b538SAndroid Build Coastguard Worker #endif
415*6777b538SAndroid Build Coastguard Worker 
416*6777b538SAndroid Build Coastguard Worker // Module provider that always return a fake module of size 1 for a given
417*6777b538SAndroid Build Coastguard Worker // |address|.
418*6777b538SAndroid Build Coastguard Worker class MockModuleProvider : public ModuleCache::AuxiliaryModuleProvider {
419*6777b538SAndroid Build Coastguard Worker  public:
MockModuleProvider(size_t module_size=1)420*6777b538SAndroid Build Coastguard Worker   explicit MockModuleProvider(size_t module_size = 1)
421*6777b538SAndroid Build Coastguard Worker       : module_size_(module_size) {}
422*6777b538SAndroid Build Coastguard Worker 
TryCreateModuleForAddress(uintptr_t address)423*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<const ModuleCache::Module> TryCreateModuleForAddress(
424*6777b538SAndroid Build Coastguard Worker       uintptr_t address) override {
425*6777b538SAndroid Build Coastguard Worker     return std::make_unique<FakeModule>(address, module_size_);
426*6777b538SAndroid Build Coastguard Worker   }
427*6777b538SAndroid Build Coastguard Worker 
428*6777b538SAndroid Build Coastguard Worker  private:
429*6777b538SAndroid Build Coastguard Worker   size_t module_size_;
430*6777b538SAndroid Build Coastguard Worker };
431*6777b538SAndroid Build Coastguard Worker 
432*6777b538SAndroid Build Coastguard Worker // Check that auxiliary provider can inject new modules when registered.
TEST(ModuleCacheTest,RegisterAuxiliaryModuleProvider)433*6777b538SAndroid Build Coastguard Worker TEST(ModuleCacheTest, RegisterAuxiliaryModuleProvider) {
434*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
435*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(1));
436*6777b538SAndroid Build Coastguard Worker 
437*6777b538SAndroid Build Coastguard Worker   MockModuleProvider auxiliary_provider;
438*6777b538SAndroid Build Coastguard Worker   cache.RegisterAuxiliaryModuleProvider(&auxiliary_provider);
439*6777b538SAndroid Build Coastguard Worker   auto* module = cache.GetModuleForAddress(1);
440*6777b538SAndroid Build Coastguard Worker   EXPECT_NE(nullptr, module);
441*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1U, module->GetBaseAddress());
442*6777b538SAndroid Build Coastguard Worker   cache.UnregisterAuxiliaryModuleProvider(&auxiliary_provider);
443*6777b538SAndroid Build Coastguard Worker 
444*6777b538SAndroid Build Coastguard Worker   // Even when unregistered, the module remains in the cache.
445*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(module, cache.GetModuleForAddress(1));
446*6777b538SAndroid Build Coastguard Worker }
447*6777b538SAndroid Build Coastguard Worker 
448*6777b538SAndroid Build Coastguard Worker // Check that ModuleCache's own module creator is used preferentially over
449*6777b538SAndroid Build Coastguard Worker // auxiliary provider if possible.
MAYBE_TEST(ModuleCacheTest,NativeModuleOverAuxiliaryModuleProvider)450*6777b538SAndroid Build Coastguard Worker MAYBE_TEST(ModuleCacheTest, NativeModuleOverAuxiliaryModuleProvider) {
451*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
452*6777b538SAndroid Build Coastguard Worker 
453*6777b538SAndroid Build Coastguard Worker   MockModuleProvider auxiliary_provider(/*module_size=*/100);
454*6777b538SAndroid Build Coastguard Worker   cache.RegisterAuxiliaryModuleProvider(&auxiliary_provider);
455*6777b538SAndroid Build Coastguard Worker 
456*6777b538SAndroid Build Coastguard Worker   const ModuleCache::Module* module =
457*6777b538SAndroid Build Coastguard Worker       cache.GetModuleForAddress(reinterpret_cast<uintptr_t>(&AFunctionForTest));
458*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, module);
459*6777b538SAndroid Build Coastguard Worker 
460*6777b538SAndroid Build Coastguard Worker   // The module should be a native module, which will have size greater than 100
461*6777b538SAndroid Build Coastguard Worker   // bytes.
462*6777b538SAndroid Build Coastguard Worker   EXPECT_NE(100u, module->GetSize());
463*6777b538SAndroid Build Coastguard Worker   cache.UnregisterAuxiliaryModuleProvider(&auxiliary_provider);
464*6777b538SAndroid Build Coastguard Worker }
465*6777b538SAndroid Build Coastguard Worker 
466*6777b538SAndroid Build Coastguard Worker // Check that auxiliary provider is no longer used after being unregistered.
TEST(ModuleCacheTest,UnregisterAuxiliaryModuleProvider)467*6777b538SAndroid Build Coastguard Worker TEST(ModuleCacheTest, UnregisterAuxiliaryModuleProvider) {
468*6777b538SAndroid Build Coastguard Worker   ModuleCache cache;
469*6777b538SAndroid Build Coastguard Worker 
470*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(1));
471*6777b538SAndroid Build Coastguard Worker 
472*6777b538SAndroid Build Coastguard Worker   MockModuleProvider auxiliary_provider;
473*6777b538SAndroid Build Coastguard Worker   cache.RegisterAuxiliaryModuleProvider(&auxiliary_provider);
474*6777b538SAndroid Build Coastguard Worker   cache.UnregisterAuxiliaryModuleProvider(&auxiliary_provider);
475*6777b538SAndroid Build Coastguard Worker 
476*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(nullptr, cache.GetModuleForAddress(1));
477*6777b538SAndroid Build Coastguard Worker }
478*6777b538SAndroid Build Coastguard Worker 
479*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
TEST(ModuleCacheTest,TransformELFToSymbolServerFormat)480*6777b538SAndroid Build Coastguard Worker TEST(ModuleCacheTest, TransformELFToSymbolServerFormat) {
481*6777b538SAndroid Build Coastguard Worker   // See explanation for the module_id mangling in
482*6777b538SAndroid Build Coastguard Worker   // base::TransformModuleIDToSymbolServerFormat implementation.
483*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(TransformModuleIDToSymbolServerFormat(
484*6777b538SAndroid Build Coastguard Worker                 "7F0715C286F8B16C10E4AD349CDA3B9B56C7A773"),
485*6777b538SAndroid Build Coastguard Worker             "C215077FF8866CB110E4AD349CDA3B9B0");
486*6777b538SAndroid Build Coastguard Worker }
487*6777b538SAndroid Build Coastguard Worker #endif
488*6777b538SAndroid Build Coastguard Worker 
489*6777b538SAndroid Build Coastguard Worker }  // namespace
490*6777b538SAndroid Build Coastguard Worker }  // namespace base
491