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(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 | |
88 | FileSpec GetRemotePath() { |
89 | FileSpec fs("/" , FileSpec::Style::posix); |
90 | fs.AppendPathComponent(component: "bin" ); |
91 | fs.AppendPathComponent(component: k_module_file); |
92 | return fs; |
93 | } |
94 | |
95 | FileSpec 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 | |
103 | void 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 | |
111 | FileSpec 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 | |
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(From: GetInputFilePath(name: k_symbol_file), |
130 | To: 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(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 | |
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(name: ConstString(name), parent_decl_ctx: CompilerDeclContext(), name_type_mask: type, |
166 | options: function_options, sc_list); |
167 | return sc_list; |
168 | } |
169 | |
170 | void 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 | |
178 | void 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 | |
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>(args&: target_sp, args&: 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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |