/ src / processor / fast_source_line_resolver_unittest.cc
fast_source_line_resolver_unittest.cc
  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 (lambxsy@google.com)
 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:
 74    explicit TestCodeModule(string code_file) : code_file_(code_file) {}
 75    virtual ~TestCodeModule() {}
 76  
 77    virtual uint64_t base_address() const { return 0; }
 78    virtual uint64_t size() const { return 0xb000; }
 79    virtual string code_file() const { return code_file_; }
 80    virtual string code_identifier() const { return ""; }
 81    virtual string debug_file() const { return ""; }
 82    virtual string debug_identifier() const { return ""; }
 83    virtual string version() const { return ""; }
 84    virtual CodeModule* Copy() const {
 85      return new TestCodeModule(code_file_);
 86    }
 87    virtual bool is_unloaded() const { return false; }
 88    virtual uint64_t shrink_down_delta() const { return 0; }
 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 {
 97    uint64_t GetBase() const { return 0x10000; }
 98    uint32_t GetSize() const { return 0x01000; }
 99    bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
100      *value = address & 0xff;
101      return true;
102    }
103    bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
104      *value = address & 0xffff;
105      return true;
106    }
107    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    }
118    bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
119      *value = address;
120      return true;
121    }
122    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".
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  
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  
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:
180    void SetUp() {
181      testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
182                           "/src/processor/testdata";
183    }
184  
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.
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.
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.
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  
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  
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  
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  
600  int main(int argc, char* argv[]) {
601    ::testing::InitGoogleTest(&argc, argv);
602    return RUN_ALL_TESTS();
603  }