xref: /llvm-project/lldb/unittests/Target/LocateModuleCallbackTest.cpp (revision 0642cd768b80665585c8500bed2933a3b99123dc)
1 //===-- LocateModuleCallbackTest.cpp --------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
10 #include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
11 #include "Plugins/Platform/Android/PlatformAndroid.h"
12 #include "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"
13 #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
14 #include "TestingSupport/SubsystemRAII.h"
15 #include "TestingSupport/TestUtilities.h"
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Host/HostInfo.h"
19 #include "lldb/Target/Target.h"
20 #include "gmock/gmock.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 using namespace lldb_private::platform_android;
25 using namespace lldb_private::platform_linux;
26 using namespace lldb_private::breakpad;
27 using namespace testing;
28 
29 namespace {
30 
31 constexpr llvm::StringLiteral k_process_plugin("mock-process-plugin");
32 constexpr llvm::StringLiteral k_platform_dir("remote-android");
33 constexpr llvm::StringLiteral k_cache_dir(".cache");
34 constexpr llvm::StringLiteral k_module_file("AndroidModule.so");
35 constexpr llvm::StringLiteral k_symbol_file("AndroidModule.unstripped.so");
36 constexpr llvm::StringLiteral k_breakpad_symbol_file("AndroidModule.so.sym");
37 constexpr llvm::StringLiteral k_arch("aarch64-none-linux");
38 constexpr llvm::StringLiteral
39     k_module_uuid("80008338-82A0-51E5-5922-C905D23890DA-BDDEFECC");
40 constexpr llvm::StringLiteral k_function_symbol("boom");
41 constexpr llvm::StringLiteral k_hidden_function_symbol("boom_hidden");
42 const size_t k_module_size = 3784;
43 
44 ModuleSpec GetTestModuleSpec();
45 
46 class MockProcess : public Process {
47 public:
48   MockProcess(TargetSP target_sp, ListenerSP listener_sp)
49       : Process(target_sp, listener_sp) {}
50 
51   llvm::StringRef GetPluginName() override { return k_process_plugin; };
52 
53   bool CanDebug(TargetSP target, bool plugin_specified_by_name) override {
54     return true;
55   }
56 
57   Status DoDestroy() override { return Status(); }
58 
59   void RefreshStateAfterStop() override {}
60 
61   bool DoUpdateThreadList(ThreadList &old_thread_list,
62                           ThreadList &new_thread_list) override {
63     return false;
64   }
65 
66   size_t DoReadMemory(addr_t vm_addr, void *buf, size_t size,
67                       Status &error) override {
68     return 0;
69   }
70 
71   bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
72                      ModuleSpec &module_spec) override {
73     module_spec = GetTestModuleSpec();
74     return true;
75   }
76 };
77 
78 FileSpec GetTestDir() {
79   const auto *info = UnitTest::GetInstance()->current_test_info();
80   FileSpec test_dir = HostInfo::GetProcessTempDir();
81   test_dir.AppendPathComponent(std::string(info->test_case_name()) + "-" +
82                                info->name());
83   std::error_code ec = llvm::sys::fs::create_directory(test_dir.GetPath());
84   EXPECT_FALSE(ec);
85   return test_dir;
86 }
87 
88 FileSpec GetRemotePath() {
89   FileSpec fs("/", FileSpec::Style::posix);
90   fs.AppendPathComponent("bin");
91   fs.AppendPathComponent(k_module_file);
92   return fs;
93 }
94 
95 FileSpec GetUuidView(FileSpec spec) {
96   spec.AppendPathComponent(k_platform_dir);
97   spec.AppendPathComponent(k_cache_dir);
98   spec.AppendPathComponent(k_module_uuid);
99   spec.AppendPathComponent(k_module_file);
100   return spec;
101 }
102 
103 void BuildEmptyCacheDir(const FileSpec &test_dir) {
104   FileSpec cache_dir(test_dir);
105   cache_dir.AppendPathComponent(k_platform_dir);
106   cache_dir.AppendPathComponent(k_cache_dir);
107   std::error_code ec = llvm::sys::fs::create_directories(cache_dir.GetPath());
108   EXPECT_FALSE(ec);
109 }
110 
111 FileSpec BuildCacheDir(const FileSpec &test_dir) {
112   FileSpec uuid_view = GetUuidView(test_dir);
113   std::error_code ec =
114       llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString());
115   EXPECT_FALSE(ec);
116   ec = llvm::sys::fs::copy_file(GetInputFilePath(k_module_file),
117                                 uuid_view.GetPath().c_str());
118   EXPECT_FALSE(ec);
119   return uuid_view;
120 }
121 
122 FileSpec GetSymFileSpec(const FileSpec &uuid_view) {
123   return FileSpec(uuid_view.GetPath() + ".sym");
124 }
125 
126 FileSpec BuildCacheDirWithSymbol(const FileSpec &test_dir) {
127   FileSpec uuid_view = BuildCacheDir(test_dir);
128   std::error_code ec =
129       llvm::sys::fs::copy_file(GetInputFilePath(k_symbol_file),
130                                GetSymFileSpec(uuid_view).GetPath().c_str());
131   EXPECT_FALSE(ec);
132   return uuid_view;
133 }
134 
135 FileSpec BuildCacheDirWithBreakpadSymbol(const FileSpec &test_dir) {
136   FileSpec uuid_view = BuildCacheDir(test_dir);
137   std::error_code ec =
138       llvm::sys::fs::copy_file(GetInputFilePath(k_breakpad_symbol_file),
139                                GetSymFileSpec(uuid_view).GetPath().c_str());
140   EXPECT_FALSE(ec);
141   return uuid_view;
142 }
143 
144 ModuleSpec GetTestModuleSpec() {
145   ModuleSpec module_spec(GetRemotePath(), ArchSpec(k_arch));
146   module_spec.GetUUID().SetFromStringRef(k_module_uuid);
147   module_spec.SetObjectSize(k_module_size);
148   return module_spec;
149 }
150 
151 void CheckModule(const ModuleSP &module_sp) {
152   ASSERT_TRUE(module_sp);
153   ASSERT_EQ(module_sp->GetUUID().GetAsString(), k_module_uuid);
154   ASSERT_EQ(module_sp->GetObjectOffset(), 0U);
155   ASSERT_EQ(module_sp->GetPlatformFileSpec(), GetRemotePath());
156 }
157 
158 SymbolContextList FindFunctions(const ModuleSP &module_sp,
159                                 const llvm::StringRef &name) {
160   SymbolContextList sc_list;
161   ModuleFunctionSearchOptions function_options;
162   function_options.include_symbols = true;
163   function_options.include_inlines = true;
164   FunctionNameType type = static_cast<FunctionNameType>(eSymbolTypeCode);
165   module_sp->FindFunctions(ConstString(name), CompilerDeclContext(), type,
166                            function_options, sc_list);
167   return sc_list;
168 }
169 
170 void CheckStrippedSymbol(const ModuleSP &module_sp) {
171   SymbolContextList sc_list = FindFunctions(module_sp, k_function_symbol);
172   EXPECT_EQ(1U, sc_list.GetSize());
173 
174   sc_list = FindFunctions(module_sp, k_hidden_function_symbol);
175   EXPECT_EQ(0U, sc_list.GetSize());
176 }
177 
178 void CheckUnstrippedSymbol(const ModuleSP &module_sp) {
179   SymbolContextList sc_list = FindFunctions(module_sp, k_function_symbol);
180   EXPECT_EQ(1U, sc_list.GetSize());
181 
182   sc_list = FindFunctions(module_sp, k_hidden_function_symbol);
183   EXPECT_EQ(1U, sc_list.GetSize());
184 }
185 
186 ProcessSP MockProcessCreateInstance(TargetSP target_sp, ListenerSP listener_sp,
187                                     const FileSpec *crash_file_path,
188                                     bool can_connect) {
189   return std::make_shared<MockProcess>(target_sp, listener_sp);
190 }
191 
192 class LocateModuleCallbackTest : public testing::Test {
193   SubsystemRAII<FileSystem, HostInfo, ObjectFileBreakpad, ObjectFileELF,
194                 PlatformAndroid, PlatformLinux, SymbolFileBreakpad,
195                 SymbolFileSymtab>
196       subsystems;
197 
198 public:
199   void SetUp() override {
200     m_test_dir = GetTestDir();
201 
202     // Set module cache directory for PlatformAndroid.
203     PlatformAndroid::GetGlobalPlatformProperties().SetModuleCacheDirectory(
204         m_test_dir);
205 
206     // Create Debugger.
207     ArchSpec host_arch("i386-pc-linux");
208     Platform::SetHostPlatform(
209         platform_linux::PlatformLinux::CreateInstance(true, &host_arch));
210     m_debugger_sp = Debugger::CreateInstance();
211     EXPECT_TRUE(m_debugger_sp);
212 
213     // Create PlatformAndroid.
214     ArchSpec arch(k_arch);
215     m_platform_sp = PlatformAndroid::CreateInstance(true, &arch);
216     EXPECT_TRUE(m_platform_sp);
217 
218     // Create Target.
219     m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
220                                                 eLoadDependentsNo,
221                                                 m_platform_sp, m_target_sp);
222     EXPECT_TRUE(m_target_sp);
223 
224     // Create MockProcess.
225     PluginManager::RegisterPlugin(k_process_plugin, "",
226                                   MockProcessCreateInstance);
227     m_process_sp =
228         m_target_sp->CreateProcess(Listener::MakeListener("test-listener"),
229                                    k_process_plugin, /*crash_file=*/nullptr,
230                                    /*can_connect=*/true);
231     EXPECT_TRUE(m_process_sp);
232 
233     m_module_spec = GetTestModuleSpec();
234     m_module_spec_without_uuid = ModuleSpec(GetRemotePath(), ArchSpec(k_arch));
235   }
236 
237   void TearDown() override {
238     if (m_module_sp)
239       ModuleList::RemoveSharedModule(m_module_sp);
240   }
241 
242   void CheckNoCallback() {
243     EXPECT_FALSE(m_platform_sp->GetLocateModuleCallback());
244     EXPECT_EQ(m_callback_call_count, 0);
245   }
246 
247   void CheckCallbackArgs(const ModuleSpec &module_spec,
248                          FileSpec &module_file_spec, FileSpec &symbol_file_spec,
249                          const ModuleSpec &expected_module_spec,
250                          int expected_callback_call_count) {
251     EXPECT_TRUE(expected_module_spec.Matches(module_spec,
252                                              /*exact_arch_match=*/true));
253     EXPECT_FALSE(module_file_spec);
254     EXPECT_FALSE(symbol_file_spec);
255 
256     EXPECT_EQ(++m_callback_call_count, expected_callback_call_count);
257   }
258 
259   void CheckCallbackArgsWithUUID(const ModuleSpec &module_spec,
260                                  FileSpec &module_file_spec,
261                                  FileSpec &symbol_file_spec,
262                                  int expected_callback_call_count) {
263     CheckCallbackArgs(module_spec, module_file_spec, symbol_file_spec,
264                       m_module_spec, expected_callback_call_count);
265     EXPECT_TRUE(module_spec.GetUUID().IsValid());
266   }
267 
268   void CheckCallbackArgsWithoutUUID(const ModuleSpec &module_spec,
269                                     FileSpec &module_file_spec,
270                                     FileSpec &symbol_file_spec,
271                                     int expected_callback_call_count) {
272     CheckCallbackArgs(module_spec, module_file_spec, symbol_file_spec,
273                       m_module_spec_without_uuid, expected_callback_call_count);
274     EXPECT_FALSE(module_spec.GetUUID().IsValid());
275   }
276 
277 protected:
278   FileSpec m_test_dir;
279   DebuggerSP m_debugger_sp;
280   PlatformSP m_platform_sp;
281   TargetSP m_target_sp;
282   ProcessSP m_process_sp;
283   ModuleSpec m_module_spec;
284   ModuleSpec m_module_spec_without_uuid;
285   ModuleSP m_module_sp;
286   int m_callback_call_count = 0;
287 };
288 
289 } // namespace
290 
291 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleWithCachedModule) {
292   // The module file is cached, and the locate module callback is not set.
293   // GetOrCreateModule should succeed to return the module from the cache.
294   FileSpec uuid_view = BuildCacheDir(m_test_dir);
295 
296   CheckNoCallback();
297 
298   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
299   CheckModule(m_module_sp);
300   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
301   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
302   CheckStrippedSymbol(m_module_sp);
303 }
304 
305 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleWithCachedModuleAndSymbol) {
306   // The module and symbol files are cached, and the locate module callback is
307   // not set. GetOrCreateModule should succeed to return the module from the
308   // cache with the symbol.
309   FileSpec uuid_view = BuildCacheDirWithSymbol(m_test_dir);
310 
311   CheckNoCallback();
312 
313   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
314   CheckModule(m_module_sp);
315   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
316   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(), GetSymFileSpec(uuid_view));
317   CheckUnstrippedSymbol(m_module_sp);
318 }
319 
320 TEST_F(LocateModuleCallbackTest,
321        GetOrCreateModuleWithCachedModuleAndBreakpadSymbol) {
322   // The module file and breakpad symbol file are cached, and the locate module
323   // callback is not set. GetOrCreateModule should succeed to return the module
324   // from the cache with the symbol.
325   FileSpec uuid_view = BuildCacheDirWithBreakpadSymbol(m_test_dir);
326 
327   CheckNoCallback();
328 
329   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
330   CheckModule(m_module_sp);
331   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
332   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(), GetSymFileSpec(uuid_view));
333   CheckUnstrippedSymbol(m_module_sp);
334 }
335 
336 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleFailure) {
337   // The cache dir is empty, and the locate module callback is not set.
338   // GetOrCreateModule should fail because PlatformAndroid tries to download the
339   // module and fails.
340   BuildEmptyCacheDir(m_test_dir);
341 
342   CheckNoCallback();
343 
344   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
345   ASSERT_FALSE(m_module_sp);
346 }
347 
348 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleCallbackFailureNoCache) {
349   // The cache dir is empty, also the locate module callback fails for some
350   // reason. GetOrCreateModule should fail because PlatformAndroid tries to
351   // download the module and fails.
352   BuildEmptyCacheDir(m_test_dir);
353 
354   int callback_call_count = 0;
355   m_platform_sp->SetLocateModuleCallback(
356       [this, &callback_call_count](const ModuleSpec &module_spec,
357                                    FileSpec &module_file_spec,
358                                    FileSpec &symbol_file_spec) {
359         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
360                                   symbol_file_spec, ++callback_call_count);
361         return Status::FromErrorString("The locate module callback failed");
362       });
363 
364   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
365   ASSERT_EQ(callback_call_count, 2);
366   ASSERT_FALSE(m_module_sp);
367 }
368 
369 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleCallbackFailureCached) {
370   // The module file is cached, so GetOrCreateModule should succeed to return
371   // the module from the cache even though the locate module callback fails for
372   // some reason.
373   FileSpec uuid_view = BuildCacheDir(m_test_dir);
374 
375   int callback_call_count = 0;
376   m_platform_sp->SetLocateModuleCallback(
377       [this, &callback_call_count](const ModuleSpec &module_spec,
378                                    FileSpec &module_file_spec,
379                                    FileSpec &symbol_file_spec) {
380         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
381                                   symbol_file_spec, ++callback_call_count);
382         return Status::FromErrorString("The locate module callback failed");
383       });
384 
385   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
386   ASSERT_EQ(callback_call_count, 2);
387   CheckModule(m_module_sp);
388   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
389   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
390   CheckStrippedSymbol(m_module_sp);
391 }
392 
393 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleCallbackNoFiles) {
394   // The module file is cached, so GetOrCreateModule should succeed to return
395   // the module from the cache even though the locate module callback returns
396   // no files.
397   FileSpec uuid_view = BuildCacheDir(m_test_dir);
398 
399   int callback_call_count = 0;
400   m_platform_sp->SetLocateModuleCallback(
401       [this, &callback_call_count](const ModuleSpec &module_spec,
402                                    FileSpec &module_file_spec,
403                                    FileSpec &symbol_file_spec) {
404         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
405                                   symbol_file_spec, ++callback_call_count);
406         // The locate module callback succeeds but it does not set
407         // module_file_spec nor symbol_file_spec.
408         return Status();
409       });
410 
411   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
412   ASSERT_EQ(callback_call_count, 2);
413   CheckModule(m_module_sp);
414   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
415   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
416   CheckStrippedSymbol(m_module_sp);
417   ModuleList::RemoveSharedModule(m_module_sp);
418 }
419 
420 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleCallbackNonExistentModule) {
421   // The module file is cached, so GetOrCreateModule should succeed to return
422   // the module from the cache even though the locate module callback returns
423   // non-existent module file.
424   FileSpec uuid_view = BuildCacheDir(m_test_dir);
425 
426   int callback_call_count = 0;
427   m_platform_sp->SetLocateModuleCallback(
428       [this, &callback_call_count](const ModuleSpec &module_spec,
429                                    FileSpec &module_file_spec,
430                                    FileSpec &symbol_file_spec) {
431         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
432                                   symbol_file_spec, ++callback_call_count);
433         module_file_spec.SetPath("/this path does not exist");
434         return Status();
435       });
436 
437   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
438   ASSERT_EQ(callback_call_count, 2);
439   CheckModule(m_module_sp);
440   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
441   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
442   CheckStrippedSymbol(m_module_sp);
443   ModuleList::RemoveSharedModule(m_module_sp);
444 }
445 
446 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleCallbackNonExistentSymbol) {
447   // The module file is cached, so GetOrCreateModule should succeed to return
448   // the module from the cache even though the locate module callback returns
449   // non-existent symbol file.
450   FileSpec uuid_view = BuildCacheDir(m_test_dir);
451 
452   int callback_call_count = 0;
453   m_platform_sp->SetLocateModuleCallback(
454       [this, &callback_call_count](const ModuleSpec &module_spec,
455                                    FileSpec &module_file_spec,
456                                    FileSpec &symbol_file_spec) {
457         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
458                                   symbol_file_spec, ++callback_call_count);
459         // The locate module callback returns a right module file.
460         module_file_spec.SetPath(GetInputFilePath(k_module_file));
461         // But it returns non-existent symbols file.
462         symbol_file_spec.SetPath("/this path does not exist");
463         return Status();
464       });
465 
466   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
467   ASSERT_EQ(callback_call_count, 2);
468   CheckModule(m_module_sp);
469   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
470   ASSERT_TRUE(m_module_sp->GetSymbolFileFileSpec().GetPath().empty());
471   CheckStrippedSymbol(m_module_sp);
472   ModuleList::RemoveSharedModule(m_module_sp);
473 }
474 
475 TEST_F(LocateModuleCallbackTest, GetOrCreateModuleCallbackSuccessWithModule) {
476   // The locate module callback returns a module file, GetOrCreateModule should
477   // succeed to return the module from the Inputs directory.
478   BuildEmptyCacheDir(m_test_dir);
479 
480   m_platform_sp->SetLocateModuleCallback([this](const ModuleSpec &module_spec,
481                                                 FileSpec &module_file_spec,
482                                                 FileSpec &symbol_file_spec) {
483     CheckCallbackArgsWithUUID(module_spec, module_file_spec, symbol_file_spec,
484                               1);
485     module_file_spec.SetPath(GetInputFilePath(k_module_file));
486     return Status();
487   });
488 
489   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
490   CheckModule(m_module_sp);
491   ASSERT_EQ(m_module_sp->GetFileSpec(),
492             FileSpec(GetInputFilePath(k_module_file)));
493   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
494   CheckStrippedSymbol(m_module_sp);
495   ModuleList::RemoveSharedModule(m_module_sp);
496 }
497 
498 TEST_F(LocateModuleCallbackTest,
499        GetOrCreateModuleCallbackSuccessWithSymbolAsModule) {
500   // The locate module callback returns the symbol file as a module file. It
501   // should work since the sections and UUID of the symbol file are the exact
502   // same with the module file, GetOrCreateModule should succeed to return the
503   // module with the symbol file from Inputs directory.
504   BuildEmptyCacheDir(m_test_dir);
505 
506   m_platform_sp->SetLocateModuleCallback([this](const ModuleSpec &module_spec,
507                                                 FileSpec &module_file_spec,
508                                                 FileSpec &symbol_file_spec) {
509     CheckCallbackArgsWithUUID(module_spec, module_file_spec, symbol_file_spec,
510                               1);
511     module_file_spec.SetPath(GetInputFilePath(k_symbol_file));
512     return Status();
513   });
514 
515   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
516   CheckModule(m_module_sp);
517   ASSERT_EQ(m_module_sp->GetFileSpec(),
518             FileSpec(GetInputFilePath(k_symbol_file)));
519   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
520   CheckUnstrippedSymbol(m_module_sp);
521   ModuleList::RemoveSharedModule(m_module_sp);
522 }
523 
524 TEST_F(LocateModuleCallbackTest,
525        GetOrCreateModuleCallbackSuccessWithSymbolAsModuleAndSymbol) {
526   // The locate module callback returns a symbol file as both a module file and
527   // a symbol file. It should work since the sections and UUID of the symbol
528   // file are the exact same with the module file, GetOrCreateModule should
529   // succeed to return the module with the symbol file from Inputs directory.
530   BuildEmptyCacheDir(m_test_dir);
531 
532   m_platform_sp->SetLocateModuleCallback([this](const ModuleSpec &module_spec,
533                                                 FileSpec &module_file_spec,
534                                                 FileSpec &symbol_file_spec) {
535     CheckCallbackArgsWithUUID(module_spec, module_file_spec, symbol_file_spec,
536                               1);
537     module_file_spec.SetPath(GetInputFilePath(k_symbol_file));
538     symbol_file_spec.SetPath(GetInputFilePath(k_symbol_file));
539     return Status();
540   });
541 
542   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
543   CheckModule(m_module_sp);
544   ASSERT_EQ(m_module_sp->GetFileSpec(),
545             FileSpec(GetInputFilePath(k_symbol_file)));
546   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
547             FileSpec(GetInputFilePath(k_symbol_file)));
548   CheckUnstrippedSymbol(m_module_sp);
549   ModuleList::RemoveSharedModule(m_module_sp);
550 }
551 
552 TEST_F(LocateModuleCallbackTest,
553        GetOrCreateModuleCallbackSuccessWithModuleAndSymbol) {
554   // The locate module callback returns a module file and a symbol file,
555   // GetOrCreateModule should succeed to return the module from Inputs
556   // directory, along with the symbol file.
557   BuildEmptyCacheDir(m_test_dir);
558 
559   m_platform_sp->SetLocateModuleCallback([this](const ModuleSpec &module_spec,
560                                                 FileSpec &module_file_spec,
561                                                 FileSpec &symbol_file_spec) {
562     CheckCallbackArgsWithUUID(module_spec, module_file_spec, symbol_file_spec,
563                               1);
564     module_file_spec.SetPath(GetInputFilePath(k_module_file));
565     symbol_file_spec.SetPath(GetInputFilePath(k_symbol_file));
566     return Status();
567   });
568 
569   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
570   CheckModule(m_module_sp);
571   ASSERT_EQ(m_module_sp->GetFileSpec(),
572             FileSpec(GetInputFilePath(k_module_file)));
573   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
574             FileSpec(GetInputFilePath(k_symbol_file)));
575   CheckUnstrippedSymbol(m_module_sp);
576   ModuleList::RemoveSharedModule(m_module_sp);
577 }
578 
579 TEST_F(LocateModuleCallbackTest,
580        GetOrCreateModuleCallbackSuccessWithModuleAndBreakpadSymbol) {
581   // The locate module callback returns a module file and a breakpad symbol
582   // file, GetOrCreateModule should succeed to return the module with the symbol
583   // file from Inputs directory.
584   BuildEmptyCacheDir(m_test_dir);
585 
586   m_platform_sp->SetLocateModuleCallback([this](const ModuleSpec &module_spec,
587                                                 FileSpec &module_file_spec,
588                                                 FileSpec &symbol_file_spec) {
589     CheckCallbackArgsWithUUID(module_spec, module_file_spec, symbol_file_spec,
590                               1);
591     module_file_spec.SetPath(GetInputFilePath(k_module_file));
592     symbol_file_spec.SetPath(GetInputFilePath(k_breakpad_symbol_file));
593     return Status();
594   });
595 
596   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
597   CheckModule(m_module_sp);
598   ASSERT_EQ(m_module_sp->GetFileSpec(),
599             FileSpec(GetInputFilePath(k_module_file)));
600   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
601             FileSpec(GetInputFilePath(k_breakpad_symbol_file)));
602   CheckUnstrippedSymbol(m_module_sp);
603   ModuleList::RemoveSharedModule(m_module_sp);
604 }
605 
606 TEST_F(LocateModuleCallbackTest,
607        GetOrCreateModuleCallbackSuccessWithOnlySymbol) {
608   // The get callback returns only a symbol file, and the module is cached,
609   // GetOrCreateModule should succeed to return the module from the cache
610   // along with the symbol file from the Inputs directory.
611   FileSpec uuid_view = BuildCacheDir(m_test_dir);
612 
613   int callback_call_count = 0;
614   m_platform_sp->SetLocateModuleCallback(
615       [this, &callback_call_count](const ModuleSpec &module_spec,
616                                    FileSpec &module_file_spec,
617                                    FileSpec &symbol_file_spec) {
618         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
619                                   symbol_file_spec, ++callback_call_count);
620         symbol_file_spec.SetPath(GetInputFilePath(k_symbol_file));
621         return Status();
622       });
623 
624   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
625   ASSERT_EQ(callback_call_count, 2);
626   CheckModule(m_module_sp);
627   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
628   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
629             FileSpec(GetInputFilePath(k_symbol_file)));
630   CheckUnstrippedSymbol(m_module_sp);
631   ModuleList::RemoveSharedModule(m_module_sp);
632 }
633 
634 TEST_F(LocateModuleCallbackTest,
635        GetOrCreateModuleCallbackSuccessWithOnlyBreakpadSymbol) {
636   // The get callback returns only a breakpad symbol file, and the module is
637   // cached, GetOrCreateModule should succeed to return the module from the
638   // cache along with the symbol file from the Inputs directory.
639   FileSpec uuid_view = BuildCacheDir(m_test_dir);
640 
641   int callback_call_count = 0;
642   m_platform_sp->SetLocateModuleCallback(
643       [this, &callback_call_count](const ModuleSpec &module_spec,
644                                    FileSpec &module_file_spec,
645                                    FileSpec &symbol_file_spec) {
646         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
647                                   symbol_file_spec, ++callback_call_count);
648         symbol_file_spec.SetPath(GetInputFilePath(k_breakpad_symbol_file));
649         return Status();
650       });
651 
652   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
653   ASSERT_EQ(callback_call_count, 2);
654   CheckModule(m_module_sp);
655   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
656   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
657             FileSpec(GetInputFilePath(k_breakpad_symbol_file)));
658   CheckUnstrippedSymbol(m_module_sp);
659   ModuleList::RemoveSharedModule(m_module_sp);
660 }
661 
662 TEST_F(LocateModuleCallbackTest,
663        GetOrCreateModuleCallbackSuccessWithMultipleSymbols) {
664   // The get callback returns only a symbol file. The first call returns
665   // a breakpad symbol file and the second call returns a symbol file.
666   // Also the module is cached, so GetOrCreateModule should succeed to return
667   // the module from the cache along with the breakpad symbol file from the
668   // Inputs directory because GetOrCreateModule will use the first symbol file
669   // from the callback.
670   FileSpec uuid_view = BuildCacheDir(m_test_dir);
671 
672   int callback_call_count = 0;
673   m_platform_sp->SetLocateModuleCallback(
674       [this, &callback_call_count](const ModuleSpec &module_spec,
675                                    FileSpec &module_file_spec,
676                                    FileSpec &symbol_file_spec) {
677         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
678                                   symbol_file_spec, ++callback_call_count);
679         symbol_file_spec.SetPath(GetInputFilePath(
680             callback_call_count == 1 ? k_breakpad_symbol_file : k_symbol_file));
681         return Status();
682       });
683 
684   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
685   ASSERT_EQ(callback_call_count, 2);
686   CheckModule(m_module_sp);
687   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
688   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
689             FileSpec(GetInputFilePath(k_breakpad_symbol_file)));
690   CheckUnstrippedSymbol(m_module_sp);
691   ModuleList::RemoveSharedModule(m_module_sp);
692 }
693 
694 TEST_F(LocateModuleCallbackTest,
695        GetOrCreateModuleNoCacheWithCallbackOnlySymbol) {
696   // The get callback returns only a symbol file, but the module is not
697   // cached, GetOrCreateModule should fail because of the missing module.
698   BuildEmptyCacheDir(m_test_dir);
699 
700   int callback_call_count = 0;
701   m_platform_sp->SetLocateModuleCallback(
702       [this, &callback_call_count](const ModuleSpec &module_spec,
703                                    FileSpec &module_file_spec,
704                                    FileSpec &symbol_file_spec) {
705         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
706                                   symbol_file_spec, ++callback_call_count);
707         symbol_file_spec.SetPath(GetInputFilePath(k_symbol_file));
708         return Status();
709       });
710 
711   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
712   ASSERT_EQ(callback_call_count, 2);
713   ASSERT_FALSE(m_module_sp);
714 }
715 
716 TEST_F(LocateModuleCallbackTest,
717        GetOrCreateModuleNoCacheWithCallbackOnlyBreakpadSymbol) {
718   // The get callback returns only a breakpad symbol file, but the module is not
719   // cached, GetOrCreateModule should fail because of the missing module.
720   BuildEmptyCacheDir(m_test_dir);
721 
722   int callback_call_count = 0;
723   m_platform_sp->SetLocateModuleCallback(
724       [this, &callback_call_count](const ModuleSpec &module_spec,
725                                    FileSpec &module_file_spec,
726                                    FileSpec &symbol_file_spec) {
727         CheckCallbackArgsWithUUID(module_spec, module_file_spec,
728                                   symbol_file_spec, ++callback_call_count);
729         symbol_file_spec.SetPath(GetInputFilePath(k_breakpad_symbol_file));
730         return Status();
731       });
732 
733   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec, /*notify=*/false);
734   ASSERT_EQ(callback_call_count, 2);
735   ASSERT_FALSE(m_module_sp);
736 }
737 
738 TEST_F(LocateModuleCallbackTest,
739        GetOrCreateModuleCallbackSuccessWithModuleByPlatformUUID) {
740   // This is a simulation for Android remote platform debugging.
741   // The locate module callback first call fails because module_spec does not
742   // have UUID. Then, the callback second call returns a module file because the
743   // platform resolved the module_spec UUID from the target process.
744   // GetOrCreateModule should succeed to return the module from the Inputs
745   // directory.
746   BuildEmptyCacheDir(m_test_dir);
747 
748   int callback_call_count = 0;
749   m_platform_sp->SetLocateModuleCallback(
750       [this, &callback_call_count](const ModuleSpec &module_spec,
751                                    FileSpec &module_file_spec,
752                                    FileSpec &symbol_file_spec) {
753         callback_call_count++;
754         if (callback_call_count == 1) {
755           // The module_spec does not have UUID on the first call.
756           CheckCallbackArgsWithoutUUID(module_spec, module_file_spec,
757                                        symbol_file_spec, callback_call_count);
758           return Status::FromErrorString("Ignored empty UUID");
759         } else {
760           // The module_spec has UUID on the second call.
761           CheckCallbackArgsWithUUID(module_spec, module_file_spec,
762                                     symbol_file_spec, callback_call_count);
763           module_file_spec.SetPath(GetInputFilePath(k_module_file));
764           return Status();
765         }
766       });
767 
768   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec_without_uuid,
769                                                /*notify=*/false);
770   ASSERT_EQ(callback_call_count, 2);
771   CheckModule(m_module_sp);
772   ASSERT_EQ(m_module_sp->GetFileSpec(),
773             FileSpec(GetInputFilePath(k_module_file)));
774   ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
775   CheckStrippedSymbol(m_module_sp);
776   ModuleList::RemoveSharedModule(m_module_sp);
777 }
778 
779 TEST_F(LocateModuleCallbackTest,
780        GetOrCreateModuleCallbackSuccessWithSymbolByPlatformUUID) {
781   // Same as GetOrCreateModuleCallbackSuccessWithModuleByPlatformUUID,
782   // but with a symbol file. GetOrCreateModule should succeed to return the
783   // module file and the symbol file from the Inputs directory.
784   BuildEmptyCacheDir(m_test_dir);
785 
786   int callback_call_count = 0;
787   m_platform_sp->SetLocateModuleCallback(
788       [this, &callback_call_count](const ModuleSpec &module_spec,
789                                    FileSpec &module_file_spec,
790                                    FileSpec &symbol_file_spec) {
791         callback_call_count++;
792         if (callback_call_count == 1) {
793           // The module_spec does not have UUID on the first call.
794           CheckCallbackArgsWithoutUUID(module_spec, module_file_spec,
795                                        symbol_file_spec, callback_call_count);
796           return Status::FromErrorString("Ignored empty UUID");
797         } else {
798           // The module_spec has UUID on the second call.
799           CheckCallbackArgsWithUUID(module_spec, module_file_spec,
800                                     symbol_file_spec, callback_call_count);
801           module_file_spec.SetPath(GetInputFilePath(k_module_file));
802           symbol_file_spec.SetPath(GetInputFilePath(k_symbol_file));
803           return Status();
804         }
805       });
806 
807   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec_without_uuid,
808                                                /*notify=*/false);
809   ASSERT_EQ(callback_call_count, 2);
810   CheckModule(m_module_sp);
811   ASSERT_EQ(m_module_sp->GetFileSpec(),
812             FileSpec(GetInputFilePath(k_module_file)));
813   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
814             FileSpec(GetInputFilePath(k_symbol_file)));
815   CheckUnstrippedSymbol(m_module_sp);
816   ModuleList::RemoveSharedModule(m_module_sp);
817 }
818 
819 TEST_F(LocateModuleCallbackTest,
820        GetOrCreateModuleCallbackSuccessWithBreakpadSymbolByPlatformUUID) {
821   // Same as GetOrCreateModuleCallbackSuccessWithModuleByPlatformUUID,
822   // but with a breakpad symbol file. GetOrCreateModule should succeed to return
823   // the module file and the symbol file from the Inputs directory.
824   BuildEmptyCacheDir(m_test_dir);
825 
826   int callback_call_count = 0;
827   m_platform_sp->SetLocateModuleCallback(
828       [this, &callback_call_count](const ModuleSpec &module_spec,
829                                    FileSpec &module_file_spec,
830                                    FileSpec &symbol_file_spec) {
831         callback_call_count++;
832         if (callback_call_count == 1) {
833           // The module_spec does not have UUID on the first call.
834           CheckCallbackArgsWithoutUUID(module_spec, module_file_spec,
835                                        symbol_file_spec, callback_call_count);
836           return Status::FromErrorString("Ignored empty UUID");
837         } else {
838           // The module_spec has UUID on the second call.
839           CheckCallbackArgsWithUUID(module_spec, module_file_spec,
840                                     symbol_file_spec, callback_call_count);
841           module_file_spec.SetPath(GetInputFilePath(k_module_file));
842           symbol_file_spec.SetPath(GetInputFilePath(k_breakpad_symbol_file));
843           return Status();
844         }
845       });
846 
847   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec_without_uuid,
848                                                /*notify=*/false);
849   ASSERT_EQ(callback_call_count, 2);
850   CheckModule(m_module_sp);
851   ASSERT_EQ(m_module_sp->GetFileSpec(),
852             FileSpec(GetInputFilePath(k_module_file)));
853   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
854             FileSpec(GetInputFilePath(k_breakpad_symbol_file)));
855   CheckUnstrippedSymbol(m_module_sp);
856   ModuleList::RemoveSharedModule(m_module_sp);
857 }
858 
859 TEST_F(LocateModuleCallbackTest,
860        GetOrCreateModuleCallbackSuccessWithOnlyBreakpadSymbolByPlatformUUID) {
861   // This is a simulation for Android remote platform debugging.
862   // The locate module callback first call fails because module_spec does not
863   // have UUID. Then, the callback second call returns a breakpad symbol file
864   // for the UUID from the target process. GetOrCreateModule should succeed to
865   // return the module from the cache along with the symbol file from the Inputs
866   // directory.
867   FileSpec uuid_view = BuildCacheDir(m_test_dir);
868 
869   int callback_call_count = 0;
870   m_platform_sp->SetLocateModuleCallback(
871       [this, &callback_call_count](const ModuleSpec &module_spec,
872                                    FileSpec &module_file_spec,
873                                    FileSpec &symbol_file_spec) {
874         callback_call_count++;
875         if (callback_call_count == 1) {
876           // The module_spec does not have UUID on the first call.
877           CheckCallbackArgsWithoutUUID(module_spec, module_file_spec,
878                                        symbol_file_spec, callback_call_count);
879           return Status::FromErrorString("Ignored empty UUID");
880         } else {
881           // The module_spec has UUID on the second call.
882           CheckCallbackArgsWithUUID(module_spec, module_file_spec,
883                                     symbol_file_spec, callback_call_count);
884           symbol_file_spec.SetPath(GetInputFilePath(k_breakpad_symbol_file));
885           return Status();
886         }
887       });
888 
889   m_module_sp = m_target_sp->GetOrCreateModule(m_module_spec_without_uuid,
890                                                /*notify=*/false);
891   ASSERT_EQ(callback_call_count, 2);
892   CheckModule(m_module_sp);
893   ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
894   ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(),
895             FileSpec(GetInputFilePath(k_breakpad_symbol_file)));
896   CheckUnstrippedSymbol(m_module_sp);
897   ModuleList::RemoveSharedModule(m_module_sp);
898 }
899