/thirdparty/breakpad/common/linux/file_id_unittest.cc
C++ | 284 lines | 202 code | 42 blank | 40 comment | 3 complexity | 4b706529fa5ca7e2c64e9d51d603c961 MD5 | raw file
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// Unit tests for FileID 31 32#include <elf.h> 33#include <stdlib.h> 34 35#include "common/linux/file_id.h" 36#include "common/linux/safe_readlink.h" 37#include "common/linux/synth_elf.h" 38#include "common/test_assembler.h" 39#include "common/tests/auto_tempdir.h" 40#include "breakpad_googletest_includes.h" 41 42using namespace google_breakpad; 43using google_breakpad::SafeReadLink; 44using google_breakpad::synth_elf::BuildIDNote; 45using google_breakpad::synth_elf::ELF; 46using google_breakpad::test_assembler::kLittleEndian; 47using google_breakpad::test_assembler::Section; 48 49namespace { 50 51// Simply calling Section::Append(size, byte) produces a uninteresting pattern 52// that tends to get hashed to 0000...0000. This populates the section with 53// data to produce better hashes. 54void PopulateSection(Section* section, int size, int prime_number) { 55 for (int i = 0; i < size; i++) 56 section->Append(1, (i % prime_number) % 256); 57} 58 59} // namespace 60 61TEST(FileIDStripTest, StripSelf) { 62 // Calculate the File ID of this binary using 63 // FileID::ElfFileIdentifier, then make a copy of this binary, 64 // strip it, and ensure that the result is the same. 65 char exe_name[PATH_MAX]; 66 ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); 67 68 // copy our binary to a temp file, and strip it 69 AutoTempDir temp_dir; 70 std::string templ = temp_dir.path() + "/file-id-unittest"; 71 char cmdline[4096]; 72 sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str()); 73 ASSERT_EQ(system(cmdline), 0); 74 sprintf(cmdline, "strip \"%s\"", templ.c_str()); 75 ASSERT_EQ(system(cmdline), 0); 76 77 uint8_t identifier1[sizeof(MDGUID)]; 78 uint8_t identifier2[sizeof(MDGUID)]; 79 FileID fileid1(exe_name); 80 EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1)); 81 FileID fileid2(templ.c_str()); 82 EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2)); 83 char identifier_string1[37]; 84 char identifier_string2[37]; 85 FileID::ConvertIdentifierToString(identifier1, identifier_string1, 86 37); 87 FileID::ConvertIdentifierToString(identifier2, identifier_string2, 88 37); 89 EXPECT_STREQ(identifier_string1, identifier_string2); 90} 91 92class FileIDTest : public testing::Test { 93public: 94 void GetElfContents(ELF& elf) { 95 string contents; 96 ASSERT_TRUE(elf.GetContents(&contents)); 97 ASSERT_LT(0, contents.size()); 98 99 elfdata_v.clear(); 100 elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); 101 elfdata = &elfdata_v[0]; 102 } 103 104 vector<uint8_t> elfdata_v; 105 uint8_t* elfdata; 106}; 107 108TEST_F(FileIDTest, ElfClass) { 109 uint8_t identifier[sizeof(MDGUID)]; 110 const char expected_identifier_string[] = 111 "80808080-8080-0000-0000-008080808080"; 112 char identifier_string[sizeof(expected_identifier_string)]; 113 const size_t kTextSectionSize = 128; 114 115 ELF elf32(EM_386, ELFCLASS32, kLittleEndian); 116 Section text32(kLittleEndian); 117 for (size_t i = 0; i < kTextSectionSize; ++i) { 118 text32.D8(i * 3); 119 } 120 elf32.AddSection(".text", text32, SHT_PROGBITS); 121 elf32.Finish(); 122 GetElfContents(elf32); 123 124 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier)); 125 126 FileID::ConvertIdentifierToString(identifier, identifier_string, 127 sizeof(identifier_string)); 128 EXPECT_STREQ(expected_identifier_string, identifier_string); 129 130 memset(identifier, 0, sizeof(identifier)); 131 memset(identifier_string, 0, sizeof(identifier_string)); 132 133 ELF elf64(EM_X86_64, ELFCLASS64, kLittleEndian); 134 Section text64(kLittleEndian); 135 for (size_t i = 0; i < kTextSectionSize; ++i) { 136 text64.D8(i * 3); 137 } 138 elf64.AddSection(".text", text64, SHT_PROGBITS); 139 elf64.Finish(); 140 GetElfContents(elf64); 141 142 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier)); 143 144 FileID::ConvertIdentifierToString(identifier, identifier_string, 145 sizeof(identifier_string)); 146 EXPECT_STREQ(expected_identifier_string, identifier_string); 147} 148 149TEST_F(FileIDTest, BuildID) { 150 const uint8_t kExpectedIdentifier[sizeof(MDGUID)] = 151 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 152 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; 153 char expected_identifier_string[] = 154 "00000000-0000-0000-0000-000000000000"; 155 FileID::ConvertIdentifierToString(kExpectedIdentifier, 156 expected_identifier_string, 157 sizeof(expected_identifier_string)); 158 159 uint8_t identifier[sizeof(MDGUID)]; 160 char identifier_string[sizeof(expected_identifier_string)]; 161 162 ELF elf32(EM_386, ELFCLASS32, kLittleEndian); 163 Section text(kLittleEndian); 164 text.Append(4096, 0); 165 elf32.AddSection(".text", text, SHT_PROGBITS); 166 BuildIDNote::AppendSection(elf32, 167 kExpectedIdentifier, 168 sizeof(kExpectedIdentifier)); 169 elf32.Finish(); 170 GetElfContents(elf32); 171 172 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier)); 173 174 FileID::ConvertIdentifierToString(identifier, identifier_string, 175 sizeof(identifier_string)); 176 EXPECT_STREQ(expected_identifier_string, identifier_string); 177 178 memset(identifier, 0, sizeof(identifier)); 179 memset(identifier_string, 0, sizeof(identifier_string)); 180 181 ELF elf64(EM_X86_64, ELFCLASS64, kLittleEndian); 182 // Re-use empty text section from previous test 183 elf64.AddSection(".text", text, SHT_PROGBITS); 184 BuildIDNote::AppendSection(elf64, 185 kExpectedIdentifier, 186 sizeof(kExpectedIdentifier)); 187 elf64.Finish(); 188 GetElfContents(elf64); 189 190 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier)); 191 192 FileID::ConvertIdentifierToString(identifier, identifier_string, 193 sizeof(identifier_string)); 194 EXPECT_STREQ(expected_identifier_string, identifier_string); 195} 196 197// Test to make sure two files with different text sections produce 198// different hashes when not using a build id. 199TEST_F(FileIDTest, UniqueHashes32) { 200 char identifier_string_1[] = 201 "00000000-0000-0000-0000-000000000000"; 202 char identifier_string_2[] = 203 "00000000-0000-0000-0000-000000000000"; 204 uint8_t identifier_1[sizeof(MDGUID)]; 205 uint8_t identifier_2[sizeof(MDGUID)]; 206 207 { 208 ELF elf1(EM_386, ELFCLASS32, kLittleEndian); 209 Section foo_1(kLittleEndian); 210 PopulateSection(&foo_1, 32, 5); 211 elf1.AddSection(".foo", foo_1, SHT_PROGBITS); 212 Section text_1(kLittleEndian); 213 PopulateSection(&text_1, 4096, 17); 214 elf1.AddSection(".text", text_1, SHT_PROGBITS); 215 elf1.Finish(); 216 GetElfContents(elf1); 217 } 218 219 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_1)); 220 FileID::ConvertIdentifierToString(identifier_1, identifier_string_1, 221 sizeof(identifier_string_1)); 222 223 { 224 ELF elf2(EM_386, ELFCLASS32, kLittleEndian); 225 Section text_2(kLittleEndian); 226 Section foo_2(kLittleEndian); 227 PopulateSection(&foo_2, 32, 5); 228 elf2.AddSection(".foo", foo_2, SHT_PROGBITS); 229 PopulateSection(&text_2, 4096, 31); 230 elf2.AddSection(".text", text_2, SHT_PROGBITS); 231 elf2.Finish(); 232 GetElfContents(elf2); 233 } 234 235 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_2)); 236 FileID::ConvertIdentifierToString(identifier_2, identifier_string_2, 237 sizeof(identifier_string_2)); 238 239 EXPECT_STRNE(identifier_string_1, identifier_string_2); 240} 241 242// Same as UniqueHashes32, for x86-64. 243TEST_F(FileIDTest, UniqueHashes64) { 244 char identifier_string_1[] = 245 "00000000-0000-0000-0000-000000000000"; 246 char identifier_string_2[] = 247 "00000000-0000-0000-0000-000000000000"; 248 uint8_t identifier_1[sizeof(MDGUID)]; 249 uint8_t identifier_2[sizeof(MDGUID)]; 250 251 { 252 ELF elf1(EM_X86_64, ELFCLASS64, kLittleEndian); 253 Section foo_1(kLittleEndian); 254 PopulateSection(&foo_1, 32, 5); 255 elf1.AddSection(".foo", foo_1, SHT_PROGBITS); 256 Section text_1(kLittleEndian); 257 PopulateSection(&text_1, 4096, 17); 258 elf1.AddSection(".text", text_1, SHT_PROGBITS); 259 elf1.Finish(); 260 GetElfContents(elf1); 261 } 262 263 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_1)); 264 FileID::ConvertIdentifierToString(identifier_1, identifier_string_1, 265 sizeof(identifier_string_1)); 266 267 { 268 ELF elf2(EM_X86_64, ELFCLASS64, kLittleEndian); 269 Section text_2(kLittleEndian); 270 Section foo_2(kLittleEndian); 271 PopulateSection(&foo_2, 32, 5); 272 elf2.AddSection(".foo", foo_2, SHT_PROGBITS); 273 PopulateSection(&text_2, 4096, 31); 274 elf2.AddSection(".text", text_2, SHT_PROGBITS); 275 elf2.Finish(); 276 GetElfContents(elf2); 277 } 278 279 EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_2)); 280 FileID::ConvertIdentifierToString(identifier_2, identifier_string_2, 281 sizeof(identifier_string_2)); 282 283 EXPECT_STRNE(identifier_string_1, identifier_string_2); 284}