1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,258 @@ 1.4 +// Copyright (c) 2010, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// Unit tests for FileID 1.34 + 1.35 +#include <elf.h> 1.36 +#include <stdlib.h> 1.37 + 1.38 +#include <string> 1.39 + 1.40 +#include "common/linux/elfutils.h" 1.41 +#include "common/linux/file_id.h" 1.42 +#include "common/linux/safe_readlink.h" 1.43 +#include "common/linux/synth_elf.h" 1.44 +#include "common/test_assembler.h" 1.45 +#include "common/tests/auto_tempdir.h" 1.46 +#include "common/using_std_string.h" 1.47 +#include "breakpad_googletest_includes.h" 1.48 + 1.49 +using namespace google_breakpad; 1.50 +using google_breakpad::ElfClass32; 1.51 +using google_breakpad::ElfClass64; 1.52 +using google_breakpad::SafeReadLink; 1.53 +using google_breakpad::synth_elf::ELF; 1.54 +using google_breakpad::synth_elf::Notes; 1.55 +using google_breakpad::test_assembler::kLittleEndian; 1.56 +using google_breakpad::test_assembler::Section; 1.57 +using ::testing::Types; 1.58 + 1.59 +namespace { 1.60 + 1.61 +// Simply calling Section::Append(size, byte) produces a uninteresting pattern 1.62 +// that tends to get hashed to 0000...0000. This populates the section with 1.63 +// data to produce better hashes. 1.64 +void PopulateSection(Section* section, int size, int prime_number) { 1.65 + for (int i = 0; i < size; i++) 1.66 + section->Append(1, (i % prime_number) % 256); 1.67 +} 1.68 + 1.69 +} // namespace 1.70 + 1.71 +TEST(FileIDStripTest, StripSelf) { 1.72 + // Calculate the File ID of this binary using 1.73 + // FileID::ElfFileIdentifier, then make a copy of this binary, 1.74 + // strip it, and ensure that the result is the same. 1.75 + char exe_name[PATH_MAX]; 1.76 + ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); 1.77 + 1.78 + // copy our binary to a temp file, and strip it 1.79 + AutoTempDir temp_dir; 1.80 + string templ = temp_dir.path() + "/file-id-unittest"; 1.81 + char cmdline[4096]; 1.82 + sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str()); 1.83 + ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; 1.84 + sprintf(cmdline, "chmod u+w \"%s\"", templ.c_str()); 1.85 + ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; 1.86 + sprintf(cmdline, "strip \"%s\"", templ.c_str()); 1.87 + ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; 1.88 + 1.89 + uint8_t identifier1[sizeof(MDGUID)]; 1.90 + uint8_t identifier2[sizeof(MDGUID)]; 1.91 + FileID fileid1(exe_name); 1.92 + EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1)); 1.93 + FileID fileid2(templ.c_str()); 1.94 + EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2)); 1.95 + char identifier_string1[37]; 1.96 + char identifier_string2[37]; 1.97 + FileID::ConvertIdentifierToString(identifier1, identifier_string1, 1.98 + 37); 1.99 + FileID::ConvertIdentifierToString(identifier2, identifier_string2, 1.100 + 37); 1.101 + EXPECT_STREQ(identifier_string1, identifier_string2); 1.102 +} 1.103 + 1.104 +template<typename ElfClass> 1.105 +class FileIDTest : public testing::Test { 1.106 +public: 1.107 + void GetElfContents(ELF& elf) { 1.108 + string contents; 1.109 + ASSERT_TRUE(elf.GetContents(&contents)); 1.110 + ASSERT_LT(0U, contents.size()); 1.111 + 1.112 + elfdata_v.clear(); 1.113 + elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); 1.114 + elfdata = &elfdata_v[0]; 1.115 + } 1.116 + 1.117 + vector<uint8_t> elfdata_v; 1.118 + uint8_t* elfdata; 1.119 +}; 1.120 + 1.121 +typedef Types<ElfClass32, ElfClass64> ElfClasses; 1.122 + 1.123 +TYPED_TEST_CASE(FileIDTest, ElfClasses); 1.124 + 1.125 +TYPED_TEST(FileIDTest, ElfClass) { 1.126 + uint8_t identifier[sizeof(MDGUID)]; 1.127 + const char expected_identifier_string[] = 1.128 + "80808080-8080-0000-0000-008080808080"; 1.129 + char identifier_string[sizeof(expected_identifier_string)]; 1.130 + const size_t kTextSectionSize = 128; 1.131 + 1.132 + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); 1.133 + Section text(kLittleEndian); 1.134 + for (size_t i = 0; i < kTextSectionSize; ++i) { 1.135 + text.D8(i * 3); 1.136 + } 1.137 + elf.AddSection(".text", text, SHT_PROGBITS); 1.138 + elf.Finish(); 1.139 + this->GetElfContents(elf); 1.140 + 1.141 + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, 1.142 + identifier)); 1.143 + 1.144 + FileID::ConvertIdentifierToString(identifier, identifier_string, 1.145 + sizeof(identifier_string)); 1.146 + EXPECT_STREQ(expected_identifier_string, identifier_string); 1.147 +} 1.148 + 1.149 +TYPED_TEST(FileIDTest, BuildID) { 1.150 + const uint8_t kExpectedIdentifier[sizeof(MDGUID)] = 1.151 + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 1.152 + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; 1.153 + char expected_identifier_string[] = 1.154 + "00000000-0000-0000-0000-000000000000"; 1.155 + FileID::ConvertIdentifierToString(kExpectedIdentifier, 1.156 + expected_identifier_string, 1.157 + sizeof(expected_identifier_string)); 1.158 + 1.159 + uint8_t identifier[sizeof(MDGUID)]; 1.160 + char identifier_string[sizeof(expected_identifier_string)]; 1.161 + 1.162 + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); 1.163 + Section text(kLittleEndian); 1.164 + text.Append(4096, 0); 1.165 + elf.AddSection(".text", text, SHT_PROGBITS); 1.166 + Notes notes(kLittleEndian); 1.167 + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier, 1.168 + sizeof(kExpectedIdentifier)); 1.169 + elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); 1.170 + elf.Finish(); 1.171 + this->GetElfContents(elf); 1.172 + 1.173 + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, 1.174 + identifier)); 1.175 + 1.176 + FileID::ConvertIdentifierToString(identifier, identifier_string, 1.177 + sizeof(identifier_string)); 1.178 + EXPECT_STREQ(expected_identifier_string, identifier_string); 1.179 +} 1.180 + 1.181 +TYPED_TEST(FileIDTest, BuildIDPH) { 1.182 + const uint8_t kExpectedIdentifier[sizeof(MDGUID)] = 1.183 + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 1.184 + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; 1.185 + char expected_identifier_string[] = 1.186 + "00000000-0000-0000-0000-000000000000"; 1.187 + FileID::ConvertIdentifierToString(kExpectedIdentifier, 1.188 + expected_identifier_string, 1.189 + sizeof(expected_identifier_string)); 1.190 + 1.191 + uint8_t identifier[sizeof(MDGUID)]; 1.192 + char identifier_string[sizeof(expected_identifier_string)]; 1.193 + 1.194 + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); 1.195 + Section text(kLittleEndian); 1.196 + text.Append(4096, 0); 1.197 + elf.AddSection(".text", text, SHT_PROGBITS); 1.198 + Notes notes(kLittleEndian); 1.199 + notes.AddNote(0, "Linux", 1.200 + reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4); 1.201 + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier, 1.202 + sizeof(kExpectedIdentifier)); 1.203 + int note_idx = elf.AddSection(".note", notes, SHT_NOTE); 1.204 + elf.AddSegment(note_idx, note_idx, PT_NOTE); 1.205 + elf.Finish(); 1.206 + this->GetElfContents(elf); 1.207 + 1.208 + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, 1.209 + identifier)); 1.210 + 1.211 + FileID::ConvertIdentifierToString(identifier, identifier_string, 1.212 + sizeof(identifier_string)); 1.213 + EXPECT_STREQ(expected_identifier_string, identifier_string); 1.214 +} 1.215 + 1.216 +// Test to make sure two files with different text sections produce 1.217 +// different hashes when not using a build id. 1.218 +TYPED_TEST(FileIDTest, UniqueHashes) { 1.219 + char identifier_string_1[] = 1.220 + "00000000-0000-0000-0000-000000000000"; 1.221 + char identifier_string_2[] = 1.222 + "00000000-0000-0000-0000-000000000000"; 1.223 + uint8_t identifier_1[sizeof(MDGUID)]; 1.224 + uint8_t identifier_2[sizeof(MDGUID)]; 1.225 + 1.226 + { 1.227 + ELF elf1(EM_386, TypeParam::kClass, kLittleEndian); 1.228 + Section foo_1(kLittleEndian); 1.229 + PopulateSection(&foo_1, 32, 5); 1.230 + elf1.AddSection(".foo", foo_1, SHT_PROGBITS); 1.231 + Section text_1(kLittleEndian); 1.232 + PopulateSection(&text_1, 4096, 17); 1.233 + elf1.AddSection(".text", text_1, SHT_PROGBITS); 1.234 + elf1.Finish(); 1.235 + this->GetElfContents(elf1); 1.236 + } 1.237 + 1.238 + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, 1.239 + identifier_1)); 1.240 + FileID::ConvertIdentifierToString(identifier_1, identifier_string_1, 1.241 + sizeof(identifier_string_1)); 1.242 + 1.243 + { 1.244 + ELF elf2(EM_386, TypeParam::kClass, kLittleEndian); 1.245 + Section text_2(kLittleEndian); 1.246 + Section foo_2(kLittleEndian); 1.247 + PopulateSection(&foo_2, 32, 5); 1.248 + elf2.AddSection(".foo", foo_2, SHT_PROGBITS); 1.249 + PopulateSection(&text_2, 4096, 31); 1.250 + elf2.AddSection(".text", text_2, SHT_PROGBITS); 1.251 + elf2.Finish(); 1.252 + this->GetElfContents(elf2); 1.253 + } 1.254 + 1.255 + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, 1.256 + identifier_2)); 1.257 + FileID::ConvertIdentifierToString(identifier_2, identifier_string_2, 1.258 + sizeof(identifier_string_2)); 1.259 + 1.260 + EXPECT_STRNE(identifier_string_1, identifier_string_2); 1.261 +}