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