• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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