xref: /aosp_15_r20/external/google-breakpad/src/processor/fast_source_line_resolver_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // fast_source_line_resolver_unittest.cc: Unit tests for FastSourceLineResolver.
30 // Two different approaches for testing fast source line resolver:
31 // First, use the same unit test data for basic source line resolver.
32 // Second, read data from symbol files, load them as basic modules, and then
33 // serialize them and load the serialized data as fast modules.  Then compare
34 // modules to assure the fast module contains exactly the same data as
35 // basic module.
36 //
37 // Author: Siyang Xie ([email protected])
38 
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>  // Must come first
41 #endif
42 
43 #include <assert.h>
44 #include <stdio.h>
45 
46 #include <sstream>
47 #include <string>
48 
49 #include "breakpad_googletest_includes.h"
50 #include "common/using_std_string.h"
51 #include "google_breakpad/processor/code_module.h"
52 #include "google_breakpad/processor/stack_frame.h"
53 #include "google_breakpad/processor/memory_region.h"
54 #include "processor/logging.h"
55 #include "processor/module_serializer.h"
56 #include "processor/module_comparer.h"
57 
58 namespace {
59 
60 using google_breakpad::SourceLineResolverBase;
61 using google_breakpad::BasicSourceLineResolver;
62 using google_breakpad::FastSourceLineResolver;
63 using google_breakpad::ModuleSerializer;
64 using google_breakpad::ModuleComparer;
65 using google_breakpad::CFIFrameInfo;
66 using google_breakpad::CodeModule;
67 using google_breakpad::MemoryRegion;
68 using google_breakpad::StackFrame;
69 using google_breakpad::WindowsFrameInfo;
70 using google_breakpad::scoped_ptr;
71 
72 class TestCodeModule : public CodeModule {
73  public:
TestCodeModule(string code_file)74   explicit TestCodeModule(string code_file) : code_file_(code_file) {}
~TestCodeModule()75   virtual ~TestCodeModule() {}
76 
base_address() const77   virtual uint64_t base_address() const { return 0; }
size() const78   virtual uint64_t size() const { return 0xb000; }
code_file() const79   virtual string code_file() const { return code_file_; }
code_identifier() const80   virtual string code_identifier() const { return ""; }
debug_file() const81   virtual string debug_file() const { return ""; }
debug_identifier() const82   virtual string debug_identifier() const { return ""; }
version() const83   virtual string version() const { return ""; }
Copy() const84   virtual CodeModule* Copy() const {
85     return new TestCodeModule(code_file_);
86   }
is_unloaded() const87   virtual bool is_unloaded() const { return false; }
shrink_down_delta() const88   virtual uint64_t shrink_down_delta() const { return 0; }
SetShrinkDownDelta(uint64_t shrink_down_delta)89   virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {}
90 
91  private:
92   string code_file_;
93 };
94 
95 // A mock memory region object, for use by the STACK CFI tests.
96 class MockMemoryRegion: public MemoryRegion {
GetBase() const97   uint64_t GetBase() const { return 0x10000; }
GetSize() const98   uint32_t GetSize() const { return 0x01000; }
GetMemoryAtAddress(uint64_t address,uint8_t * value) const99   bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
100     *value = address & 0xff;
101     return true;
102   }
GetMemoryAtAddress(uint64_t address,uint16_t * value) const103   bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
104     *value = address & 0xffff;
105     return true;
106   }
GetMemoryAtAddress(uint64_t address,uint32_t * value) const107   bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
108     switch (address) {
109       case 0x10008: *value = 0x98ecadc3; break;  // saved %ebx
110       case 0x1000c: *value = 0x878f7524; break;  // saved %esi
111       case 0x10010: *value = 0x6312f9a5; break;  // saved %edi
112       case 0x10014: *value = 0x10038;    break;  // caller's %ebp
113       case 0x10018: *value = 0xf6438648; break;  // return address
114       default: *value = 0xdeadbeef;      break;  // junk
115     }
116     return true;
117   }
GetMemoryAtAddress(uint64_t address,uint64_t * value) const118   bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
119     *value = address;
120     return true;
121   }
Print() const122   void Print() const {
123     assert(false);
124   }
125 };
126 
127 // Verify that, for every association in ACTUAL, EXPECTED has the same
128 // association. (That is, ACTUAL's associations should be a subset of
129 // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
130 // ".cfa".
VerifyRegisters(const char * file,int line,const CFIFrameInfo::RegisterValueMap<uint32_t> & expected,const CFIFrameInfo::RegisterValueMap<uint32_t> & actual)131 static bool VerifyRegisters(
132     const char* file, int line,
133     const CFIFrameInfo::RegisterValueMap<uint32_t>& expected,
134     const CFIFrameInfo::RegisterValueMap<uint32_t>& actual) {
135   CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
136   a = actual.find(".cfa");
137   if (a == actual.end())
138     return false;
139   a = actual.find(".ra");
140   if (a == actual.end())
141     return false;
142   for (a = actual.begin(); a != actual.end(); a++) {
143     CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e =
144       expected.find(a->first);
145     if (e == expected.end()) {
146       fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
147               file, line, a->first.c_str(), a->second);
148       return false;
149     }
150     if (e->second != a->second) {
151       fprintf(stderr,
152               "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
153               file, line, a->first.c_str(), a->second, e->second);
154       return false;
155     }
156     // Don't complain if this doesn't recover all registers. Although
157     // the DWARF spec says that unmentioned registers are undefined,
158     // GCC uses omission to mean that they are unchanged.
159   }
160   return true;
161 }
162 
VerifyEmpty(const StackFrame & frame)163 static bool VerifyEmpty(const StackFrame& frame) {
164   if (frame.function_name.empty() &&
165       frame.source_file_name.empty() &&
166       frame.source_line == 0)
167     return true;
168   return false;
169 }
170 
ClearSourceLineInfo(StackFrame * frame)171 static void ClearSourceLineInfo(StackFrame* frame) {
172   frame->function_name.clear();
173   frame->module = NULL;
174   frame->source_file_name.clear();
175   frame->source_line = 0;
176 }
177 
178 class TestFastSourceLineResolver : public ::testing::Test {
179  public:
SetUp()180   void SetUp() {
181     testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
182                          "/src/processor/testdata";
183   }
184 
symbol_file(int file_index)185   string symbol_file(int file_index) {
186     std::stringstream ss;
187     ss << testdata_dir << "/module" << file_index << ".out";
188     return ss.str();
189   }
190 
191   ModuleSerializer serializer;
192   BasicSourceLineResolver basic_resolver;
193   FastSourceLineResolver fast_resolver;
194   ModuleComparer module_comparer;
195 
196   string testdata_dir;
197 };
198 
199 // Test adapted from basic_source_line_resolver_unittest.
TEST_F(TestFastSourceLineResolver,TestLoadAndResolve)200 TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
201   TestCodeModule module1("module1");
202   ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
203   ASSERT_TRUE(basic_resolver.HasModule(&module1));
204   // Convert module1 to fast_module:
205   ASSERT_TRUE(serializer.ConvertOneModule(
206       module1.code_file(), &basic_resolver, &fast_resolver));
207   ASSERT_TRUE(fast_resolver.HasModule(&module1));
208 
209   TestCodeModule module2("module2");
210   ASSERT_TRUE(basic_resolver.LoadModule(&module2, symbol_file(2)));
211   ASSERT_TRUE(basic_resolver.HasModule(&module2));
212   // Convert module2 to fast_module:
213   ASSERT_TRUE(serializer.ConvertOneModule(
214       module2.code_file(), &basic_resolver, &fast_resolver));
215   ASSERT_TRUE(fast_resolver.HasModule(&module2));
216 
217   StackFrame frame;
218   scoped_ptr<WindowsFrameInfo> windows_frame_info;
219   scoped_ptr<CFIFrameInfo> cfi_frame_info;
220   frame.instruction = 0x1000;
221   frame.module = NULL;
222   fast_resolver.FillSourceLineInfo(&frame, nullptr);
223   ASSERT_FALSE(frame.module);
224   ASSERT_TRUE(frame.function_name.empty());
225   ASSERT_EQ(frame.function_base, 0U);
226   ASSERT_TRUE(frame.source_file_name.empty());
227   ASSERT_EQ(frame.source_line, 0);
228   ASSERT_EQ(frame.source_line_base, 0U);
229   ASSERT_EQ(frame.is_multiple, false);
230 
231   frame.module = &module1;
232   fast_resolver.FillSourceLineInfo(&frame, nullptr);
233   ASSERT_EQ(frame.function_name, "Function1_1");
234   ASSERT_TRUE(frame.module);
235   ASSERT_EQ(frame.module->code_file(), "module1");
236   ASSERT_EQ(frame.function_base, 0x1000U);
237   ASSERT_EQ(frame.source_file_name, "file1_1.cc");
238   ASSERT_EQ(frame.source_line, 44);
239   ASSERT_EQ(frame.source_line_base, 0x1000U);
240   ASSERT_EQ(frame.is_multiple, true);
241   windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
242   ASSERT_TRUE(windows_frame_info.get());
243   ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
244   ASSERT_EQ(windows_frame_info->program_string,
245             "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =");
246 
247   ClearSourceLineInfo(&frame);
248   frame.instruction = 0x800;
249   frame.module = &module1;
250   fast_resolver.FillSourceLineInfo(&frame, nullptr);
251   ASSERT_TRUE(VerifyEmpty(frame));
252   windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
253   ASSERT_FALSE(windows_frame_info.get());
254 
255   frame.instruction = 0x1280;
256   fast_resolver.FillSourceLineInfo(&frame, nullptr);
257   ASSERT_EQ(frame.function_name, "Function1_3");
258   ASSERT_TRUE(frame.source_file_name.empty());
259   ASSERT_EQ(frame.source_line, 0);
260   windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
261   ASSERT_TRUE(windows_frame_info.get());
262   ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_UNKNOWN);
263   ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
264   ASSERT_TRUE(windows_frame_info->program_string.empty());
265 
266   frame.instruction = 0x1380;
267   fast_resolver.FillSourceLineInfo(&frame, nullptr);
268   ASSERT_EQ(frame.function_name, "Function1_4");
269   ASSERT_TRUE(frame.source_file_name.empty());
270   ASSERT_EQ(frame.source_line, 0);
271   windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
272   ASSERT_TRUE(windows_frame_info.get());
273   ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
274   ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
275   ASSERT_FALSE(windows_frame_info->program_string.empty());
276 
277   frame.instruction = 0x2000;
278   windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
279   ASSERT_FALSE(windows_frame_info.get());
280 
281   // module1 has STACK CFI records covering 3d40..3def;
282   // module2 has STACK CFI records covering 3df0..3e9f;
283   // check that FindCFIFrameInfo doesn't claim to find any outside those ranges.
284   frame.instruction = 0x3d3f;
285   frame.module = &module1;
286   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
287   ASSERT_FALSE(cfi_frame_info.get());
288 
289   frame.instruction = 0x3e9f;
290   frame.module = &module1;
291   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
292   ASSERT_FALSE(cfi_frame_info.get());
293 
294   CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
295   CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
296   CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers;
297   MockMemoryRegion memory;
298 
299   // Regardless of which instruction evaluation takes place at, it
300   // should produce the same values for the caller's registers.
301   expected_caller_registers[".cfa"] = 0x1001c;
302   expected_caller_registers[".ra"]  = 0xf6438648;
303   expected_caller_registers["$ebp"] = 0x10038;
304   expected_caller_registers["$ebx"] = 0x98ecadc3;
305   expected_caller_registers["$esi"] = 0x878f7524;
306   expected_caller_registers["$edi"] = 0x6312f9a5;
307 
308   frame.instruction = 0x3d40;
309   frame.module = &module1;
310   current_registers.clear();
311   current_registers["$esp"] = 0x10018;
312   current_registers["$ebp"] = 0x10038;
313   current_registers["$ebx"] = 0x98ecadc3;
314   current_registers["$esi"] = 0x878f7524;
315   current_registers["$edi"] = 0x6312f9a5;
316   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
317   ASSERT_TRUE(cfi_frame_info.get());
318   ASSERT_TRUE(cfi_frame_info.get()
319               ->FindCallerRegs<uint32_t>(current_registers, memory,
320                                           &caller_registers));
321   ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
322                               expected_caller_registers, caller_registers));
323 
324   frame.instruction = 0x3d41;
325   current_registers["$esp"] = 0x10014;
326   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
327   ASSERT_TRUE(cfi_frame_info.get());
328   ASSERT_TRUE(cfi_frame_info.get()
329               ->FindCallerRegs<uint32_t>(current_registers, memory,
330                                           &caller_registers));
331   ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
332                               expected_caller_registers, caller_registers));
333 
334   frame.instruction = 0x3d43;
335   current_registers["$ebp"] = 0x10014;
336   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
337   ASSERT_TRUE(cfi_frame_info.get());
338   ASSERT_TRUE(cfi_frame_info.get()
339               ->FindCallerRegs<uint32_t>(current_registers, memory,
340                                           &caller_registers));
341   VerifyRegisters(__FILE__, __LINE__,
342                   expected_caller_registers, caller_registers);
343 
344   frame.instruction = 0x3d54;
345   current_registers["$ebx"] = 0x6864f054U;
346   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
347   ASSERT_TRUE(cfi_frame_info.get());
348   ASSERT_TRUE(cfi_frame_info.get()
349               ->FindCallerRegs<uint32_t>(current_registers, memory,
350                                           &caller_registers));
351   VerifyRegisters(__FILE__, __LINE__,
352                   expected_caller_registers, caller_registers);
353 
354   frame.instruction = 0x3d5a;
355   current_registers["$esi"] = 0x6285f79aU;
356   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
357   ASSERT_TRUE(cfi_frame_info.get());
358   ASSERT_TRUE(cfi_frame_info.get()
359               ->FindCallerRegs<uint32_t>(current_registers, memory,
360                                           &caller_registers));
361   VerifyRegisters(__FILE__, __LINE__,
362                   expected_caller_registers, caller_registers);
363 
364   frame.instruction = 0x3d84;
365   current_registers["$edi"] = 0x64061449U;
366   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
367   ASSERT_TRUE(cfi_frame_info.get());
368   ASSERT_TRUE(cfi_frame_info.get()
369               ->FindCallerRegs<uint32_t>(current_registers, memory,
370                                           &caller_registers));
371   VerifyRegisters(__FILE__, __LINE__,
372                   expected_caller_registers, caller_registers);
373 
374   frame.instruction = 0x2900;
375   frame.module = &module1;
376   fast_resolver.FillSourceLineInfo(&frame, nullptr);
377   ASSERT_EQ(frame.function_name, string("PublicSymbol"));
378   EXPECT_EQ(frame.is_multiple, true);
379 
380   frame.instruction = 0x4000;
381   frame.module = &module1;
382   fast_resolver.FillSourceLineInfo(&frame, nullptr);
383   ASSERT_EQ(frame.function_name, string("LargeFunction"));
384 
385   frame.instruction = 0x2181;
386   frame.module = &module2;
387   fast_resolver.FillSourceLineInfo(&frame, nullptr);
388   ASSERT_EQ(frame.function_name, "Function2_2");
389   ASSERT_EQ(frame.function_base, 0x2170U);
390   ASSERT_TRUE(frame.module);
391   ASSERT_EQ(frame.module->code_file(), "module2");
392   ASSERT_EQ(frame.source_file_name, "file2_2.cc");
393   ASSERT_EQ(frame.source_line, 21);
394   ASSERT_EQ(frame.source_line_base, 0x2180U);
395   ASSERT_EQ(frame.is_multiple, false);
396   windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
397   ASSERT_TRUE(windows_frame_info.get());
398   ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
399   ASSERT_EQ(windows_frame_info->prolog_size, 1U);
400 
401   frame.instruction = 0x216f;
402   fast_resolver.FillSourceLineInfo(&frame, nullptr);
403   ASSERT_EQ(frame.function_name, "Public2_1");
404   EXPECT_EQ(frame.is_multiple, false);
405 
406   ClearSourceLineInfo(&frame);
407   frame.instruction = 0x219f;
408   frame.module = &module2;
409   fast_resolver.FillSourceLineInfo(&frame, nullptr);
410   ASSERT_TRUE(frame.function_name.empty());
411 
412   frame.instruction = 0x21a0;
413   frame.module = &module2;
414   fast_resolver.FillSourceLineInfo(&frame, nullptr);
415   ASSERT_EQ(frame.function_name, "Public2_2");
416 }
417 
418 // Test adapted from basic_source_line_resolver_unittest.
TEST_F(TestFastSourceLineResolver,TestLoadAndResolveOldInlines)419 TEST_F(TestFastSourceLineResolver, TestLoadAndResolveOldInlines) {
420   TestCodeModule module("linux_inline");
421   ASSERT_TRUE(basic_resolver.LoadModule(
422       &module, testdata_dir +
423                    "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
424                    "linux_inline.old.sym"));
425   ASSERT_TRUE(basic_resolver.HasModule(&module));
426   // Convert module1 to fast_module:
427   ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver,
428                                           &fast_resolver));
429   ASSERT_TRUE(fast_resolver.HasModule(&module));
430 
431   StackFrame frame;
432   std::deque<std::unique_ptr<StackFrame>> inlined_frames;
433   frame.instruction = 0x161b6;
434   frame.module = &module;
435   fast_resolver.FillSourceLineInfo(&frame, &inlined_frames);
436 
437   // main frame.
438   ASSERT_EQ(frame.function_name, "main");
439   ASSERT_EQ(frame.function_base, 0x15b30U);
440   ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
441   ASSERT_EQ(frame.source_line, 42);
442   ASSERT_EQ(frame.source_line_base, 0x161b6U);
443   ASSERT_EQ(frame.is_multiple, false);
444 
445   ASSERT_EQ(inlined_frames.size(), 3UL);
446 
447   // Inlined frames inside main frame.
448   ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
449   ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
450   ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp");
451   ASSERT_EQ(inlined_frames[2]->source_line, 39);
452   ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
453   ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
454 
455   ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
456   ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
457   ASSERT_EQ(inlined_frames[1]->source_file_name, "linux_inline.cpp");
458   ASSERT_EQ(inlined_frames[1]->source_line, 32);
459   ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
460   ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
461 
462   ASSERT_EQ(inlined_frames[0]->function_name, "func()");
463   ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
464   ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
465   ASSERT_EQ(inlined_frames[0]->source_line, 27);
466   ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
467   ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
468 }
469 
470 // Test adapted from basic_source_line_resolver_unittest.
TEST_F(TestFastSourceLineResolver,TestLoadAndResolveNewInlines)471 TEST_F(TestFastSourceLineResolver, TestLoadAndResolveNewInlines) {
472   TestCodeModule module("linux_inline");
473   ASSERT_TRUE(basic_resolver.LoadModule(
474       &module, testdata_dir +
475                    "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
476                    "linux_inline.new.sym"));
477   ASSERT_TRUE(basic_resolver.HasModule(&module));
478   // Convert module1 to fast_module:
479   ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver,
480                                           &fast_resolver));
481   ASSERT_TRUE(fast_resolver.HasModule(&module));
482 
483   StackFrame frame;
484   std::deque<std::unique_ptr<StackFrame>> inlined_frames;
485   frame.instruction = 0x161b6;
486   frame.module = &module;
487   fast_resolver.FillSourceLineInfo(&frame, &inlined_frames);
488 
489   // main frame.
490   ASSERT_EQ(frame.function_name, "main");
491   ASSERT_EQ(frame.function_base, 0x15b30U);
492   ASSERT_EQ(frame.source_file_name, "a.cpp");
493   ASSERT_EQ(frame.source_line, 42);
494   ASSERT_EQ(frame.source_line_base, 0x161b6U);
495   ASSERT_EQ(frame.is_multiple, false);
496 
497   ASSERT_EQ(inlined_frames.size(), 3UL);
498 
499   // Inlined frames inside main frame.
500   ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
501   ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
502   ASSERT_EQ(inlined_frames[2]->source_file_name, "b.cpp");
503   ASSERT_EQ(inlined_frames[2]->source_line, 39);
504   ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
505   ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
506 
507   ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
508   ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
509   ASSERT_EQ(inlined_frames[1]->source_file_name, "c.cpp");
510   ASSERT_EQ(inlined_frames[1]->source_line, 32);
511   ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
512   ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
513 
514   ASSERT_EQ(inlined_frames[0]->function_name, "func()");
515   ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
516   ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
517   ASSERT_EQ(inlined_frames[0]->source_line, 27);
518   ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
519   ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
520 }
521 
TEST_F(TestFastSourceLineResolver,TestInvalidLoads)522 TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
523   TestCodeModule module3("module3");
524   ASSERT_TRUE(basic_resolver.LoadModule(&module3,
525                                         testdata_dir + "/module3_bad.out"));
526   ASSERT_TRUE(basic_resolver.HasModule(&module3));
527   ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module3));
528   // Convert module3 to fast_module:
529   ASSERT_TRUE(serializer.ConvertOneModule(module3.code_file(),
530                                           &basic_resolver,
531                                           &fast_resolver));
532   ASSERT_TRUE(fast_resolver.HasModule(&module3));
533   ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module3));
534 
535   TestCodeModule module4("module4");
536   ASSERT_TRUE(basic_resolver.LoadModule(&module4,
537                                         testdata_dir + "/module4_bad.out"));
538   ASSERT_TRUE(basic_resolver.HasModule(&module4));
539   ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module4));
540   // Convert module4 to fast_module:
541   ASSERT_TRUE(serializer.ConvertOneModule(module4.code_file(),
542                                           &basic_resolver,
543                                           &fast_resolver));
544   ASSERT_TRUE(fast_resolver.HasModule(&module4));
545   ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module4));
546 
547   TestCodeModule module5("module5");
548   ASSERT_FALSE(fast_resolver.LoadModule(&module5,
549                                         testdata_dir + "/invalid-filename"));
550   ASSERT_FALSE(fast_resolver.HasModule(&module5));
551 
552   TestCodeModule invalidmodule("invalid-module");
553   ASSERT_FALSE(fast_resolver.HasModule(&invalidmodule));
554 }
555 
TEST_F(TestFastSourceLineResolver,TestUnload)556 TEST_F(TestFastSourceLineResolver, TestUnload) {
557   TestCodeModule module1("module1");
558   ASSERT_FALSE(basic_resolver.HasModule(&module1));
559 
560   ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
561   ASSERT_TRUE(basic_resolver.HasModule(&module1));
562   // Convert module1 to fast_module.
563   ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(),
564                                           &basic_resolver,
565                                           &fast_resolver));
566   ASSERT_TRUE(fast_resolver.HasModule(&module1));
567   basic_resolver.UnloadModule(&module1);
568   fast_resolver.UnloadModule(&module1);
569   ASSERT_FALSE(fast_resolver.HasModule(&module1));
570 
571   ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
572   ASSERT_TRUE(basic_resolver.HasModule(&module1));
573   // Convert module1 to fast_module.
574   ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(),
575                                           &basic_resolver,
576                                           &fast_resolver));
577   ASSERT_TRUE(fast_resolver.HasModule(&module1));
578 }
579 
TEST_F(TestFastSourceLineResolver,CompareModule)580 TEST_F(TestFastSourceLineResolver, CompareModule) {
581   char* symbol_data;
582   size_t symbol_data_size;
583   string symbol_data_string;
584   string filename;
585 
586   for (int module_index = 0; module_index < 3; ++module_index) {
587     std::stringstream ss;
588     ss << testdata_dir << "/module" << module_index << ".out";
589     filename = ss.str();
590     ASSERT_TRUE(SourceLineResolverBase::ReadSymbolFile(
591         symbol_file(module_index), &symbol_data, &symbol_data_size));
592     symbol_data_string.assign(symbol_data, symbol_data_size);
593     delete [] symbol_data;
594     ASSERT_TRUE(module_comparer.Compare(symbol_data_string));
595   }
596 }
597 
598 }  // namespace
599 
main(int argc,char * argv[])600 int main(int argc, char* argv[]) {
601   ::testing::InitGoogleTest(&argc, argv);
602   return RUN_ALL_TESTS();
603 }
604