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