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
22using namespace lldb;
23using namespace lldb_private;
24using namespace lldb_private::platform_android;
25using namespace lldb_private::platform_linux;
26using namespace lldb_private::breakpad;
27using namespace testing;
28
29namespace {
30
31constexpr llvm::StringLiteral k_process_plugin("mock-process-plugin");
32constexpr llvm::StringLiteral k_platform_dir("remote-android");
33constexpr llvm::StringLiteral k_cache_dir(".cache");
34constexpr llvm::StringLiteral k_module_file("AndroidModule.so");
35constexpr llvm::StringLiteral k_symbol_file("AndroidModule.unstripped.so");
36constexpr llvm::StringLiteral k_breakpad_symbol_file("AndroidModule.so.sym");
37constexpr llvm::StringLiteral k_arch("aarch64-none-linux");
38constexpr llvm::StringLiteral
39 k_module_uuid("80008338-82A0-51E5-5922-C905D23890DA-BDDEFECC");
40constexpr llvm::StringLiteral k_function_symbol("boom");
41constexpr llvm::StringLiteral k_hidden_function_symbol("boom_hidden");
42const size_t k_module_size = 3784;
43
44ModuleSpec GetTestModuleSpec();
45
46class MockProcess : public Process {
47public:
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
78FileSpec GetTestDir() {
79 const auto *info = UnitTest::GetInstance()->current_test_info();
80 FileSpec test_dir = HostInfo::GetProcessTempDir();
81 test_dir.AppendPathComponent(component: std::string(info->test_case_name()) + "-" +
82 info->name());
83 std::error_code ec = llvm::sys::fs::create_directory(path: test_dir.GetPath());
84 EXPECT_FALSE(ec);
85 return test_dir;
86}
87
88FileSpec GetRemotePath() {
89 FileSpec fs("/", FileSpec::Style::posix);
90 fs.AppendPathComponent(component: "bin");
91 fs.AppendPathComponent(component: k_module_file);
92 return fs;
93}
94
95FileSpec GetUuidView(FileSpec spec) {
96 spec.AppendPathComponent(component: k_platform_dir);
97 spec.AppendPathComponent(component: k_cache_dir);
98 spec.AppendPathComponent(component: k_module_uuid);
99 spec.AppendPathComponent(component: k_module_file);
100 return spec;
101}
102
103void BuildEmptyCacheDir(const FileSpec &test_dir) {
104 FileSpec cache_dir(test_dir);
105 cache_dir.AppendPathComponent(component: k_platform_dir);
106 cache_dir.AppendPathComponent(component: k_cache_dir);
107 std::error_code ec = llvm::sys::fs::create_directories(path: cache_dir.GetPath());
108 EXPECT_FALSE(ec);
109}
110
111FileSpec BuildCacheDir(const FileSpec &test_dir) {
112 FileSpec uuid_view = GetUuidView(spec: test_dir);
113 std::error_code ec =
114 llvm::sys::fs::create_directories(path: uuid_view.GetDirectory().GetCString());
115 EXPECT_FALSE(ec);
116 ec = llvm::sys::fs::copy_file(From: GetInputFilePath(name: k_module_file),
117 To: uuid_view.GetPath().c_str());
118 EXPECT_FALSE(ec);
119 return uuid_view;
120}
121
122FileSpec GetSymFileSpec(const FileSpec &uuid_view) {
123 return FileSpec(uuid_view.GetPath() + ".sym");
124}
125
126FileSpec BuildCacheDirWithSymbol(const FileSpec &test_dir) {
127 FileSpec uuid_view = BuildCacheDir(test_dir);
128 std::error_code ec =
129 llvm::sys::fs::copy_file(From: GetInputFilePath(name: k_symbol_file),
130 To: GetSymFileSpec(uuid_view).GetPath().c_str());
131 EXPECT_FALSE(ec);
132 return uuid_view;
133}
134
135FileSpec BuildCacheDirWithBreakpadSymbol(const FileSpec &test_dir) {
136 FileSpec uuid_view = BuildCacheDir(test_dir);
137 std::error_code ec =
138 llvm::sys::fs::copy_file(From: GetInputFilePath(name: k_breakpad_symbol_file),
139 To: GetSymFileSpec(uuid_view).GetPath().c_str());
140 EXPECT_FALSE(ec);
141 return uuid_view;
142}
143
144ModuleSpec 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
151void 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
158SymbolContextList 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(name: ConstString(name), parent_decl_ctx: CompilerDeclContext(), name_type_mask: type,
166 options: function_options, sc_list);
167 return sc_list;
168}
169
170void CheckStrippedSymbol(const ModuleSP &module_sp) {
171 SymbolContextList sc_list = FindFunctions(module_sp, name: k_function_symbol);
172 EXPECT_EQ(1U, sc_list.GetSize());
173
174 sc_list = FindFunctions(module_sp, name: k_hidden_function_symbol);
175 EXPECT_EQ(0U, sc_list.GetSize());
176}
177
178void CheckUnstrippedSymbol(const ModuleSP &module_sp) {
179 SymbolContextList sc_list = FindFunctions(module_sp, name: k_function_symbol);
180 EXPECT_EQ(1U, sc_list.GetSize());
181
182 sc_list = FindFunctions(module_sp, name: k_hidden_function_symbol);
183 EXPECT_EQ(1U, sc_list.GetSize());
184}
185
186ProcessSP MockProcessCreateInstance(TargetSP target_sp, ListenerSP listener_sp,
187 const FileSpec *crash_file_path,
188 bool can_connect) {
189 return std::make_shared<MockProcess>(args&: target_sp, args&: listener_sp);
190}
191
192class LocateModuleCallbackTest : public testing::Test {
193 SubsystemRAII<FileSystem, HostInfo, ObjectFileBreakpad, ObjectFileELF,
194 PlatformAndroid, PlatformLinux, SymbolFileBreakpad,
195 SymbolFileSymtab>
196 subsystems;
197
198public:
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(force: true, arch: &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(force: true, arch: &arch);
216 EXPECT_TRUE(m_platform_sp);
217
218 // Create Target.
219 m_debugger_sp->GetTargetList().CreateTarget(debugger&: *m_debugger_sp, user_exe_path: "", arch,
220 get_dependent_modules: eLoadDependentsNo,
221 platform_sp&: m_platform_sp, target_sp&: m_target_sp);
222 EXPECT_TRUE(m_target_sp);
223
224 // Create MockProcess.
225 PluginManager::RegisterPlugin(name: k_process_plugin, description: "",
226 create_callback: MockProcessCreateInstance);
227 m_process_sp =
228 m_target_sp->CreateProcess(listener_sp: Listener::MakeListener(name: "test-listener"),
229 plugin_name: 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(module_sp&: 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 expected_module_spec: 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 expected_module_spec: m_module_spec_without_uuid, expected_callback_call_count);
274 EXPECT_FALSE(module_spec.GetUUID().IsValid());
275 }
276
277protected:
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
291TEST_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(test_dir: m_test_dir);
295
296 CheckNoCallback();
297
298 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
299 CheckModule(module_sp: m_module_sp);
300 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
301 ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
302 CheckStrippedSymbol(module_sp: m_module_sp);
303}
304
305TEST_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(test_dir: m_test_dir);
310
311 CheckNoCallback();
312
313 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
314 CheckModule(module_sp: m_module_sp);
315 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
316 ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(), GetSymFileSpec(uuid_view));
317 CheckUnstrippedSymbol(module_sp: m_module_sp);
318}
319
320TEST_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(test_dir: m_test_dir);
326
327 CheckNoCallback();
328
329 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
330 CheckModule(module_sp: m_module_sp);
331 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
332 ASSERT_EQ(m_module_sp->GetSymbolFileFileSpec(), GetSymFileSpec(uuid_view));
333 CheckUnstrippedSymbol(module_sp: m_module_sp);
334}
335
336TEST_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(test_dir: m_test_dir);
341
342 CheckNoCallback();
343
344 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
345 ASSERT_FALSE(m_module_sp);
346}
347
348TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
361 return Status("The locate module callback failed");
362 });
363
364 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
365 ASSERT_EQ(callback_call_count, 2);
366 ASSERT_FALSE(m_module_sp);
367}
368
369TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
382 return Status("The locate module callback failed");
383 });
384
385 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
386 ASSERT_EQ(callback_call_count, 2);
387 CheckModule(module_sp: m_module_sp);
388 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
389 ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
390 CheckStrippedSymbol(module_sp: m_module_sp);
391}
392
393TEST_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(test_dir: 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, expected_callback_call_count: ++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(module_spec: m_module_spec, /*notify=*/false);
412 ASSERT_EQ(callback_call_count, 2);
413 CheckModule(module_sp: m_module_sp);
414 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
415 ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
416 CheckStrippedSymbol(module_sp: m_module_sp);
417 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
418}
419
420TEST_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(test_dir: 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, expected_callback_call_count: ++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(module_spec: m_module_spec, /*notify=*/false);
438 ASSERT_EQ(callback_call_count, 2);
439 CheckModule(module_sp: m_module_sp);
440 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
441 ASSERT_FALSE(m_module_sp->GetSymbolFileFileSpec());
442 CheckStrippedSymbol(module_sp: m_module_sp);
443 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
444}
445
446TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
459 // The locate module callback returns a right module file.
460 module_file_spec.SetPath(GetInputFilePath(name: 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(module_spec: m_module_spec, /*notify=*/false);
467 ASSERT_EQ(callback_call_count, 2);
468 CheckModule(module_sp: m_module_sp);
469 ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
470 ASSERT_TRUE(m_module_sp->GetSymbolFileFileSpec().GetPath().empty());
471 CheckStrippedSymbol(module_sp: m_module_sp);
472 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
473}
474
475TEST_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(test_dir: 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 expected_callback_call_count: 1);
485 module_file_spec.SetPath(GetInputFilePath(name: k_module_file));
486 return Status();
487 });
488
489 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
490 CheckModule(module_sp: 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(module_sp: m_module_sp);
495 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
496}
497
498TEST_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(test_dir: 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 expected_callback_call_count: 1);
511 module_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
512 return Status();
513 });
514
515 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
516 CheckModule(module_sp: 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(module_sp: m_module_sp);
521 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
522}
523
524TEST_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(test_dir: 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 expected_callback_call_count: 1);
537 module_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
538 symbol_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
539 return Status();
540 });
541
542 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
543 CheckModule(module_sp: 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(module_sp: m_module_sp);
549 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
550}
551
552TEST_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(test_dir: 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 expected_callback_call_count: 1);
564 module_file_spec.SetPath(GetInputFilePath(name: k_module_file));
565 symbol_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
566 return Status();
567 });
568
569 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
570 CheckModule(module_sp: 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(module_sp: m_module_sp);
576 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
577}
578
579TEST_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(test_dir: 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 expected_callback_call_count: 1);
591 module_file_spec.SetPath(GetInputFilePath(name: k_module_file));
592 symbol_file_spec.SetPath(GetInputFilePath(name: k_breakpad_symbol_file));
593 return Status();
594 });
595
596 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
597 CheckModule(module_sp: 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(module_sp: m_module_sp);
603 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
604}
605
606TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
620 symbol_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
621 return Status();
622 });
623
624 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
625 ASSERT_EQ(callback_call_count, 2);
626 CheckModule(module_sp: 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(module_sp: m_module_sp);
631 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
632}
633
634TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
648 symbol_file_spec.SetPath(GetInputFilePath(name: k_breakpad_symbol_file));
649 return Status();
650 });
651
652 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
653 ASSERT_EQ(callback_call_count, 2);
654 CheckModule(module_sp: 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(module_sp: m_module_sp);
659 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
660}
661
662TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
679 symbol_file_spec.SetPath(GetInputFilePath(
680 name: callback_call_count == 1 ? k_breakpad_symbol_file : k_symbol_file));
681 return Status();
682 });
683
684 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
685 ASSERT_EQ(callback_call_count, 2);
686 CheckModule(module_sp: 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(module_sp: m_module_sp);
691 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
692}
693
694TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
707 symbol_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
708 return Status();
709 });
710
711 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
712 ASSERT_EQ(callback_call_count, 2);
713 ASSERT_FALSE(m_module_sp);
714}
715
716TEST_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(test_dir: 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, expected_callback_call_count: ++callback_call_count);
729 symbol_file_spec.SetPath(GetInputFilePath(name: k_breakpad_symbol_file));
730 return Status();
731 });
732
733 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec, /*notify=*/false);
734 ASSERT_EQ(callback_call_count, 2);
735 ASSERT_FALSE(m_module_sp);
736}
737
738TEST_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(test_dir: 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, expected_callback_call_count: callback_call_count);
758 return Status("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, expected_callback_call_count: callback_call_count);
763 module_file_spec.SetPath(GetInputFilePath(name: k_module_file));
764 return Status();
765 }
766 });
767
768 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec_without_uuid,
769 /*notify=*/false);
770 ASSERT_EQ(callback_call_count, 2);
771 CheckModule(module_sp: 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(module_sp: m_module_sp);
776 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
777}
778
779TEST_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(test_dir: 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, expected_callback_call_count: callback_call_count);
796 return Status("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, expected_callback_call_count: callback_call_count);
801 module_file_spec.SetPath(GetInputFilePath(name: k_module_file));
802 symbol_file_spec.SetPath(GetInputFilePath(name: k_symbol_file));
803 return Status();
804 }
805 });
806
807 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec_without_uuid,
808 /*notify=*/false);
809 ASSERT_EQ(callback_call_count, 2);
810 CheckModule(module_sp: 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(module_sp: m_module_sp);
816 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
817}
818
819TEST_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(test_dir: 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, expected_callback_call_count: callback_call_count);
836 return Status("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, expected_callback_call_count: callback_call_count);
841 module_file_spec.SetPath(GetInputFilePath(name: k_module_file));
842 symbol_file_spec.SetPath(GetInputFilePath(name: k_breakpad_symbol_file));
843 return Status();
844 }
845 });
846
847 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec_without_uuid,
848 /*notify=*/false);
849 ASSERT_EQ(callback_call_count, 2);
850 CheckModule(module_sp: 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(module_sp: m_module_sp);
856 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
857}
858
859TEST_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(test_dir: 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, expected_callback_call_count: callback_call_count);
879 return Status("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, expected_callback_call_count: callback_call_count);
884 symbol_file_spec.SetPath(GetInputFilePath(name: k_breakpad_symbol_file));
885 return Status();
886 }
887 });
888
889 m_module_sp = m_target_sp->GetOrCreateModule(module_spec: m_module_spec_without_uuid,
890 /*notify=*/false);
891 ASSERT_EQ(callback_call_count, 2);
892 CheckModule(module_sp: 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(module_sp: m_module_sp);
897 ModuleList::RemoveSharedModule(module_sp&: m_module_sp);
898}
899

source code of lldb/unittests/Target/LocateModuleCallbackTest.cpp