/thirdparty/breakpad/common/linux/file_id_unittest.cc

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