1 // Copyright (c) 2010 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
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
13 // distribution.
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.
17 //
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.
29
30 #include <assert.h>
31 #include <stdio.h>
32
33 #include <string>
34
35 #include "breakpad_googletest_includes.h"
36 #include "common/scoped_ptr.h"
37 #include "common/using_std_string.h"
38 #include "google_breakpad/processor/basic_source_line_resolver.h"
39 #include "google_breakpad/processor/code_module.h"
40 #include "google_breakpad/processor/stack_frame.h"
41 #include "google_breakpad/processor/memory_region.h"
42 #include "processor/linked_ptr.h"
43 #include "processor/logging.h"
44 #include "processor/windows_frame_info.h"
45 #include "processor/cfi_frame_info.h"
46
47 namespace {
48
49 using google_breakpad::BasicSourceLineResolver;
50 using google_breakpad::CFIFrameInfo;
51 using google_breakpad::CodeModule;
52 using google_breakpad::MemoryRegion;
53 using google_breakpad::StackFrame;
54 using google_breakpad::WindowsFrameInfo;
55 using google_breakpad::linked_ptr;
56 using google_breakpad::scoped_ptr;
57 using google_breakpad::SymbolParseHelper;
58
59 class TestCodeModule : public CodeModule {
60 public:
TestCodeModule(string code_file)61 TestCodeModule(string code_file) : code_file_(code_file) {}
~TestCodeModule()62 virtual ~TestCodeModule() {}
63
base_address() const64 virtual uint64_t base_address() const { return 0; }
size() const65 virtual uint64_t size() const { return 0xb000; }
code_file() const66 virtual string code_file() const { return code_file_; }
code_identifier() const67 virtual string code_identifier() const { return ""; }
debug_file() const68 virtual string debug_file() const { return ""; }
debug_identifier() const69 virtual string debug_identifier() const { return ""; }
version() const70 virtual string version() const { return ""; }
Copy() const71 virtual CodeModule* Copy() const {
72 return new TestCodeModule(code_file_);
73 }
is_unloaded() const74 virtual bool is_unloaded() const { return false; }
shrink_down_delta() const75 virtual uint64_t shrink_down_delta() const { return 0; }
SetShrinkDownDelta(uint64_t shrink_down_delta)76 virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {}
77
78 private:
79 string code_file_;
80 };
81
82 // A mock memory region object, for use by the STACK CFI tests.
83 class MockMemoryRegion: public MemoryRegion {
GetBase() const84 uint64_t GetBase() const { return 0x10000; }
GetSize() const85 uint32_t GetSize() const { return 0x01000; }
GetMemoryAtAddress(uint64_t address,uint8_t * value) const86 bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
87 *value = address & 0xff;
88 return true;
89 }
GetMemoryAtAddress(uint64_t address,uint16_t * value) const90 bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
91 *value = address & 0xffff;
92 return true;
93 }
GetMemoryAtAddress(uint64_t address,uint32_t * value) const94 bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
95 switch (address) {
96 case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
97 case 0x1000c: *value = 0x878f7524; break; // saved %esi
98 case 0x10010: *value = 0x6312f9a5; break; // saved %edi
99 case 0x10014: *value = 0x10038; break; // caller's %ebp
100 case 0x10018: *value = 0xf6438648; break; // return address
101 default: *value = 0xdeadbeef; break; // junk
102 }
103 return true;
104 }
GetMemoryAtAddress(uint64_t address,uint64_t * value) const105 bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
106 *value = address;
107 return true;
108 }
Print() const109 void Print() const {
110 assert(false);
111 }
112 };
113
114 // Verify that, for every association in ACTUAL, EXPECTED has the same
115 // association. (That is, ACTUAL's associations should be a subset of
116 // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
117 // ".cfa".
VerifyRegisters(const char * file,int line,const CFIFrameInfo::RegisterValueMap<uint32_t> & expected,const CFIFrameInfo::RegisterValueMap<uint32_t> & actual)118 static bool VerifyRegisters(
119 const char *file, int line,
120 const CFIFrameInfo::RegisterValueMap<uint32_t> &expected,
121 const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) {
122 CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
123 a = actual.find(".cfa");
124 if (a == actual.end())
125 return false;
126 a = actual.find(".ra");
127 if (a == actual.end())
128 return false;
129 for (a = actual.begin(); a != actual.end(); a++) {
130 CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e =
131 expected.find(a->first);
132 if (e == expected.end()) {
133 fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
134 file, line, a->first.c_str(), a->second);
135 return false;
136 }
137 if (e->second != a->second) {
138 fprintf(stderr,
139 "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
140 file, line, a->first.c_str(), a->second, e->second);
141 return false;
142 }
143 // Don't complain if this doesn't recover all registers. Although
144 // the DWARF spec says that unmentioned registers are undefined,
145 // GCC uses omission to mean that they are unchanged.
146 }
147 return true;
148 }
149
150
VerifyEmpty(const StackFrame & frame)151 static bool VerifyEmpty(const StackFrame &frame) {
152 if (frame.function_name.empty() &&
153 frame.source_file_name.empty() &&
154 frame.source_line == 0)
155 return true;
156 return false;
157 }
158
ClearSourceLineInfo(StackFrame * frame)159 static void ClearSourceLineInfo(StackFrame *frame) {
160 frame->function_name.clear();
161 frame->module = NULL;
162 frame->source_file_name.clear();
163 frame->source_line = 0;
164 }
165
166 class TestBasicSourceLineResolver : public ::testing::Test {
167 public:
SetUp()168 void SetUp() {
169 testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
170 "/src/processor/testdata";
171 }
172
173 BasicSourceLineResolver resolver;
174 string testdata_dir;
175 };
176
TEST_F(TestBasicSourceLineResolver,TestLoadAndResolve)177 TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
178 {
179 TestCodeModule module1("module1");
180 ASSERT_TRUE(resolver.LoadModule(&module1, testdata_dir + "/module1.out"));
181 ASSERT_TRUE(resolver.HasModule(&module1));
182 TestCodeModule module2("module2");
183 ASSERT_TRUE(resolver.LoadModule(&module2, testdata_dir + "/module2.out"));
184 ASSERT_TRUE(resolver.HasModule(&module2));
185
186
187 StackFrame frame;
188 scoped_ptr<WindowsFrameInfo> windows_frame_info;
189 scoped_ptr<CFIFrameInfo> cfi_frame_info;
190 frame.instruction = 0x1000;
191 frame.module = NULL;
192 resolver.FillSourceLineInfo(&frame);
193 ASSERT_FALSE(frame.module);
194 ASSERT_TRUE(frame.function_name.empty());
195 ASSERT_EQ(frame.function_base, 0U);
196 ASSERT_TRUE(frame.source_file_name.empty());
197 ASSERT_EQ(frame.source_line, 0);
198 ASSERT_EQ(frame.source_line_base, 0U);
199
200 frame.module = &module1;
201 resolver.FillSourceLineInfo(&frame);
202 ASSERT_EQ(frame.function_name, "Function1_1");
203 ASSERT_TRUE(frame.module);
204 ASSERT_EQ(frame.module->code_file(), "module1");
205 ASSERT_EQ(frame.function_base, 0x1000U);
206 ASSERT_EQ(frame.source_file_name, "file1_1.cc");
207 ASSERT_EQ(frame.source_line, 44);
208 ASSERT_EQ(frame.source_line_base, 0x1000U);
209 windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
210 ASSERT_TRUE(windows_frame_info.get());
211 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
212 ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
213 ASSERT_EQ(windows_frame_info->program_string,
214 "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =");
215
216 ClearSourceLineInfo(&frame);
217 frame.instruction = 0x800;
218 frame.module = &module1;
219 resolver.FillSourceLineInfo(&frame);
220 ASSERT_TRUE(VerifyEmpty(frame));
221 windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
222 ASSERT_FALSE(windows_frame_info.get());
223
224 frame.instruction = 0x1280;
225 resolver.FillSourceLineInfo(&frame);
226 ASSERT_EQ(frame.function_name, "Function1_3");
227 ASSERT_TRUE(frame.source_file_name.empty());
228 ASSERT_EQ(frame.source_line, 0);
229 windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
230 ASSERT_TRUE(windows_frame_info.get());
231 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_UNKNOWN);
232 ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
233 ASSERT_TRUE(windows_frame_info->program_string.empty());
234
235 frame.instruction = 0x1380;
236 resolver.FillSourceLineInfo(&frame);
237 ASSERT_EQ(frame.function_name, "Function1_4");
238 ASSERT_TRUE(frame.source_file_name.empty());
239 ASSERT_EQ(frame.source_line, 0);
240 windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
241 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
242 ASSERT_TRUE(windows_frame_info.get());
243 ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
244 ASSERT_FALSE(windows_frame_info->program_string.empty());
245
246 frame.instruction = 0x2000;
247 windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
248 ASSERT_FALSE(windows_frame_info.get());
249
250 // module1 has STACK CFI records covering 3d40..3def;
251 // module2 has STACK CFI records covering 3df0..3e9f;
252 // check that FindCFIFrameInfo doesn't claim to find any outside those ranges.
253 frame.instruction = 0x3d3f;
254 frame.module = &module1;
255 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
256 ASSERT_FALSE(cfi_frame_info.get());
257
258 frame.instruction = 0x3e9f;
259 frame.module = &module1;
260 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
261 ASSERT_FALSE(cfi_frame_info.get());
262
263 CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
264 CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
265 CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers;
266 MockMemoryRegion memory;
267
268 // Regardless of which instruction evaluation takes place at, it
269 // should produce the same values for the caller's registers.
270 expected_caller_registers[".cfa"] = 0x1001c;
271 expected_caller_registers[".ra"] = 0xf6438648;
272 expected_caller_registers["$ebp"] = 0x10038;
273 expected_caller_registers["$ebx"] = 0x98ecadc3;
274 expected_caller_registers["$esi"] = 0x878f7524;
275 expected_caller_registers["$edi"] = 0x6312f9a5;
276
277 frame.instruction = 0x3d40;
278 frame.module = &module1;
279 current_registers.clear();
280 current_registers["$esp"] = 0x10018;
281 current_registers["$ebp"] = 0x10038;
282 current_registers["$ebx"] = 0x98ecadc3;
283 current_registers["$esi"] = 0x878f7524;
284 current_registers["$edi"] = 0x6312f9a5;
285 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
286 ASSERT_TRUE(cfi_frame_info.get());
287 ASSERT_TRUE(cfi_frame_info.get()
288 ->FindCallerRegs<uint32_t>(current_registers, memory,
289 &caller_registers));
290 ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
291 expected_caller_registers, caller_registers));
292
293 frame.instruction = 0x3d41;
294 current_registers["$esp"] = 0x10014;
295 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
296 ASSERT_TRUE(cfi_frame_info.get());
297 ASSERT_TRUE(cfi_frame_info.get()
298 ->FindCallerRegs<uint32_t>(current_registers, memory,
299 &caller_registers));
300 ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
301 expected_caller_registers, caller_registers));
302
303 frame.instruction = 0x3d43;
304 current_registers["$ebp"] = 0x10014;
305 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
306 ASSERT_TRUE(cfi_frame_info.get());
307 ASSERT_TRUE(cfi_frame_info.get()
308 ->FindCallerRegs<uint32_t>(current_registers, memory,
309 &caller_registers));
310 VerifyRegisters(__FILE__, __LINE__,
311 expected_caller_registers, caller_registers);
312
313 frame.instruction = 0x3d54;
314 current_registers["$ebx"] = 0x6864f054U;
315 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
316 ASSERT_TRUE(cfi_frame_info.get());
317 ASSERT_TRUE(cfi_frame_info.get()
318 ->FindCallerRegs<uint32_t>(current_registers, memory,
319 &caller_registers));
320 VerifyRegisters(__FILE__, __LINE__,
321 expected_caller_registers, caller_registers);
322
323 frame.instruction = 0x3d5a;
324 current_registers["$esi"] = 0x6285f79aU;
325 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
326 ASSERT_TRUE(cfi_frame_info.get());
327 ASSERT_TRUE(cfi_frame_info.get()
328 ->FindCallerRegs<uint32_t>(current_registers, memory,
329 &caller_registers));
330 VerifyRegisters(__FILE__, __LINE__,
331 expected_caller_registers, caller_registers);
332
333 frame.instruction = 0x3d84;
334 current_registers["$edi"] = 0x64061449U;
335 cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
336 ASSERT_TRUE(cfi_frame_info.get());
337 ASSERT_TRUE(cfi_frame_info.get()
338 ->FindCallerRegs<uint32_t>(current_registers, memory,
339 &caller_registers));
340 VerifyRegisters(__FILE__, __LINE__,
341 expected_caller_registers, caller_registers);
342
343 frame.instruction = 0x2900;
344 frame.module = &module1;
345 resolver.FillSourceLineInfo(&frame);
346 ASSERT_EQ(frame.function_name, string("PublicSymbol"));
347
348 frame.instruction = 0x4000;
349 frame.module = &module1;
350 resolver.FillSourceLineInfo(&frame);
351 ASSERT_EQ(frame.function_name, string("LargeFunction"));
352
353 frame.instruction = 0x2181;
354 frame.module = &module2;
355 resolver.FillSourceLineInfo(&frame);
356 ASSERT_EQ(frame.function_name, "Function2_2");
357 ASSERT_EQ(frame.function_base, 0x2170U);
358 ASSERT_TRUE(frame.module);
359 ASSERT_EQ(frame.module->code_file(), "module2");
360 ASSERT_EQ(frame.source_file_name, "file2_2.cc");
361 ASSERT_EQ(frame.source_line, 21);
362 ASSERT_EQ(frame.source_line_base, 0x2180U);
363 windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
364 ASSERT_TRUE(windows_frame_info.get());
365 ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
366 ASSERT_EQ(windows_frame_info->prolog_size, 1U);
367
368 frame.instruction = 0x216f;
369 resolver.FillSourceLineInfo(&frame);
370 ASSERT_EQ(frame.function_name, "Public2_1");
371
372 ClearSourceLineInfo(&frame);
373 frame.instruction = 0x219f;
374 frame.module = &module2;
375 resolver.FillSourceLineInfo(&frame);
376 ASSERT_TRUE(frame.function_name.empty());
377
378 frame.instruction = 0x21a0;
379 frame.module = &module2;
380 resolver.FillSourceLineInfo(&frame);
381 ASSERT_EQ(frame.function_name, "Public2_2");
382 }
383
TEST_F(TestBasicSourceLineResolver,TestInvalidLoads)384 TEST_F(TestBasicSourceLineResolver, TestInvalidLoads)
385 {
386 TestCodeModule module3("module3");
387 ASSERT_TRUE(resolver.LoadModule(&module3,
388 testdata_dir + "/module3_bad.out"));
389 ASSERT_TRUE(resolver.HasModule(&module3));
390 ASSERT_TRUE(resolver.IsModuleCorrupt(&module3));
391 TestCodeModule module4("module4");
392 ASSERT_TRUE(resolver.LoadModule(&module4,
393 testdata_dir + "/module4_bad.out"));
394 ASSERT_TRUE(resolver.HasModule(&module4));
395 ASSERT_TRUE(resolver.IsModuleCorrupt(&module4));
396 TestCodeModule module5("module5");
397 ASSERT_FALSE(resolver.LoadModule(&module5,
398 testdata_dir + "/invalid-filename"));
399 ASSERT_FALSE(resolver.HasModule(&module5));
400 TestCodeModule invalidmodule("invalid-module");
401 ASSERT_FALSE(resolver.HasModule(&invalidmodule));
402 }
403
TEST_F(TestBasicSourceLineResolver,TestUnload)404 TEST_F(TestBasicSourceLineResolver, TestUnload)
405 {
406 TestCodeModule module1("module1");
407 ASSERT_FALSE(resolver.HasModule(&module1));
408 ASSERT_TRUE(resolver.LoadModule(&module1, testdata_dir + "/module1.out"));
409 ASSERT_TRUE(resolver.HasModule(&module1));
410 resolver.UnloadModule(&module1);
411 ASSERT_FALSE(resolver.HasModule(&module1));
412 ASSERT_TRUE(resolver.LoadModule(&module1, testdata_dir + "/module1.out"));
413 ASSERT_TRUE(resolver.HasModule(&module1));
414 }
415
416 // Test parsing of valid FILE lines. The format is:
417 // FILE <id> <filename>
TEST(SymbolParseHelper,ParseFileValid)418 TEST(SymbolParseHelper, ParseFileValid) {
419 long index;
420 char *filename;
421
422 char kTestLine[] = "FILE 1 file name";
423 ASSERT_TRUE(SymbolParseHelper::ParseFile(kTestLine, &index, &filename));
424 EXPECT_EQ(1, index);
425 EXPECT_EQ("file name", string(filename));
426
427 // 0 is a valid index.
428 char kTestLine1[] = "FILE 0 file name";
429 ASSERT_TRUE(SymbolParseHelper::ParseFile(kTestLine1, &index, &filename));
430 EXPECT_EQ(0, index);
431 EXPECT_EQ("file name", string(filename));
432 }
433
434 // Test parsing of invalid FILE lines. The format is:
435 // FILE <id> <filename>
TEST(SymbolParseHelper,ParseFileInvalid)436 TEST(SymbolParseHelper, ParseFileInvalid) {
437 long index;
438 char *filename;
439
440 // Test missing file name.
441 char kTestLine[] = "FILE 1 ";
442 ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine, &index, &filename));
443
444 // Test bad index.
445 char kTestLine1[] = "FILE x1 file name";
446 ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine1, &index, &filename));
447
448 // Test large index.
449 char kTestLine2[] = "FILE 123123123123123123123123 file name";
450 ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine2, &index, &filename));
451
452 // Test negative index.
453 char kTestLine3[] = "FILE -2 file name";
454 ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine3, &index, &filename));
455 }
456
457 // Test parsing of valid FUNC lines. The format is:
458 // FUNC [<multiple>] <address> <size> <stack_param_size> <name>
TEST(SymbolParseHelper,ParseFunctionValid)459 TEST(SymbolParseHelper, ParseFunctionValid) {
460 bool multiple;
461 uint64_t address;
462 uint64_t size;
463 long stack_param_size;
464 char *name;
465
466 char kTestLine[] = "FUNC 1 2 3 function name";
467 ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine, &multiple, &address,
468 &size, &stack_param_size,
469 &name));
470 EXPECT_FALSE(multiple);
471 EXPECT_EQ(1ULL, address);
472 EXPECT_EQ(2ULL, size);
473 EXPECT_EQ(3, stack_param_size);
474 EXPECT_EQ("function name", string(name));
475
476 // Test hex address, size, and param size.
477 char kTestLine1[] = "FUNC a1 a2 a3 function name";
478 ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine1, &multiple, &address,
479 &size, &stack_param_size,
480 &name));
481 EXPECT_FALSE(multiple);
482 EXPECT_EQ(0xa1ULL, address);
483 EXPECT_EQ(0xa2ULL, size);
484 EXPECT_EQ(0xa3, stack_param_size);
485 EXPECT_EQ("function name", string(name));
486
487 char kTestLine2[] = "FUNC 0 0 0 function name";
488 ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine2, &multiple, &address,
489 &size, &stack_param_size,
490 &name));
491 EXPECT_FALSE(multiple);
492 EXPECT_EQ(0ULL, address);
493 EXPECT_EQ(0ULL, size);
494 EXPECT_EQ(0, stack_param_size);
495 EXPECT_EQ("function name", string(name));
496
497 // Test optional multiple field.
498 char kTestLine3[] = "FUNC m a1 a2 a3 function name";
499 ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine3, &multiple, &address,
500 &size, &stack_param_size,
501 &name));
502 EXPECT_TRUE(multiple);
503 EXPECT_EQ(0xa1ULL, address);
504 EXPECT_EQ(0xa2ULL, size);
505 EXPECT_EQ(0xa3, stack_param_size);
506 EXPECT_EQ("function name", string(name));
507 }
508
509 // Test parsing of invalid FUNC lines. The format is:
510 // FUNC [<multiple>] <address> <size> <stack_param_size> <name>
TEST(SymbolParseHelper,ParseFunctionInvalid)511 TEST(SymbolParseHelper, ParseFunctionInvalid) {
512 bool multiple;
513 uint64_t address;
514 uint64_t size;
515 long stack_param_size;
516 char *name;
517
518 // Test missing function name.
519 char kTestLine[] = "FUNC 1 2 3 ";
520 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine, &multiple, &address,
521 &size, &stack_param_size,
522 &name));
523 // Test bad address.
524 char kTestLine1[] = "FUNC 1z 2 3 function name";
525 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine1, &multiple, &address,
526 &size, &stack_param_size,
527 &name));
528 // Test large address.
529 char kTestLine2[] = "FUNC 123123123123123123123123123 2 3 function name";
530 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine2, &multiple, &address,
531 &size, &stack_param_size,
532 &name));
533 // Test bad size.
534 char kTestLine3[] = "FUNC 1 z2 3 function name";
535 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine3, &multiple, &address,
536 &size, &stack_param_size,
537 &name));
538 // Test large size.
539 char kTestLine4[] = "FUNC 1 231231231231231231231231232 3 function name";
540 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine4, &multiple, &address,
541 &size, &stack_param_size,
542 &name));
543 // Test bad param size.
544 char kTestLine5[] = "FUNC 1 2 3z function name";
545 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine5, &multiple, &address,
546 &size, &stack_param_size,
547 &name));
548 // Test large param size.
549 char kTestLine6[] = "FUNC 1 2 312312312312312312312312323 function name";
550 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine6, &multiple, &address,
551 &size, &stack_param_size,
552 &name));
553 // Negative param size.
554 char kTestLine7[] = "FUNC 1 2 -5 function name";
555 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine7, &multiple, &address,
556 &size, &stack_param_size,
557 &name));
558 // Test invalid optional field.
559 char kTestLine8[] = "FUNC x 1 2 5 function name";
560 ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine8, &multiple, &address,
561 &size, &stack_param_size,
562 &name));
563 }
564
565 // Test parsing of valid lines. The format is:
566 // <address> <size> <line number> <source file id>
TEST(SymbolParseHelper,ParseLineValid)567 TEST(SymbolParseHelper, ParseLineValid) {
568 uint64_t address;
569 uint64_t size;
570 long line_number;
571 long source_file;
572
573 char kTestLine[] = "1 2 3 4";
574 ASSERT_TRUE(SymbolParseHelper::ParseLine(kTestLine, &address, &size,
575 &line_number, &source_file));
576 EXPECT_EQ(1ULL, address);
577 EXPECT_EQ(2ULL, size);
578 EXPECT_EQ(3, line_number);
579 EXPECT_EQ(4, source_file);
580
581 // Test hex size and address.
582 char kTestLine1[] = "a1 a2 3 4 // some comment";
583 ASSERT_TRUE(SymbolParseHelper::ParseLine(kTestLine1, &address, &size,
584 &line_number, &source_file));
585 EXPECT_EQ(0xa1ULL, address);
586 EXPECT_EQ(0xa2ULL, size);
587 EXPECT_EQ(3, line_number);
588 EXPECT_EQ(4, source_file);
589
590 // 0 is a valid line number.
591 char kTestLine2[] = "a1 a2 0 4 // some comment";
592 ASSERT_TRUE(SymbolParseHelper::ParseLine(kTestLine2, &address, &size,
593 &line_number, &source_file));
594 EXPECT_EQ(0xa1ULL, address);
595 EXPECT_EQ(0xa2ULL, size);
596 EXPECT_EQ(0, line_number);
597 EXPECT_EQ(4, source_file);
598 }
599
600 // Test parsing of invalid lines. The format is:
601 // <address> <size> <line number> <source file id>
TEST(SymbolParseHelper,ParseLineInvalid)602 TEST(SymbolParseHelper, ParseLineInvalid) {
603 uint64_t address;
604 uint64_t size;
605 long line_number;
606 long source_file;
607
608 // Test missing source file id.
609 char kTestLine[] = "1 2 3";
610 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine, &address, &size,
611 &line_number, &source_file));
612 // Test bad address.
613 char kTestLine1[] = "1z 2 3 4";
614 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine1, &address, &size,
615 &line_number, &source_file));
616 // Test large address.
617 char kTestLine2[] = "123123123123123123123123 2 3 4";
618 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine2, &address, &size,
619 &line_number, &source_file));
620 // Test bad size.
621 char kTestLine3[] = "1 z2 3 4";
622 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine3, &address, &size,
623 &line_number, &source_file));
624 // Test large size.
625 char kTestLine4[] = "1 123123123123123123123123 3 4";
626 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine4, &address, &size,
627 &line_number, &source_file));
628 // Test bad line number.
629 char kTestLine5[] = "1 2 z3 4";
630 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine5, &address, &size,
631 &line_number, &source_file));
632 // Test negative line number.
633 char kTestLine6[] = "1 2 -1 4";
634 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine6, &address, &size,
635 &line_number, &source_file));
636 // Test large line number.
637 char kTestLine7[] = "1 2 123123123123123123123 4";
638 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine7, &address, &size,
639 &line_number, &source_file));
640 // Test bad source file id.
641 char kTestLine8[] = "1 2 3 f";
642 ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine8, &address, &size,
643 &line_number, &source_file));
644 }
645
646 // Test parsing of valid PUBLIC lines. The format is:
647 // PUBLIC [<multiple>] <address> <stack_param_size> <name>
TEST(SymbolParseHelper,ParsePublicSymbolValid)648 TEST(SymbolParseHelper, ParsePublicSymbolValid) {
649 bool multiple;
650 uint64_t address;
651 long stack_param_size;
652 char *name;
653
654 char kTestLine[] = "PUBLIC 1 2 3";
655 ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine, &multiple,
656 &address, &stack_param_size,
657 &name));
658 EXPECT_FALSE(multiple);
659 EXPECT_EQ(1ULL, address);
660 EXPECT_EQ(2, stack_param_size);
661 EXPECT_EQ("3", string(name));
662
663 // Test hex size and address.
664 char kTestLine1[] = "PUBLIC a1 a2 function name";
665 ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine1, &multiple,
666 &address, &stack_param_size,
667 &name));
668 EXPECT_FALSE(multiple);
669 EXPECT_EQ(0xa1ULL, address);
670 EXPECT_EQ(0xa2, stack_param_size);
671 EXPECT_EQ("function name", string(name));
672
673 // Test 0 is a valid address.
674 char kTestLine2[] = "PUBLIC 0 a2 function name";
675 ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine2, &multiple,
676 &address, &stack_param_size,
677 &name));
678 EXPECT_FALSE(multiple);
679 EXPECT_EQ(0ULL, address);
680 EXPECT_EQ(0xa2, stack_param_size);
681 EXPECT_EQ("function name", string(name));
682
683 // Test optional multiple field.
684 char kTestLine3[] = "PUBLIC m a1 a2 function name";
685 ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine3, &multiple,
686 &address, &stack_param_size,
687 &name));
688 EXPECT_TRUE(multiple);
689 EXPECT_EQ(0xa1ULL, address);
690 EXPECT_EQ(0xa2, stack_param_size);
691 EXPECT_EQ("function name", string(name));
692 }
693
694 // Test parsing of invalid PUBLIC lines. The format is:
695 // PUBLIC [<multiple>] <address> <stack_param_size> <name>
TEST(SymbolParseHelper,ParsePublicSymbolInvalid)696 TEST(SymbolParseHelper, ParsePublicSymbolInvalid) {
697 bool multiple;
698 uint64_t address;
699 long stack_param_size;
700 char *name;
701
702 // Test missing source function name.
703 char kTestLine[] = "PUBLIC 1 2 ";
704 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine, &multiple,
705 &address, &stack_param_size,
706 &name));
707 // Test bad address.
708 char kTestLine1[] = "PUBLIC 1z 2 3";
709 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine1, &multiple,
710 &address, &stack_param_size,
711 &name));
712 // Test large address.
713 char kTestLine2[] = "PUBLIC 123123123123123123123123 2 3";
714 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine2, &multiple,
715 &address, &stack_param_size,
716 &name));
717 // Test bad param stack size.
718 char kTestLine3[] = "PUBLIC 1 z2 3";
719 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine3, &multiple,
720 &address, &stack_param_size,
721 &name));
722 // Test large param stack size.
723 char kTestLine4[] = "PUBLIC 1 123123123123123123123123123 3";
724 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine4, &multiple,
725 &address, &stack_param_size,
726 &name));
727 // Test negative param stack size.
728 char kTestLine5[] = "PUBLIC 1 -5 3";
729 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine5, &multiple,
730 &address, &stack_param_size,
731 &name));
732 // Test invalid optional field.
733 char kTestLine6[] = "PUBLIC x 1 5 3";
734 ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine6, &multiple,
735 &address, &stack_param_size,
736 &name));
737 }
738
739 } // namespace
740
main(int argc,char * argv[])741 int main(int argc, char *argv[]) {
742 ::testing::InitGoogleTest(&argc, argv);
743 return RUN_ALL_TESTS();
744 }
745