1 // Copyright (c) 2010 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 // fast_source_line_resolver_unittest.cc: Unit tests for FastSourceLineResolver.
31 // Two different approaches for testing fast source line resolver:
32 // First, use the same unit test data for basic source line resolver.
33 // Second, read data from symbol files, load them as basic modules, and then
34 // serialize them and load the serialized data as fast modules. Then compare
35 // modules to assure the fast module contains exactly the same data as
38 // Author: Siyang Xie (lambxsy@google.com)
46 #include "breakpad_googletest_includes.h"
47 #include "common/using_std_string.h"
48 #include "google_breakpad/processor/code_module.h"
49 #include "google_breakpad/processor/stack_frame.h"
50 #include "google_breakpad/processor/memory_region.h"
51 #include "processor/logging.h"
52 #include "processor/module_serializer.h"
53 #include "processor/module_comparer.h"
57 using google_breakpad::SourceLineResolverBase;
58 using google_breakpad::BasicSourceLineResolver;
59 using google_breakpad::FastSourceLineResolver;
60 using google_breakpad::ModuleSerializer;
61 using google_breakpad::ModuleComparer;
62 using google_breakpad::CFIFrameInfo;
63 using google_breakpad::CodeModule;
64 using google_breakpad::MemoryRegion;
65 using google_breakpad::StackFrame;
66 using google_breakpad::WindowsFrameInfo;
67 using google_breakpad::linked_ptr;
68 using google_breakpad::scoped_ptr;
70 class TestCodeModule : public CodeModule {
72 explicit TestCodeModule(string code_file) : code_file_(code_file) {}
73 virtual ~TestCodeModule() {}
75 virtual uint64_t base_address() const { return 0; }
76 virtual uint64_t size() const { return 0xb000; }
77 virtual string code_file() const { return code_file_; }
78 virtual string code_identifier() const { return ""; }
79 virtual string debug_file() const { return ""; }
80 virtual string debug_identifier() const { return ""; }
81 virtual string version() const { return ""; }
82 virtual const CodeModule* Copy() const {
83 return new TestCodeModule(code_file_);
90 // A mock memory region object, for use by the STACK CFI tests.
91 class MockMemoryRegion: public MemoryRegion {
92 uint64_t GetBase() const { return 0x10000; }
93 uint32_t GetSize() const { return 0x01000; }
94 bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
95 *value = address & 0xff;
98 bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
99 *value = address & 0xffff;
102 bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
104 case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
105 case 0x1000c: *value = 0x878f7524; break; // saved %esi
106 case 0x10010: *value = 0x6312f9a5; break; // saved %edi
107 case 0x10014: *value = 0x10038; break; // caller's %ebp
108 case 0x10018: *value = 0xf6438648; break; // return address
109 default: *value = 0xdeadbeef; break; // junk
113 bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
122 // Verify that, for every association in ACTUAL, EXPECTED has the same
123 // association. (That is, ACTUAL's associations should be a subset of
124 // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
126 static bool VerifyRegisters(
127 const char *file, int line,
128 const CFIFrameInfo::RegisterValueMap<uint32_t> &expected,
129 const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) {
130 CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
131 a = actual.find(".cfa");
132 if (a == actual.end())
134 a = actual.find(".ra");
135 if (a == actual.end())
137 for (a = actual.begin(); a != actual.end(); a++) {
138 CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e =
139 expected.find(a->first);
140 if (e == expected.end()) {
141 fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
142 file, line, a->first.c_str(), a->second);
145 if (e->second != a->second) {
147 "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
148 file, line, a->first.c_str(), a->second, e->second);
151 // Don't complain if this doesn't recover all registers. Although
152 // the DWARF spec says that unmentioned registers are undefined,
153 // GCC uses omission to mean that they are unchanged.
158 static bool VerifyEmpty(const StackFrame &frame) {
159 if (frame.function_name.empty() &&
160 frame.source_file_name.empty() &&
161 frame.source_line == 0)
166 static void ClearSourceLineInfo(StackFrame *frame) {
167 frame->function_name.clear();
168 frame->module = NULL;
169 frame->source_file_name.clear();
170 frame->source_line = 0;
173 class TestFastSourceLineResolver : public ::testing::Test {
176 testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
177 "/src/processor/testdata";
180 string symbol_file(int file_index) {
181 std::stringstream ss;
182 ss << testdata_dir << "/module" << file_index << ".out";
186 ModuleSerializer serializer;
187 BasicSourceLineResolver basic_resolver;
188 FastSourceLineResolver fast_resolver;
189 ModuleComparer module_comparer;
194 // Test adapted from basic_source_line_resolver_unittest.
195 TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
196 TestCodeModule module1("module1");
197 ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
198 ASSERT_TRUE(basic_resolver.HasModule(&module1));
199 // Convert module1 to fast_module:
200 ASSERT_TRUE(serializer.ConvertOneModule(
201 module1.code_file(), &basic_resolver, &fast_resolver));
202 ASSERT_TRUE(fast_resolver.HasModule(&module1));
204 TestCodeModule module2("module2");
205 ASSERT_TRUE(basic_resolver.LoadModule(&module2, symbol_file(2)));
206 ASSERT_TRUE(basic_resolver.HasModule(&module2));
207 // Convert module2 to fast_module:
208 ASSERT_TRUE(serializer.ConvertOneModule(
209 module2.code_file(), &basic_resolver, &fast_resolver));
210 ASSERT_TRUE(fast_resolver.HasModule(&module2));
213 scoped_ptr<WindowsFrameInfo> windows_frame_info;
214 scoped_ptr<CFIFrameInfo> cfi_frame_info;
215 frame.instruction = 0x1000;
217 fast_resolver.FillSourceLineInfo(&frame);
218 ASSERT_FALSE(frame.module);
219 ASSERT_TRUE(frame.function_name.empty());
220 ASSERT_EQ(frame.function_base, 0U);
221 ASSERT_TRUE(frame.source_file_name.empty());
222 ASSERT_EQ(frame.source_line, 0);
223 ASSERT_EQ(frame.source_line_base, 0U);
225 frame.module = &module1;
226 fast_resolver.FillSourceLineInfo(&frame);
227 ASSERT_EQ(frame.function_name, "Function1_1");
228 ASSERT_TRUE(frame.module);
229 ASSERT_EQ(frame.module->code_file(), "module1");
230 ASSERT_EQ(frame.function_base, 0x1000U);
231 ASSERT_EQ(frame.source_file_name, "file1_1.cc");
232 ASSERT_EQ(frame.source_line, 44);
233 ASSERT_EQ(frame.source_line_base, 0x1000U);
234 windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
235 ASSERT_TRUE(windows_frame_info.get());
236 ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
237 ASSERT_EQ(windows_frame_info->program_string,
238 "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =");
240 ClearSourceLineInfo(&frame);
241 frame.instruction = 0x800;
242 frame.module = &module1;
243 fast_resolver.FillSourceLineInfo(&frame);
244 ASSERT_TRUE(VerifyEmpty(frame));
245 windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
246 ASSERT_FALSE(windows_frame_info.get());
248 frame.instruction = 0x1280;
249 fast_resolver.FillSourceLineInfo(&frame);
250 ASSERT_EQ(frame.function_name, "Function1_3");
251 ASSERT_TRUE(frame.source_file_name.empty());
252 ASSERT_EQ(frame.source_line, 0);
253 windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
254 ASSERT_TRUE(windows_frame_info.get());
255 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_UNKNOWN);
256 ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
257 ASSERT_TRUE(windows_frame_info->program_string.empty());
259 frame.instruction = 0x1380;
260 fast_resolver.FillSourceLineInfo(&frame);
261 ASSERT_EQ(frame.function_name, "Function1_4");
262 ASSERT_TRUE(frame.source_file_name.empty());
263 ASSERT_EQ(frame.source_line, 0);
264 windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
265 ASSERT_TRUE(windows_frame_info.get());
266 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
267 ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
268 ASSERT_FALSE(windows_frame_info->program_string.empty());
270 frame.instruction = 0x2000;
271 windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
272 ASSERT_FALSE(windows_frame_info.get());
274 // module1 has STACK CFI records covering 3d40..3def;
275 // module2 has STACK CFI records covering 3df0..3e9f;
276 // check that FindCFIFrameInfo doesn't claim to find any outside those ranges.
277 frame.instruction = 0x3d3f;
278 frame.module = &module1;
279 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
280 ASSERT_FALSE(cfi_frame_info.get());
282 frame.instruction = 0x3e9f;
283 frame.module = &module1;
284 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
285 ASSERT_FALSE(cfi_frame_info.get());
287 CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
288 CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
289 CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers;
290 MockMemoryRegion memory;
292 // Regardless of which instruction evaluation takes place at, it
293 // should produce the same values for the caller's registers.
294 expected_caller_registers[".cfa"] = 0x1001c;
295 expected_caller_registers[".ra"] = 0xf6438648;
296 expected_caller_registers["$ebp"] = 0x10038;
297 expected_caller_registers["$ebx"] = 0x98ecadc3;
298 expected_caller_registers["$esi"] = 0x878f7524;
299 expected_caller_registers["$edi"] = 0x6312f9a5;
301 frame.instruction = 0x3d40;
302 frame.module = &module1;
303 current_registers.clear();
304 current_registers["$esp"] = 0x10018;
305 current_registers["$ebp"] = 0x10038;
306 current_registers["$ebx"] = 0x98ecadc3;
307 current_registers["$esi"] = 0x878f7524;
308 current_registers["$edi"] = 0x6312f9a5;
309 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
310 ASSERT_TRUE(cfi_frame_info.get());
311 ASSERT_TRUE(cfi_frame_info.get()
312 ->FindCallerRegs<uint32_t>(current_registers, memory,
314 ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
315 expected_caller_registers, caller_registers));
317 frame.instruction = 0x3d41;
318 current_registers["$esp"] = 0x10014;
319 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
320 ASSERT_TRUE(cfi_frame_info.get());
321 ASSERT_TRUE(cfi_frame_info.get()
322 ->FindCallerRegs<uint32_t>(current_registers, memory,
324 ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
325 expected_caller_registers, caller_registers));
327 frame.instruction = 0x3d43;
328 current_registers["$ebp"] = 0x10014;
329 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
330 ASSERT_TRUE(cfi_frame_info.get());
331 ASSERT_TRUE(cfi_frame_info.get()
332 ->FindCallerRegs<uint32_t>(current_registers, memory,
334 VerifyRegisters(__FILE__, __LINE__,
335 expected_caller_registers, caller_registers);
337 frame.instruction = 0x3d54;
338 current_registers["$ebx"] = 0x6864f054U;
339 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
340 ASSERT_TRUE(cfi_frame_info.get());
341 ASSERT_TRUE(cfi_frame_info.get()
342 ->FindCallerRegs<uint32_t>(current_registers, memory,
344 VerifyRegisters(__FILE__, __LINE__,
345 expected_caller_registers, caller_registers);
347 frame.instruction = 0x3d5a;
348 current_registers["$esi"] = 0x6285f79aU;
349 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
350 ASSERT_TRUE(cfi_frame_info.get());
351 ASSERT_TRUE(cfi_frame_info.get()
352 ->FindCallerRegs<uint32_t>(current_registers, memory,
354 VerifyRegisters(__FILE__, __LINE__,
355 expected_caller_registers, caller_registers);
357 frame.instruction = 0x3d84;
358 current_registers["$edi"] = 0x64061449U;
359 cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
360 ASSERT_TRUE(cfi_frame_info.get());
361 ASSERT_TRUE(cfi_frame_info.get()
362 ->FindCallerRegs<uint32_t>(current_registers, memory,
364 VerifyRegisters(__FILE__, __LINE__,
365 expected_caller_registers, caller_registers);
367 frame.instruction = 0x2900;
368 frame.module = &module1;
369 fast_resolver.FillSourceLineInfo(&frame);
370 ASSERT_EQ(frame.function_name, string("PublicSymbol"));
372 frame.instruction = 0x4000;
373 frame.module = &module1;
374 fast_resolver.FillSourceLineInfo(&frame);
375 ASSERT_EQ(frame.function_name, string("LargeFunction"));
377 frame.instruction = 0x2181;
378 frame.module = &module2;
379 fast_resolver.FillSourceLineInfo(&frame);
380 ASSERT_EQ(frame.function_name, "Function2_2");
381 ASSERT_EQ(frame.function_base, 0x2170U);
382 ASSERT_TRUE(frame.module);
383 ASSERT_EQ(frame.module->code_file(), "module2");
384 ASSERT_EQ(frame.source_file_name, "file2_2.cc");
385 ASSERT_EQ(frame.source_line, 21);
386 ASSERT_EQ(frame.source_line_base, 0x2180U);
387 windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
388 ASSERT_TRUE(windows_frame_info.get());
389 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
390 ASSERT_EQ(windows_frame_info->prolog_size, 1U);
392 frame.instruction = 0x216f;
393 fast_resolver.FillSourceLineInfo(&frame);
394 ASSERT_EQ(frame.function_name, "Public2_1");
396 ClearSourceLineInfo(&frame);
397 frame.instruction = 0x219f;
398 frame.module = &module2;
399 fast_resolver.FillSourceLineInfo(&frame);
400 ASSERT_TRUE(frame.function_name.empty());
402 frame.instruction = 0x21a0;
403 frame.module = &module2;
404 fast_resolver.FillSourceLineInfo(&frame);
405 ASSERT_EQ(frame.function_name, "Public2_2");
408 TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
409 TestCodeModule module3("module3");
410 ASSERT_TRUE(basic_resolver.LoadModule(&module3,
411 testdata_dir + "/module3_bad.out"));
412 ASSERT_TRUE(basic_resolver.HasModule(&module3));
413 ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module3));
414 // Convert module3 to fast_module:
415 ASSERT_TRUE(serializer.ConvertOneModule(module3.code_file(),
418 ASSERT_TRUE(fast_resolver.HasModule(&module3));
419 ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module3));
421 TestCodeModule module4("module4");
422 ASSERT_TRUE(basic_resolver.LoadModule(&module4,
423 testdata_dir + "/module4_bad.out"));
424 ASSERT_TRUE(basic_resolver.HasModule(&module4));
425 ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module4));
426 // Convert module4 to fast_module:
427 ASSERT_TRUE(serializer.ConvertOneModule(module4.code_file(),
430 ASSERT_TRUE(fast_resolver.HasModule(&module4));
431 ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module4));
433 TestCodeModule module5("module5");
434 ASSERT_FALSE(fast_resolver.LoadModule(&module5,
435 testdata_dir + "/invalid-filename"));
436 ASSERT_FALSE(fast_resolver.HasModule(&module5));
438 TestCodeModule invalidmodule("invalid-module");
439 ASSERT_FALSE(fast_resolver.HasModule(&invalidmodule));
442 TEST_F(TestFastSourceLineResolver, TestUnload) {
443 TestCodeModule module1("module1");
444 ASSERT_FALSE(basic_resolver.HasModule(&module1));
446 ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
447 ASSERT_TRUE(basic_resolver.HasModule(&module1));
448 // Convert module1 to fast_module.
449 ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(),
452 ASSERT_TRUE(fast_resolver.HasModule(&module1));
453 basic_resolver.UnloadModule(&module1);
454 fast_resolver.UnloadModule(&module1);
455 ASSERT_FALSE(fast_resolver.HasModule(&module1));
457 ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
458 ASSERT_TRUE(basic_resolver.HasModule(&module1));
459 // Convert module1 to fast_module.
460 ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(),
463 ASSERT_TRUE(fast_resolver.HasModule(&module1));
466 TEST_F(TestFastSourceLineResolver, CompareModule) {
468 size_t symbol_data_size;
469 string symbol_data_string;
472 for (int module_index = 0; module_index < 3; ++module_index) {
473 std::stringstream ss;
474 ss << testdata_dir << "/module" << module_index << ".out";
476 ASSERT_TRUE(SourceLineResolverBase::ReadSymbolFile(
477 symbol_file(module_index), &symbol_data, &symbol_data_size));
478 symbol_data_string.assign(symbol_data, symbol_data_size);
479 delete [] symbol_data;
480 ASSERT_TRUE(module_comparer.Compare(symbol_data_string));
486 int main(int argc, char *argv[]) {
487 ::testing::InitGoogleTest(&argc, argv);
488 return RUN_ALL_TESTS();