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