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
47namespace {
48
49using google_breakpad::BasicSourceLineResolver;
50using google_breakpad::CFIFrameInfo;
51using google_breakpad::CodeModule;
52using google_breakpad::MemoryRegion;
53using google_breakpad::StackFrame;
54using google_breakpad::WindowsFrameInfo;
55using google_breakpad::linked_ptr;
56using google_breakpad::scoped_ptr;
57using google_breakpad::SymbolParseHelper;
58
59class TestCodeModule : public CodeModule {
60 public:
61  TestCodeModule(string code_file) : code_file_(code_file) {}
62  virtual ~TestCodeModule() {}
63
64  virtual uint64_t base_address() const { return 0; }
65  virtual uint64_t size() const { return 0xb000; }
66  virtual string code_file() const { return code_file_; }
67  virtual string code_identifier() const { return ""; }
68  virtual string debug_file() const { return ""; }
69  virtual string debug_identifier() const { return ""; }
70  virtual string version() const { return ""; }
71  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.
80class MockMemoryRegion: public MemoryRegion {
81  uint64_t GetBase() const { return 0x10000; }
82  uint32_t GetSize() const { return 0x01000; }
83  bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
84    *value = address & 0xff;
85    return true;
86  }
87  bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
88    *value = address & 0xffff;
89    return true;
90  }
91  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  }
102  bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
103    *value = address;
104    return true;
105  }
106  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".
115static 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
148static 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
156static 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
163class TestBasicSourceLineResolver : public ::testing::Test {
164public:
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
174TEST_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
381TEST_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
401TEST_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>
415TEST(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>
433TEST(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>
456TEST(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>
490TEST(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>
532TEST(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>
567TEST(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>
613TEST(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>
644TEST(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
677int main(int argc, char *argv[]) {
678  ::testing::InitGoogleTest(&argc, argv);
679  return RUN_ALL_TESTS();
680}
681