• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 // Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
31 
32 // dump_symbols_unittest.cc:
33 // Unittests for google_breakpad::DumpSymbols
34 
35 #include <elf.h>
36 #include <link.h>
37 #include <stdio.h>
38 
39 #include <sstream>
40 #include <vector>
41 
42 #include "breakpad_googletest_includes.h"
43 #include "common/linux/elf_gnu_compat.h"
44 #include "common/linux/elfutils.h"
45 #include "common/linux/dump_symbols.h"
46 #include "common/linux/synth_elf.h"
47 #include "common/module.h"
48 #include "common/using_std_string.h"
49 
50 namespace google_breakpad {
51 
52 bool ReadSymbolDataInternal(const uint8_t* obj_file,
53                             const string& obj_filename,
54                             const string& obj_os,
55                             const std::vector<string>& debug_dir,
56                             const DumpOptions& options,
57                             Module** module);
58 
59 using google_breakpad::synth_elf::ELF;
60 using google_breakpad::synth_elf::Notes;
61 using google_breakpad::synth_elf::StringTable;
62 using google_breakpad::synth_elf::SymbolTable;
63 using google_breakpad::test_assembler::kLittleEndian;
64 using google_breakpad::test_assembler::Section;
65 using std::stringstream;
66 using std::vector;
67 using ::testing::Test;
68 using ::testing::Types;
69 
70 template<typename ElfClass>
71 class DumpSymbols : public Test {
72  public:
GetElfContents(ELF & elf)73   void GetElfContents(ELF& elf) {
74     string contents;
75     ASSERT_TRUE(elf.GetContents(&contents));
76     ASSERT_LT(0U, contents.size());
77 
78     elfdata_v.clear();
79     elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end());
80     elfdata = &elfdata_v[0];
81   }
82 
83   vector<uint8_t> elfdata_v;
84   uint8_t* elfdata;
85 };
86 
87 typedef Types<ElfClass32, ElfClass64> ElfClasses;
88 
89 TYPED_TEST_SUITE(DumpSymbols, ElfClasses);
90 
TYPED_TEST(DumpSymbols,Invalid)91 TYPED_TEST(DumpSymbols, Invalid) {
92   Elf32_Ehdr header;
93   memset(&header, 0, sizeof(header));
94   Module* module;
95   DumpOptions options(ALL_SYMBOL_DATA, true);
96   EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
97                                       "foo",
98                                       "Linux",
99                                       vector<string>(),
100                                       options,
101                                       &module));
102 }
103 
TYPED_TEST(DumpSymbols,SimplePublic)104 TYPED_TEST(DumpSymbols, SimplePublic) {
105   ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
106   // Zero out text section for simplicity.
107   Section text(kLittleEndian);
108   text.Append(4096, 0);
109   elf.AddSection(".text", text, SHT_PROGBITS);
110 
111   // Add a public symbol.
112   StringTable table(kLittleEndian);
113   SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table);
114   syms.AddSymbol("superfunc",
115                    (typename TypeParam::Addr)0x1000,
116                    (typename TypeParam::Addr)0x10,
117                  // ELF32_ST_INFO works for 32-or 64-bit.
118                  ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
119                  SHN_UNDEF + 1);
120   int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
121   elf.AddSection(".dynsym", syms,
122                  SHT_DYNSYM,          // type
123                  SHF_ALLOC,           // flags
124                  0,                   // addr
125                  index,               // link
126                  sizeof(typename TypeParam::Sym));  // entsize
127 
128   elf.Finish();
129   this->GetElfContents(elf);
130 
131   Module* module;
132   DumpOptions options(ALL_SYMBOL_DATA, true);
133   EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
134                                      "foo",
135                                      "Linux",
136                                      vector<string>(),
137                                      options,
138                                      &module));
139 
140   stringstream s;
141   module->Write(s, ALL_SYMBOL_DATA);
142   const string expected =
143     string("MODULE Linux ") + TypeParam::kMachineName
144     + " 000000000000000000000000000000000 foo\n"
145     "INFO CODE_ID 00000000000000000000000000000000\n"
146     "PUBLIC 1000 0 superfunc\n";
147   EXPECT_EQ(expected, s.str());
148   delete module;
149 }
150 
TYPED_TEST(DumpSymbols,SimpleBuildID)151 TYPED_TEST(DumpSymbols, SimpleBuildID) {
152   ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
153   // Zero out text section for simplicity.
154   Section text(kLittleEndian);
155   text.Append(4096, 0);
156   elf.AddSection(".text", text, SHT_PROGBITS);
157 
158   // Add a Build ID
159   const uint8_t kExpectedIdentifierBytes[] =
160     {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
161      0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
162      0x10, 0x11, 0x12, 0x13};
163   Notes notes(kLittleEndian);
164   notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
165                 sizeof(kExpectedIdentifierBytes));
166   elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
167 
168   // Add a public symbol.
169   StringTable table(kLittleEndian);
170   SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table);
171   syms.AddSymbol("superfunc",
172                    (typename TypeParam::Addr)0x1000,
173                    (typename TypeParam::Addr)0x10,
174                  // ELF32_ST_INFO works for 32-or 64-bit.
175                  ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
176                  SHN_UNDEF + 1);
177   int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
178   elf.AddSection(".dynsym", syms,
179                  SHT_DYNSYM,          // type
180                  SHF_ALLOC,           // flags
181                  0,                   // addr
182                  index,               // link
183                  sizeof(typename TypeParam::Sym));  // entsize
184 
185   elf.Finish();
186   this->GetElfContents(elf);
187 
188   Module* module;
189   DumpOptions options(ALL_SYMBOL_DATA, true);
190   EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
191                                      "foo",
192                                      "Linux",
193                                      vector<string>(),
194                                      options,
195                                      &module));
196 
197   stringstream s;
198   module->Write(s, ALL_SYMBOL_DATA);
199   const string expected =
200     string("MODULE Linux ") + TypeParam::kMachineName
201     + " 030201000504070608090A0B0C0D0E0F0 foo\n"
202     "INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n"
203     "PUBLIC 1000 0 superfunc\n";
204   EXPECT_EQ(expected, s.str());
205   delete module;
206 }
207 
208 }  // namespace google_breakpad
209