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