dump_symbols_unittest.cc
1 // Copyright 2011 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // Original author: Ted Mielczarek <ted.mielczarek@gmail.com> 30 31 // dump_symbols_unittest.cc: 32 // Unittests for google_breakpad::DumpSymbols 33 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> // Must come first 36 #endif 37 38 #include <elf.h> 39 #include <link.h> 40 #include <stdio.h> 41 42 #include <sstream> 43 #include <vector> 44 45 #include "breakpad_googletest_includes.h" 46 #include "common/linux/elf_gnu_compat.h" 47 #include "common/linux/elfutils.h" 48 #include "common/linux/dump_symbols.h" 49 #include "common/linux/synth_elf.h" 50 #include "common/module.h" 51 #include "common/using_std_string.h" 52 53 namespace google_breakpad { 54 55 bool ReadSymbolDataInternal(const uint8_t* obj_file, 56 const string& obj_filename, 57 const string& obj_os, 58 const std::vector<string>& debug_dir, 59 const DumpOptions& options, 60 Module** module); 61 62 using google_breakpad::synth_elf::ELF; 63 using google_breakpad::synth_elf::Notes; 64 using google_breakpad::synth_elf::StringTable; 65 using google_breakpad::synth_elf::SymbolTable; 66 using google_breakpad::test_assembler::kLittleEndian; 67 using google_breakpad::test_assembler::Section; 68 using std::stringstream; 69 using std::vector; 70 using ::testing::Test; 71 using ::testing::Types; 72 73 template<typename ElfClass> 74 class DumpSymbols : public Test { 75 public: 76 void GetElfContents(ELF& elf) { 77 string contents; 78 ASSERT_TRUE(elf.GetContents(&contents)); 79 ASSERT_LT(0U, contents.size()); 80 81 elfdata_v.clear(); 82 elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); 83 elfdata = &elfdata_v[0]; 84 } 85 86 vector<uint8_t> elfdata_v; 87 uint8_t* elfdata; 88 }; 89 90 typedef Types<ElfClass32, ElfClass64> ElfClasses; 91 92 TYPED_TEST_SUITE(DumpSymbols, ElfClasses); 93 94 TYPED_TEST(DumpSymbols, Invalid) { 95 Elf32_Ehdr header; 96 memset(&header, 0, sizeof(header)); 97 Module* module; 98 DumpOptions options(ALL_SYMBOL_DATA, true, false); 99 EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header), 100 "foo", 101 "Linux", 102 vector<string>(), 103 options, 104 &module)); 105 } 106 107 TYPED_TEST(DumpSymbols, SimplePublic) { 108 ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); 109 // Zero out text section for simplicity. 110 Section text(kLittleEndian); 111 text.Append(4096, 0); 112 elf.AddSection(".text", text, SHT_PROGBITS); 113 114 // Add a public symbol. 115 StringTable table(kLittleEndian); 116 SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); 117 syms.AddSymbol("superfunc", 118 (typename TypeParam::Addr)0x1000, 119 (typename TypeParam::Addr)0x10, 120 // ELF32_ST_INFO works for 32-or 64-bit. 121 ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), 122 SHN_UNDEF + 1); 123 int index = elf.AddSection(".dynstr", table, SHT_STRTAB); 124 elf.AddSection(".dynsym", syms, 125 SHT_DYNSYM, // type 126 SHF_ALLOC, // flags 127 0, // addr 128 index, // link 129 sizeof(typename TypeParam::Sym)); // entsize 130 131 elf.Finish(); 132 this->GetElfContents(elf); 133 134 Module* module; 135 DumpOptions options(ALL_SYMBOL_DATA, true, false); 136 EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, 137 "foo", 138 "Linux", 139 vector<string>(), 140 options, 141 &module)); 142 143 stringstream s; 144 module->Write(s, ALL_SYMBOL_DATA); 145 const string expected = 146 string("MODULE Linux ") + TypeParam::kMachineName 147 + " 000000000000000000000000000000000 foo\n" 148 "INFO CODE_ID 00000000000000000000000000000000\n" 149 "PUBLIC 1000 0 superfunc\n"; 150 EXPECT_EQ(expected, s.str()); 151 delete module; 152 } 153 154 TYPED_TEST(DumpSymbols, SimpleBuildID) { 155 ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); 156 // Zero out text section for simplicity. 157 Section text(kLittleEndian); 158 text.Append(4096, 0); 159 elf.AddSection(".text", text, SHT_PROGBITS); 160 161 // Add a Build ID 162 const uint8_t kExpectedIdentifierBytes[] = 163 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 164 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 165 0x10, 0x11, 0x12, 0x13}; 166 Notes notes(kLittleEndian); 167 notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, 168 sizeof(kExpectedIdentifierBytes)); 169 elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); 170 171 // Add a public symbol. 172 StringTable table(kLittleEndian); 173 SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); 174 syms.AddSymbol("superfunc", 175 (typename TypeParam::Addr)0x1000, 176 (typename TypeParam::Addr)0x10, 177 // ELF32_ST_INFO works for 32-or 64-bit. 178 ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), 179 SHN_UNDEF + 1); 180 int index = elf.AddSection(".dynstr", table, SHT_STRTAB); 181 elf.AddSection(".dynsym", syms, 182 SHT_DYNSYM, // type 183 SHF_ALLOC, // flags 184 0, // addr 185 index, // link 186 sizeof(typename TypeParam::Sym)); // entsize 187 188 elf.Finish(); 189 this->GetElfContents(elf); 190 191 Module* module; 192 DumpOptions options(ALL_SYMBOL_DATA, true, false); 193 EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, 194 "foo", 195 "Linux", 196 vector<string>(), 197 options, 198 &module)); 199 200 stringstream s; 201 module->Write(s, ALL_SYMBOL_DATA); 202 const string expected = 203 string("MODULE Linux ") + TypeParam::kMachineName 204 + " 030201000504070608090A0B0C0D0E0F0 foo\n" 205 "INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n" 206 "PUBLIC 1000 0 superfunc\n"; 207 EXPECT_EQ(expected, s.str()); 208 delete module; 209 } 210 211 } // namespace google_breakpad