PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/thirdparty/breakpad/common/mac/macho_reader_unittest.cc

http://github.com/tomahawk-player/tomahawk
C++ | 1815 lines | 1378 code | 261 blank | 176 comment | 28 complexity | eb99e21c8389469df2b7230f41511ef9 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-3.0, GPL-2.0
  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. // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
  30. // macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader
  31. // and google_breakpad::Mach_O::Reader.
  32. #include <map>
  33. #include <string>
  34. #include <vector>
  35. #include "breakpad_googletest_includes.h"
  36. #include "common/mac/macho_reader.h"
  37. #include "common/test_assembler.h"
  38. namespace mach_o = google_breakpad::mach_o;
  39. namespace test_assembler = google_breakpad::test_assembler;
  40. using mach_o::FatReader;
  41. using mach_o::FileFlags;
  42. using mach_o::FileType;
  43. using mach_o::LoadCommandType;
  44. using mach_o::Reader;
  45. using mach_o::Section;
  46. using mach_o::SectionMap;
  47. using mach_o::Segment;
  48. using test_assembler::Endianness;
  49. using test_assembler::Label;
  50. using test_assembler::kBigEndian;
  51. using test_assembler::kLittleEndian;
  52. using test_assembler::kUnsetEndian;
  53. using google_breakpad::ByteBuffer;
  54. using std::map;
  55. using std::string;
  56. using std::vector;
  57. using testing::AllOf;
  58. using testing::DoAll;
  59. using testing::Field;
  60. using testing::InSequence;
  61. using testing::Matcher;
  62. using testing::Return;
  63. using testing::SaveArg;
  64. using testing::Test;
  65. using testing::_;
  66. // Mock classes for the reader's various reporters and handlers.
  67. class MockFatReaderReporter: public FatReader::Reporter {
  68. public:
  69. MockFatReaderReporter(const string &filename)
  70. : FatReader::Reporter(filename) { }
  71. MOCK_METHOD0(BadHeader, void());
  72. MOCK_METHOD0(MisplacedObjectFile, void());
  73. MOCK_METHOD0(TooShort, void());
  74. };
  75. class MockReaderReporter: public Reader::Reporter {
  76. public:
  77. MockReaderReporter(const string &filename) : Reader::Reporter(filename) { }
  78. MOCK_METHOD0(BadHeader, void());
  79. MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type,
  80. cpu_subtype_t cpu_subtype,
  81. cpu_type_t expected_cpu_type,
  82. cpu_subtype_t expected_cpu_subtype));
  83. MOCK_METHOD0(HeaderTruncated, void());
  84. MOCK_METHOD0(LoadCommandRegionTruncated, void());
  85. MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i,
  86. LoadCommandType type));
  87. MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type));
  88. MOCK_METHOD1(SectionsMissing, void(const string &name));
  89. MOCK_METHOD1(MisplacedSegmentData, void(const string &name));
  90. MOCK_METHOD2(MisplacedSectionData, void(const string &section,
  91. const string &segment));
  92. MOCK_METHOD0(MisplacedSymbolTable, void());
  93. MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type));
  94. };
  95. class MockLoadCommandHandler: public Reader::LoadCommandHandler {
  96. public:
  97. MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
  98. MOCK_METHOD1(SegmentCommand, bool(const Segment &));
  99. MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &));
  100. };
  101. class MockSectionHandler: public Reader::SectionHandler {
  102. public:
  103. MOCK_METHOD1(HandleSection, bool(const Section &section));
  104. };
  105. // Tests for mach_o::FatReader.
  106. // Since the effect of these functions is to write to stderr, the
  107. // results of these tests must be inspected by hand.
  108. TEST(FatReaderReporter, BadHeader) {
  109. FatReader::Reporter reporter("filename");
  110. reporter.BadHeader();
  111. }
  112. TEST(FatReaderReporter, MisplacedObjectFile) {
  113. FatReader::Reporter reporter("filename");
  114. reporter.MisplacedObjectFile();
  115. }
  116. TEST(FatReaderReporter, TooShort) {
  117. FatReader::Reporter reporter("filename");
  118. reporter.TooShort();
  119. }
  120. TEST(MachOReaderReporter, BadHeader) {
  121. Reader::Reporter reporter("filename");
  122. reporter.BadHeader();
  123. }
  124. TEST(MachOReaderReporter, CPUTypeMismatch) {
  125. Reader::Reporter reporter("filename");
  126. reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
  127. CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
  128. }
  129. TEST(MachOReaderReporter, HeaderTruncated) {
  130. Reader::Reporter reporter("filename");
  131. reporter.HeaderTruncated();
  132. }
  133. TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
  134. Reader::Reporter reporter("filename");
  135. reporter.LoadCommandRegionTruncated();
  136. }
  137. TEST(MachOReaderReporter, LoadCommandsOverrun) {
  138. Reader::Reporter reporter("filename");
  139. reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
  140. reporter.LoadCommandsOverrun(10, 9, 0);
  141. }
  142. TEST(MachOReaderReporter, LoadCommandTooShort) {
  143. Reader::Reporter reporter("filename");
  144. reporter.LoadCommandTooShort(11, LC_SYMTAB);
  145. }
  146. TEST(MachOReaderReporter, SectionsMissing) {
  147. Reader::Reporter reporter("filename");
  148. reporter.SectionsMissing("segment name");
  149. }
  150. TEST(MachOReaderReporter, MisplacedSegmentData) {
  151. Reader::Reporter reporter("filename");
  152. reporter.MisplacedSegmentData("segment name");
  153. }
  154. TEST(MachOReaderReporter, MisplacedSectionData) {
  155. Reader::Reporter reporter("filename");
  156. reporter.MisplacedSectionData("section name", "segment name");
  157. }
  158. TEST(MachOReaderReporter, MisplacedSymbolTable) {
  159. Reader::Reporter reporter("filename");
  160. reporter.MisplacedSymbolTable();
  161. }
  162. TEST(MachOReaderReporter, UnsupportedCPUType) {
  163. Reader::Reporter reporter("filename");
  164. reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
  165. }
  166. struct FatReaderFixture {
  167. FatReaderFixture()
  168. : fat(kBigEndian),
  169. reporter("reporter filename"),
  170. reader(&reporter), object_files(), object_files_size() {
  171. EXPECT_CALL(reporter, BadHeader()).Times(0);
  172. EXPECT_CALL(reporter, TooShort()).Times(0);
  173. // here, start, and Mark are file offsets in 'fat'.
  174. fat.start() = 0;
  175. }
  176. // Append a 'fat_arch' entry to 'fat', with the given field values.
  177. void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype,
  178. Label offset, Label size, uint32_t align) {
  179. fat
  180. .B32(type)
  181. .B32(subtype)
  182. .B32(offset)
  183. .B32(size)
  184. .B32(align);
  185. }
  186. // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and
  187. // subtype have unrealistic values.
  188. void AppendDummyArchEntries(int n) {
  189. for (int i = 0; i < n; i++)
  190. AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1);
  191. }
  192. void ReadFat(bool expect_parse_success = true) {
  193. ASSERT_TRUE(fat.GetContents(&contents));
  194. fat_bytes = reinterpret_cast<const uint8_t *>(contents.data());
  195. if (expect_parse_success) {
  196. EXPECT_TRUE(reader.Read(fat_bytes, contents.size()));
  197. object_files = reader.object_files(&object_files_size);
  198. }
  199. else
  200. EXPECT_FALSE(reader.Read(fat_bytes, contents.size()));
  201. }
  202. test_assembler::Section fat;
  203. MockFatReaderReporter reporter;
  204. FatReader reader;
  205. string contents;
  206. const uint8_t *fat_bytes;
  207. const struct fat_arch *object_files;
  208. size_t object_files_size;
  209. };
  210. class FatReaderTest: public FatReaderFixture, public Test { };
  211. TEST_F(FatReaderTest, BadMagic) {
  212. EXPECT_CALL(reporter, BadHeader()).Times(1);
  213. fat
  214. .B32(0xcafed00d) // magic number (incorrect)
  215. .B32(10); // number of architectures
  216. AppendDummyArchEntries(10);
  217. ReadFat(false);
  218. }
  219. TEST_F(FatReaderTest, HeaderTooShort) {
  220. EXPECT_CALL(reporter, TooShort()).Times(1);
  221. fat
  222. .B32(0xcafebabe); // magic number
  223. ReadFat(false);
  224. }
  225. TEST_F(FatReaderTest, ObjectListTooShort) {
  226. EXPECT_CALL(reporter, TooShort()).Times(1);
  227. fat
  228. .B32(0xcafebabe) // magic number
  229. .B32(10); // number of architectures
  230. AppendDummyArchEntries(9); // nine dummy architecture entries...
  231. fat // and a tenth, missing a byte at the end
  232. .B32(0x3d46c8fc) // cpu type
  233. .B32(0x8a7bfb01) // cpu subtype
  234. .B32(0) // offset
  235. .B32(0) // size
  236. .Append(3, '*'); // one byte short of a four-byte alignment
  237. ReadFat(false);
  238. }
  239. TEST_F(FatReaderTest, DataTooShort) {
  240. EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1);
  241. Label arch_data;
  242. fat
  243. .B32(0xcafebabe) // magic number
  244. .B32(1); // number of architectures
  245. AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0);
  246. fat
  247. .Mark(&arch_data) // file data begins here
  248. .Append(30, '*'); // only 30 bytes, not 40 as header claims
  249. ReadFat(false);
  250. }
  251. TEST_F(FatReaderTest, NoObjectFiles) {
  252. fat
  253. .B32(0xcafebabe) // magic number
  254. .B32(0); // number of architectures
  255. ReadFat();
  256. EXPECT_EQ(0U, object_files_size);
  257. }
  258. TEST_F(FatReaderTest, OneObjectFile) {
  259. Label obj1_offset;
  260. fat
  261. .B32(0xcafebabe) // magic number
  262. .B32(1); // number of architectures
  263. // First object file list entry
  264. AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2);
  265. // First object file data
  266. fat
  267. .Mark(&obj1_offset)
  268. .Append(0x42, '*'); // dummy contents
  269. ReadFat();
  270. ASSERT_EQ(1U, object_files_size);
  271. EXPECT_EQ(0x5e3a6e91, object_files[0].cputype);
  272. EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype);
  273. EXPECT_EQ(obj1_offset.Value(), object_files[0].offset);
  274. EXPECT_EQ(0x42U, object_files[0].size);
  275. EXPECT_EQ(0x355b15b2U, object_files[0].align);
  276. }
  277. TEST_F(FatReaderTest, ThreeObjectFiles) {
  278. Label obj1, obj2, obj3;
  279. fat
  280. .B32(0xcafebabe) // magic number
  281. .B32(3); // number of architectures
  282. // Three object file list entries.
  283. AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8);
  284. AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd);
  285. AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7);
  286. fat
  287. // First object file data
  288. .Mark(&obj1)
  289. .Append(0xfb4, '*') // dummy contents
  290. // Second object file data
  291. .Mark(&obj2)
  292. .Append(0xc31, '%') // dummy contents
  293. // Third object file data
  294. .Mark(&obj3)
  295. .Append(0x4b3, '^'); // dummy contents
  296. ReadFat();
  297. ASSERT_EQ(3U, object_files_size);
  298. // First object file.
  299. EXPECT_EQ(0x0cb92c30, object_files[0].cputype);
  300. EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype);
  301. EXPECT_EQ(obj1.Value(), object_files[0].offset);
  302. EXPECT_EQ(0xfb4U, object_files[0].size);
  303. EXPECT_EQ(0x2615dbe8U, object_files[0].align);
  304. // Second object file.
  305. EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype);
  306. EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype);
  307. EXPECT_EQ(obj2.Value(), object_files[1].offset);
  308. EXPECT_EQ(0xc31U, object_files[1].size);
  309. EXPECT_EQ(0x83af6ffdU, object_files[1].align);
  310. // Third object file.
  311. EXPECT_EQ(0x3717276d, object_files[2].cputype);
  312. EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype);
  313. EXPECT_EQ(obj3.Value(), object_files[2].offset);
  314. EXPECT_EQ(0x4b3U, object_files[2].size);
  315. EXPECT_EQ(0x035267d7U, object_files[2].align);
  316. }
  317. TEST_F(FatReaderTest, BigEndianMachO32) {
  318. fat.set_endianness(kBigEndian);
  319. fat
  320. .D32(0xfeedface) // Mach-O file magic number
  321. .D32(0x1a9d0518) // cpu type
  322. .D32(0x1b779357) // cpu subtype
  323. .D32(0x009df67e) // file type
  324. .D32(0) // no load commands
  325. .D32(0) // the load commands occupy no bytes
  326. .D32(0x21987a99); // flags
  327. ReadFat();
  328. // FatReader should treat a Mach-O file as if it were a fat binary file
  329. // containing one object file --- the whole thing.
  330. ASSERT_EQ(1U, object_files_size);
  331. EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
  332. EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
  333. EXPECT_EQ(0U, object_files[0].offset);
  334. EXPECT_EQ(contents.size(), object_files[0].size);
  335. }
  336. TEST_F(FatReaderTest, BigEndianMachO64) {
  337. fat.set_endianness(kBigEndian);
  338. fat
  339. .D32(0xfeedfacf) // Mach-O 64-bit file magic number
  340. .D32(0x5aff8487) // cpu type
  341. .D32(0x4c6a57f7) // cpu subtype
  342. .D32(0x4392d2c8) // file type
  343. .D32(0) // no load commands
  344. .D32(0) // the load commands occupy no bytes
  345. .D32(0x1b033eea); // flags
  346. ReadFat();
  347. // FatReader should treat a Mach-O file as if it were a fat binary file
  348. // containing one object file --- the whole thing.
  349. ASSERT_EQ(1U, object_files_size);
  350. EXPECT_EQ(0x5aff8487, object_files[0].cputype);
  351. EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
  352. EXPECT_EQ(0U, object_files[0].offset);
  353. EXPECT_EQ(contents.size(), object_files[0].size);
  354. }
  355. TEST_F(FatReaderTest, LittleEndianMachO32) {
  356. fat.set_endianness(kLittleEndian);
  357. fat
  358. .D32(0xfeedface) // Mach-O file magic number
  359. .D32(0x1a9d0518) // cpu type
  360. .D32(0x1b779357) // cpu subtype
  361. .D32(0x009df67e) // file type
  362. .D32(0) // no load commands
  363. .D32(0) // the load commands occupy no bytes
  364. .D32(0x21987a99); // flags
  365. ReadFat();
  366. // FatReader should treat a Mach-O file as if it were a fat binary file
  367. // containing one object file --- the whole thing.
  368. ASSERT_EQ(1U, object_files_size);
  369. EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
  370. EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
  371. EXPECT_EQ(0U, object_files[0].offset);
  372. EXPECT_EQ(contents.size(), object_files[0].size);
  373. }
  374. TEST_F(FatReaderTest, LittleEndianMachO64) {
  375. fat.set_endianness(kLittleEndian);
  376. fat
  377. .D32(0xfeedfacf) // Mach-O 64-bit file magic number
  378. .D32(0x5aff8487) // cpu type
  379. .D32(0x4c6a57f7) // cpu subtype
  380. .D32(0x4392d2c8) // file type
  381. .D32(0) // no load commands
  382. .D32(0) // the load commands occupy no bytes
  383. .D32(0x1b033eea); // flags
  384. ReadFat();
  385. // FatReader should treat a Mach-O file as if it were a fat binary file
  386. // containing one object file --- the whole thing.
  387. ASSERT_EQ(1U, object_files_size);
  388. EXPECT_EQ(0x5aff8487, object_files[0].cputype);
  389. EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
  390. EXPECT_EQ(0U, object_files[0].offset);
  391. EXPECT_EQ(contents.size(), object_files[0].size);
  392. }
  393. TEST_F(FatReaderTest, IncompleteMach) {
  394. fat.set_endianness(kLittleEndian);
  395. fat
  396. .D32(0xfeedfacf) // Mach-O 64-bit file magic number
  397. .D32(0x5aff8487); // cpu type
  398. // Truncated!
  399. EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
  400. ReadFat(false);
  401. }
  402. // General mach_o::Reader tests.
  403. // Dynamically scoped configuration data.
  404. class WithConfiguration {
  405. public:
  406. // Establish the given parameters as the default for SizedSections
  407. // created within the dynamic scope of this instance.
  408. WithConfiguration(Endianness endianness, size_t word_size)
  409. : endianness_(endianness), word_size_(word_size), saved_(current_) {
  410. current_ = this;
  411. }
  412. ~WithConfiguration() { current_ = saved_; }
  413. static Endianness endianness() {
  414. assert(current_);
  415. return current_->endianness_;
  416. }
  417. static size_t word_size() {
  418. assert(current_);
  419. return current_->word_size_;
  420. }
  421. private:
  422. // The innermost WithConfiguration in whose dynamic scope we are
  423. // currently executing.
  424. static WithConfiguration *current_;
  425. // The innermost WithConfiguration whose dynamic scope encloses this
  426. // WithConfiguration.
  427. Endianness endianness_;
  428. size_t word_size_;
  429. WithConfiguration *saved_;
  430. };
  431. WithConfiguration *WithConfiguration::current_ = NULL;
  432. // A test_assembler::Section with a size that we can cite. The start(),
  433. // Here() and Mark() member functions of a SizedSection always represent
  434. // offsets within the overall file.
  435. class SizedSection: public test_assembler::Section {
  436. public:
  437. // Construct a section of the given endianness and word size.
  438. explicit SizedSection(Endianness endianness, size_t word_size)
  439. : test_assembler::Section(endianness), word_size_(word_size) {
  440. assert(word_size_ == 32 || word_size_ == 64);
  441. }
  442. SizedSection()
  443. : test_assembler::Section(WithConfiguration::endianness()),
  444. word_size_(WithConfiguration::word_size()) {
  445. assert(word_size_ == 32 || word_size_ == 64);
  446. }
  447. // Access/set this section's word size.
  448. size_t word_size() const { return word_size_; }
  449. void set_word_size(size_t word_size) {
  450. assert(word_size_ == 32 || word_size_ == 64);
  451. word_size_ = word_size;
  452. }
  453. // Return a label representing the size this section will have when it
  454. // is Placed in some containing section.
  455. Label final_size() const { return final_size_; }
  456. // Append SECTION to the end of this section, and call its Finish member.
  457. // Return a reference to this section.
  458. SizedSection &Place(SizedSection *section) {
  459. assert(section->endianness() == endianness());
  460. section->Finish();
  461. section->start() = Here();
  462. test_assembler::Section::Append(*section);
  463. return *this;
  464. }
  465. protected:
  466. // Mark this section's contents as complete. For plain SizedSections, we
  467. // set SECTION's start to its position in this section, and its final_size
  468. // label to its current size. Derived classes can extend this as needed
  469. // for their additional semantics.
  470. virtual void Finish() {
  471. final_size_ = Size();
  472. }
  473. // The word size for this data: either 32 or 64.
  474. size_t word_size_;
  475. private:
  476. // This section's final size, set when we are placed in some other
  477. // SizedSection.
  478. Label final_size_;
  479. };
  480. // A SizedSection that is loaded into memory at a particular address.
  481. class LoadedSection: public SizedSection {
  482. public:
  483. explicit LoadedSection(Label address = Label()) : address_(address) { }
  484. // Return a label representing this section's address.
  485. Label address() const { return address_; }
  486. // Placing a loaded section within a loaded section sets the relationship
  487. // between their addresses.
  488. LoadedSection &Place(LoadedSection *section) {
  489. section->address() = address() + Size();
  490. SizedSection::Place(section);
  491. return *this;
  492. }
  493. protected:
  494. // The address at which this section's contents will be loaded.
  495. Label address_;
  496. };
  497. // A SizedSection representing a segment load command.
  498. class SegmentLoadCommand: public SizedSection {
  499. public:
  500. SegmentLoadCommand() : section_count_(0) { }
  501. // Append a segment load command header with the given characteristics.
  502. // The load command will refer to CONTENTS, which must be Placed in the
  503. // file separately, at the desired position. Return a reference to this
  504. // section.
  505. SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
  506. uint32_t maxprot, uint32_t initprot,
  507. uint32_t flags) {
  508. assert(contents.word_size() == word_size());
  509. D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64);
  510. D32(final_size());
  511. AppendCString(name, 16);
  512. Append(endianness(), word_size() / 8, contents.address());
  513. Append(endianness(), word_size() / 8, vmsize_);
  514. Append(endianness(), word_size() / 8, contents.start());
  515. Append(endianness(), word_size() / 8, contents.final_size());
  516. D32(maxprot);
  517. D32(initprot);
  518. D32(final_section_count_);
  519. D32(flags);
  520. content_final_size_ = contents.final_size();
  521. return *this;
  522. }
  523. // Return a label representing the size of this segment when loaded into
  524. // memory. If this label is still undefined by the time we place this
  525. // segment, it defaults to the final size of the segment's in-file
  526. // contents. Return a reference to this load command.
  527. Label &vmsize() { return vmsize_; }
  528. // Add a section entry with the given characteristics to this segment
  529. // load command. Return a reference to this. The section entry will refer
  530. // to CONTENTS, which must be Placed in the segment's contents
  531. // separately, at the desired position.
  532. SegmentLoadCommand &AppendSectionEntry(const string &section_name,
  533. const string &segment_name,
  534. uint32_t alignment, uint32_t flags,
  535. const LoadedSection &contents) {
  536. AppendCString(section_name, 16);
  537. AppendCString(segment_name, 16);
  538. Append(endianness(), word_size() / 8, contents.address());
  539. Append(endianness(), word_size() / 8, contents.final_size());
  540. D32(contents.start());
  541. D32(alignment);
  542. D32(0); // relocations start
  543. D32(0); // relocations size
  544. D32(flags);
  545. D32(0x93656b95); // reserved1
  546. D32(0xc35a2473); // reserved2
  547. if (word_size() == 64)
  548. D32(0x70284b95); // reserved3
  549. section_count_++;
  550. return *this;
  551. }
  552. protected:
  553. void Finish() {
  554. final_section_count_ = section_count_;
  555. if (!vmsize_.IsKnownConstant())
  556. vmsize_ = content_final_size_;
  557. SizedSection::Finish();
  558. }
  559. private:
  560. // The number of sections that have been added to this segment so far.
  561. size_t section_count_;
  562. // A label representing the final number of sections this segment will hold.
  563. Label final_section_count_;
  564. // The size of the contents for this segment present in the file.
  565. Label content_final_size_;
  566. // A label representing the size of this segment when loaded; this can be
  567. // larger than the size of its file contents, the difference being
  568. // zero-filled. If not set explicitly by calling set_vmsize, this is set
  569. // equal to the size of the contents.
  570. Label vmsize_;
  571. };
  572. // A SizedSection holding a list of Mach-O load commands.
  573. class LoadCommands: public SizedSection {
  574. public:
  575. LoadCommands() : command_count_(0) { }
  576. // Return a label representing the final load command count.
  577. Label final_command_count() const { return final_command_count_; }
  578. // Increment the command count; return a reference to this section.
  579. LoadCommands &CountCommand() {
  580. command_count_++;
  581. return *this;
  582. }
  583. // Place COMMAND, containing a load command, at the end of this section.
  584. // Return a reference to this section.
  585. LoadCommands &Place(SizedSection *section) {
  586. SizedSection::Place(section);
  587. CountCommand();
  588. return *this;
  589. }
  590. protected:
  591. // Mark this load command list as complete.
  592. void Finish() {
  593. SizedSection::Finish();
  594. final_command_count_ = command_count_;
  595. }
  596. private:
  597. // The number of load commands we have added to this file so far.
  598. size_t command_count_;
  599. // A label representing the final command count.
  600. Label final_command_count_;
  601. };
  602. // A SizedSection holding the contents of a Mach-O file. Within a
  603. // MachOFile, the start, Here, and Mark members refer to file offsets.
  604. class MachOFile: public SizedSection {
  605. public:
  606. MachOFile() {
  607. start() = 0;
  608. }
  609. // Create a Mach-O file header using the given characteristics and load
  610. // command list. This Places COMMANDS immediately after the header.
  611. // Return a reference to this section.
  612. MachOFile &Header(LoadCommands *commands,
  613. cpu_type_t cpu_type = CPU_TYPE_X86,
  614. cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL,
  615. FileType file_type = MH_EXECUTE,
  616. uint32_t file_flags = (MH_TWOLEVEL |
  617. MH_DYLDLINK |
  618. MH_NOUNDEFS)) {
  619. D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf); // magic number
  620. D32(cpu_type); // cpu type
  621. D32(cpu_subtype); // cpu subtype
  622. D32(file_type); // file type
  623. D32(commands->final_command_count()); // number of load commands
  624. D32(commands->final_size()); // their size in bytes
  625. D32(file_flags); // flags
  626. if (word_size() == 64)
  627. D32(0x55638b90); // reserved
  628. Place(commands);
  629. return *this;
  630. }
  631. };
  632. struct ReaderFixture {
  633. ReaderFixture()
  634. : reporter("reporter filename"),
  635. reader(&reporter) {
  636. EXPECT_CALL(reporter, BadHeader()).Times(0);
  637. EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0);
  638. EXPECT_CALL(reporter, HeaderTruncated()).Times(0);
  639. EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0);
  640. EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0);
  641. EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0);
  642. EXPECT_CALL(reporter, SectionsMissing(_)).Times(0);
  643. EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0);
  644. EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0);
  645. EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0);
  646. EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0);
  647. EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0);
  648. EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
  649. }
  650. void ReadFile(MachOFile *file,
  651. bool expect_parse_success,
  652. cpu_type_t expected_cpu_type,
  653. cpu_subtype_t expected_cpu_subtype) {
  654. ASSERT_TRUE(file->GetContents(&file_contents));
  655. file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data());
  656. if (expect_parse_success) {
  657. EXPECT_TRUE(reader.Read(file_bytes,
  658. file_contents.size(),
  659. expected_cpu_type,
  660. expected_cpu_subtype));
  661. } else {
  662. EXPECT_FALSE(reader.Read(file_bytes,
  663. file_contents.size(),
  664. expected_cpu_type,
  665. expected_cpu_subtype));
  666. }
  667. }
  668. string file_contents;
  669. const uint8_t *file_bytes;
  670. MockReaderReporter reporter;
  671. Reader reader;
  672. MockLoadCommandHandler load_command_handler;
  673. MockSectionHandler section_handler;
  674. };
  675. class ReaderTest: public ReaderFixture, public Test { };
  676. TEST_F(ReaderTest, BadMagic) {
  677. WithConfiguration config(kLittleEndian, 32);
  678. const cpu_type_t kCPUType = 0x46b760df;
  679. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  680. MachOFile file;
  681. file
  682. .D32(0x67bdebe1) // Not a proper magic number.
  683. .D32(kCPUType) // cpu type
  684. .D32(kCPUSubType) // cpu subtype
  685. .D32(0x149fc717) // file type
  686. .D32(0) // no load commands
  687. .D32(0) // they occupy no bytes
  688. .D32(0x80e71d64) // flags
  689. .D32(0); // reserved
  690. EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
  691. ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
  692. }
  693. TEST_F(ReaderTest, MismatchedMagic) {
  694. WithConfiguration config(kLittleEndian, 32);
  695. const cpu_type_t kCPUType = CPU_TYPE_I386;
  696. const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
  697. MachOFile file;
  698. file
  699. .D32(MH_CIGAM) // Right magic, but winds up wrong
  700. // due to bitswapping
  701. .D32(kCPUType) // cpu type
  702. .D32(kCPUSubType) // cpu subtype
  703. .D32(0x149fc717) // file type
  704. .D32(0) // no load commands
  705. .D32(0) // they occupy no bytes
  706. .D32(0x80e71d64) // flags
  707. .D32(0); // reserved
  708. EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
  709. ReadFile(&file, false, kCPUType, kCPUSubType);
  710. }
  711. TEST_F(ReaderTest, ShortMagic) {
  712. WithConfiguration config(kBigEndian, 32);
  713. MachOFile file;
  714. file
  715. .D16(0xfeed); // magic number
  716. // truncated!
  717. EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
  718. ReadFile(&file, false, CPU_TYPE_ANY, 0);
  719. }
  720. TEST_F(ReaderTest, ShortHeader) {
  721. WithConfiguration config(kBigEndian, 32);
  722. const cpu_type_t kCPUType = CPU_TYPE_ANY;
  723. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  724. MachOFile file;
  725. file
  726. .D32(0xfeedface) // magic number
  727. .D32(kCPUType) // cpu type
  728. .D32(kCPUSubType) // cpu subtype
  729. .D32(0x149fc717) // file type
  730. .D32(0) // no load commands
  731. .D32(0); // they occupy no bytes
  732. EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
  733. ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
  734. }
  735. TEST_F(ReaderTest, MismatchedCPU) {
  736. WithConfiguration config(kBigEndian, 32);
  737. const cpu_type_t kCPUType = CPU_TYPE_I386;
  738. const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
  739. MachOFile file;
  740. file
  741. .D32(MH_MAGIC) // Right magic for PPC (once bitswapped)
  742. .D32(kCPUType) // cpu type
  743. .D32(kCPUSubType) // cpu subtype
  744. .D32(0x149fc717) // file type
  745. .D32(0) // no load commands
  746. .D32(0) // they occupy no bytes
  747. .D32(0x80e71d64) // flags
  748. .D32(0); // reserved
  749. EXPECT_CALL(reporter,
  750. CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
  751. CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL))
  752. .WillOnce(Return());
  753. ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
  754. }
  755. TEST_F(ReaderTest, LittleEndian32Bit) {
  756. WithConfiguration config(kLittleEndian, 32);
  757. const cpu_type_t kCPUType = 0x46b760df;
  758. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  759. MachOFile file;
  760. file
  761. .D32(0xfeedface) // magic number
  762. .D32(kCPUType) // cpu type
  763. .D32(kCPUSubType) // cpu subtype
  764. .D32(0x149fc717) // file type
  765. .D32(0) // no load commands
  766. .D32(0) // they occupy no bytes
  767. .D32(0x80e71d64) // flags
  768. .D32(0); // reserved
  769. ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
  770. EXPECT_FALSE(reader.bits_64());
  771. EXPECT_FALSE(reader.big_endian());
  772. EXPECT_EQ(kCPUType, reader.cpu_type());
  773. EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
  774. EXPECT_EQ(FileType(0x149fc717), reader.file_type());
  775. EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
  776. }
  777. TEST_F(ReaderTest, LittleEndian64Bit) {
  778. WithConfiguration config(kLittleEndian, 64);
  779. const cpu_type_t kCPUType = 0x46b760df;
  780. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  781. MachOFile file;
  782. file
  783. .D32(0xfeedfacf) // magic number
  784. .D32(kCPUType) // cpu type
  785. .D32(kCPUSubType) // cpu subtype
  786. .D32(0x149fc717) // file type
  787. .D32(0) // no load commands
  788. .D32(0) // they occupy no bytes
  789. .D32(0x80e71d64) // flags
  790. .D32(0); // reserved
  791. ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
  792. EXPECT_TRUE(reader.bits_64());
  793. EXPECT_FALSE(reader.big_endian());
  794. EXPECT_EQ(kCPUType, reader.cpu_type());
  795. EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
  796. EXPECT_EQ(FileType(0x149fc717), reader.file_type());
  797. EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
  798. }
  799. TEST_F(ReaderTest, BigEndian32Bit) {
  800. WithConfiguration config(kBigEndian, 32);
  801. const cpu_type_t kCPUType = 0x46b760df;
  802. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  803. MachOFile file;
  804. file
  805. .D32(0xfeedface) // magic number
  806. .D32(kCPUType) // cpu type
  807. .D32(kCPUSubType) // cpu subtype
  808. .D32(0x149fc717) // file type
  809. .D32(0) // no load commands
  810. .D32(0) // they occupy no bytes
  811. .D32(0x80e71d64) // flags
  812. .D32(0); // reserved
  813. ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
  814. EXPECT_FALSE(reader.bits_64());
  815. EXPECT_TRUE(reader.big_endian());
  816. EXPECT_EQ(kCPUType, reader.cpu_type());
  817. EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
  818. EXPECT_EQ(FileType(0x149fc717), reader.file_type());
  819. EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
  820. }
  821. TEST_F(ReaderTest, BigEndian64Bit) {
  822. WithConfiguration config(kBigEndian, 64);
  823. const cpu_type_t kCPUType = 0x46b760df;
  824. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  825. MachOFile file;
  826. file
  827. .D32(0xfeedfacf) // magic number
  828. .D32(kCPUType) // cpu type
  829. .D32(kCPUSubType) // cpu subtype
  830. .D32(0x149fc717) // file type
  831. .D32(0) // no load commands
  832. .D32(0) // they occupy no bytes
  833. .D32(0x80e71d64) // flags
  834. .D32(0); // reserved
  835. ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
  836. EXPECT_TRUE(reader.bits_64());
  837. EXPECT_TRUE(reader.big_endian());
  838. EXPECT_EQ(kCPUType, reader.cpu_type());
  839. EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
  840. EXPECT_EQ(FileType(0x149fc717), reader.file_type());
  841. EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
  842. }
  843. // Load command tests.
  844. class LoadCommand: public ReaderFixture, public Test { };
  845. TEST_F(LoadCommand, RegionTruncated) {
  846. WithConfiguration config(kBigEndian, 64);
  847. const cpu_type_t kCPUType = 0x46b760df;
  848. const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
  849. MachOFile file;
  850. file
  851. .D32(0xfeedfacf) // magic number
  852. .D32(kCPUType) // cpu type
  853. .D32(kCPUSubType) // cpu subtype
  854. .D32(0x149fc717) // file type
  855. .D32(1) // one load command
  856. .D32(40) // occupying 40 bytes
  857. .D32(0x80e71d64) // flags
  858. .D32(0) // reserved
  859. .Append(20, 0); // load command region, not as long as
  860. // Mach-O header promised
  861. EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
  862. ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
  863. }
  864. TEST_F(LoadCommand, None) {
  865. WithConfiguration config(kLittleEndian, 32);
  866. LoadCommands load_commands;
  867. MachOFile file;
  868. file.Header(&load_commands);
  869. ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
  870. EXPECT_FALSE(reader.bits_64());
  871. EXPECT_FALSE(reader.big_endian());
  872. EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type());
  873. EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
  874. EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
  875. EXPECT_EQ(FileFlags(MH_TWOLEVEL |
  876. MH_DYLDLINK |
  877. MH_NOUNDEFS),
  878. FileFlags(reader.flags()));
  879. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  880. }
  881. TEST_F(LoadCommand, Unknown) {
  882. WithConfiguration config(kBigEndian, 32);
  883. LoadCommands load_commands;
  884. load_commands
  885. .CountCommand()
  886. .D32(0x33293d4a) // unknown load command
  887. .D32(40) // total size in bytes
  888. .Append(32, '*'); // dummy data
  889. MachOFile file;
  890. file.Header(&load_commands);
  891. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  892. EXPECT_FALSE(reader.bits_64());
  893. EXPECT_TRUE(reader.big_endian());
  894. EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type());
  895. EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
  896. EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
  897. EXPECT_EQ(FileFlags(MH_TWOLEVEL |
  898. MH_DYLDLINK |
  899. MH_NOUNDEFS),
  900. reader.flags());
  901. ByteBuffer expected;
  902. expected.start = file_bytes + load_commands.start().Value();
  903. expected.end = expected.start + load_commands.final_size().Value();
  904. EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a,
  905. expected))
  906. .WillOnce(Return(true));
  907. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  908. }
  909. TEST_F(LoadCommand, TypeIncomplete) {
  910. WithConfiguration config(kLittleEndian, 32);
  911. LoadCommands load_commands;
  912. load_commands
  913. .CountCommand()
  914. .Append(3, 0); // load command type, incomplete
  915. MachOFile file;
  916. file.Header(&load_commands);
  917. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  918. EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
  919. .WillOnce(Return());
  920. EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  921. }
  922. TEST_F(LoadCommand, LengthIncomplete) {
  923. WithConfiguration config(kBigEndian, 64);
  924. LoadCommands load_commands;
  925. load_commands
  926. .CountCommand()
  927. .D32(LC_SEGMENT); // load command
  928. // no length
  929. MachOFile file;
  930. file.Header(&load_commands);
  931. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  932. EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
  933. .WillOnce(Return());
  934. EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  935. }
  936. TEST_F(LoadCommand, ContentIncomplete) {
  937. WithConfiguration config(kLittleEndian, 64);
  938. LoadCommands load_commands;
  939. load_commands
  940. .CountCommand()
  941. .D32(LC_SEGMENT) // load command
  942. .D32(40) // total size in bytes
  943. .Append(28, '*'); // not enough dummy data
  944. MachOFile file;
  945. file.Header(&load_commands);
  946. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  947. EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
  948. .WillOnce(Return());
  949. EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  950. }
  951. TEST_F(LoadCommand, SegmentBE32) {
  952. WithConfiguration config(kBigEndian, 32);
  953. LoadedSection segment;
  954. segment.address() = 0x1891139c;
  955. segment.Append(42, '*'); // segment contents
  956. SegmentLoadCommand segment_command;
  957. segment_command
  958. .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd);
  959. segment_command.vmsize() = 0xcb76584fU;
  960. LoadCommands load_commands;
  961. load_commands.Place(&segment_command);
  962. MachOFile file;
  963. file
  964. .Header(&load_commands)
  965. .Place(&segment);
  966. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  967. Segment actual_segment;
  968. EXPECT_CALL(load_command_handler, SegmentCommand(_))
  969. .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  970. Return(true)));
  971. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  972. EXPECT_EQ(false, actual_segment.bits_64);
  973. EXPECT_EQ("froon", actual_segment.name);
  974. EXPECT_EQ(0x1891139cU, actual_segment.vmaddr);
  975. EXPECT_EQ(0xcb76584fU, actual_segment.vmsize);
  976. EXPECT_EQ(0x94d6dd22U, actual_segment.maxprot);
  977. EXPECT_EQ(0x8bdbc319U, actual_segment.initprot);
  978. EXPECT_EQ(0x990a16ddU, actual_segment.flags);
  979. EXPECT_EQ(0U, actual_segment.nsects);
  980. EXPECT_EQ(0U, actual_segment.section_list.Size());
  981. EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  982. }
  983. TEST_F(LoadCommand, SegmentLE32) {
  984. WithConfiguration config(kLittleEndian, 32);
  985. LoadedSection segment;
  986. segment.address() = 0x4b877866;
  987. segment.Append(42, '*'); // segment contents
  988. SegmentLoadCommand segment_command;
  989. segment_command
  990. .Header("sixteenprecisely", segment,
  991. 0x350759ed, 0x6cf5a62e, 0x990a16dd);
  992. segment_command.vmsize() = 0xcb76584fU;
  993. LoadCommands load_commands;
  994. load_commands.Place(&segment_command);
  995. MachOFile file;
  996. file
  997. .Header(&load_commands)
  998. .Place(&segment);
  999. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1000. Segment actual_segment;
  1001. EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1002. .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1003. Return(true)));
  1004. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1005. EXPECT_EQ(false, actual_segment.bits_64);
  1006. EXPECT_EQ("sixteenprecisely", actual_segment.name);
  1007. EXPECT_EQ(0x4b877866U, actual_segment.vmaddr);
  1008. EXPECT_EQ(0xcb76584fU, actual_segment.vmsize);
  1009. EXPECT_EQ(0x350759edU, actual_segment.maxprot);
  1010. EXPECT_EQ(0x6cf5a62eU, actual_segment.initprot);
  1011. EXPECT_EQ(0x990a16ddU, actual_segment.flags);
  1012. EXPECT_EQ(0U, actual_segment.nsects);
  1013. EXPECT_EQ(0U, actual_segment.section_list.Size());
  1014. EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1015. }
  1016. TEST_F(LoadCommand, SegmentBE64) {
  1017. WithConfiguration config(kBigEndian, 64);
  1018. LoadedSection segment;
  1019. segment.address() = 0x79f484f77009e511ULL;
  1020. segment.Append(42, '*'); // segment contents
  1021. SegmentLoadCommand segment_command;
  1022. segment_command
  1023. .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220);
  1024. segment_command.vmsize() = 0x8d92397ce6248abaULL;
  1025. LoadCommands load_commands;
  1026. load_commands.Place(&segment_command);
  1027. MachOFile file;
  1028. file
  1029. .Header(&load_commands)
  1030. .Place(&segment);
  1031. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1032. Segment actual_segment;
  1033. EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1034. .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1035. Return(true)));
  1036. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1037. EXPECT_EQ(true, actual_segment.bits_64);
  1038. EXPECT_EQ("froon", actual_segment.name);
  1039. EXPECT_EQ(0x79f484f77009e511ULL, actual_segment.vmaddr);
  1040. EXPECT_EQ(0x8d92397ce6248abaULL, actual_segment.vmsize);
  1041. EXPECT_EQ(0x42b45da5U, actual_segment.maxprot);
  1042. EXPECT_EQ(0x8bdbc319U, actual_segment.initprot);
  1043. EXPECT_EQ(0xb2335220U, actual_segment.flags);
  1044. EXPECT_EQ(0U, actual_segment.nsects);
  1045. EXPECT_EQ(0U, actual_segment.section_list.Size());
  1046. EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1047. }
  1048. TEST_F(LoadCommand, SegmentLE64) {
  1049. WithConfiguration config(kLittleEndian, 64);
  1050. LoadedSection segment;
  1051. segment.address() = 0x50c0501dc5922d35ULL;
  1052. segment.Append(42, '*'); // segment contents
  1053. SegmentLoadCommand segment_command;
  1054. segment_command
  1055. .Header("sixteenprecisely", segment,
  1056. 0x917c339d, 0xdbc446fa, 0xb650b563);
  1057. segment_command.vmsize() = 0x84ae73e7c75469bfULL;
  1058. LoadCommands load_commands;
  1059. load_commands.Place(&segment_command);
  1060. MachOFile file;
  1061. file
  1062. .Header(&load_commands)
  1063. .Place(&segment);
  1064. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1065. Segment actual_segment;
  1066. EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1067. .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1068. Return(true)));
  1069. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1070. EXPECT_EQ(true, actual_segment.bits_64);
  1071. EXPECT_EQ("sixteenprecisely", actual_segment.name);
  1072. EXPECT_EQ(0x50c0501dc5922d35ULL, actual_segment.vmaddr);
  1073. EXPECT_EQ(0x84ae73e7c75469bfULL, actual_segment.vmsize);
  1074. EXPECT_EQ(0x917c339dU, actual_segment.maxprot);
  1075. EXPECT_EQ(0xdbc446faU, actual_segment.initprot);
  1076. EXPECT_EQ(0xb650b563U, actual_segment.flags);
  1077. EXPECT_EQ(0U, actual_segment.nsects);
  1078. EXPECT_EQ(0U, actual_segment.section_list.Size());
  1079. EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1080. }
  1081. TEST_F(LoadCommand, SegmentCommandTruncated) {
  1082. WithConfiguration config(kBigEndian, 32);
  1083. LoadedSection segment_contents;
  1084. segment_contents.Append(20, '*'); // lah di dah
  1085. SizedSection command;
  1086. command
  1087. .D32(LC_SEGMENT) // command type
  1088. .D32(command.final_size()) // command size
  1089. .AppendCString("too-short", 16) // segment name
  1090. .D32(0x9c759211) // vmaddr
  1091. .D32(segment_contents.final_size()) // vmsize
  1092. .D32(segment_contents.start()) // file offset
  1093. .D32(segment_contents.final_size()) // file size
  1094. .D32(0x56f28446) // max protection
  1095. .D32(0xe7910dcb) // initial protection
  1096. .D32(0) // no sections
  1097. .Append(3, 0); // flags (one byte short!)
  1098. LoadCommands load_commands;
  1099. load_commands.Place(&command);
  1100. MachOFile file;
  1101. file
  1102. .Header(&load_commands)
  1103. .Place(&segment_contents);
  1104. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1105. EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
  1106. .WillOnce(Return());
  1107. EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1108. }
  1109. TEST_F(LoadCommand, SegmentBadContentOffset) {
  1110. WithConfiguration config(kLittleEndian, 32);
  1111. // Instead of letting a Place call set the segment's file offset and size,
  1112. // set them ourselves, to check that the parser catches invalid offsets
  1113. // instead of handing us bogus pointers.
  1114. LoadedSection segment;
  1115. segment.address() = 0x4db5489c;
  1116. segment.start() = 0x7e189e76; // beyond end of file
  1117. segment.final_size() = 0x98b9c3ab;
  1118. SegmentLoadCommand segment_command;
  1119. segment_command
  1120. .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f);
  1121. LoadCommands load_commands;
  1122. load_commands.Place(&segment_command);
  1123. MachOFile file;
  1124. file.Header(&load_commands);
  1125. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1126. EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
  1127. .WillOnce(Return());
  1128. EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1129. }
  1130. TEST_F(LoadCommand, ThreeLoadCommands) {
  1131. WithConfiguration config(kBigEndian, 32);
  1132. LoadedSection seg1, seg2, seg3;
  1133. SegmentLoadCommand cmd1, cmd2, cmd3;
  1134. seg1.Append(128, '@');
  1135. seg1.address() = 0xa7f61ef6;
  1136. cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87);
  1137. // Include some dummy data at the end of the load command. Since we
  1138. // didn't claim to have any sections, the reader should ignore this. But
  1139. // making sure the commands have different lengths ensures that we're
  1140. // using the right command's length to advance the LoadCommandIterator.
  1141. cmd1.Append(128, '!');
  1142. seg2.Append(42, '*');
  1143. seg2.address() = 0xc70fc909;
  1144. cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30);
  1145. // More dummy data at the end of the load command.
  1146. cmd2.Append(32, '^');
  1147. seg3.Append(42, '%');
  1148. seg3.address() = 0x46b3ab05;
  1149. cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b);
  1150. // More dummy data at the end of the load command.
  1151. cmd3.Append(64, '&');
  1152. LoadCommands load_commands;
  1153. load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
  1154. MachOFile file;
  1155. file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
  1156. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1157. {
  1158. InSequence s;
  1159. EXPECT_CALL(load_command_handler,
  1160. SegmentCommand(Field(&Segment::name, "head")))
  1161. .WillOnce(Return(true));
  1162. EXPECT_CALL(load_command_handler,
  1163. SegmentCommand(Field(&Segment::name, "thorax")))
  1164. .WillOnce(Return(true));
  1165. EXPECT_CALL(load_command_handler,
  1166. SegmentCommand(Field(&Segment::name, "abdomen")))
  1167. .WillOnce(Return(true));
  1168. }
  1169. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1170. }
  1171. static inline Matcher<const Section &> MatchSection(
  1172. Matcher<bool> bits_64,
  1173. Matcher<const string &> section_name,
  1174. Matcher<const string &> segment_name,
  1175. Matcher<uint64_t> address,
  1176. Matcher<uint32_t> alignment,
  1177. Matcher<uint32_t> flags,
  1178. Matcher<const ByteBuffer &> contents) {
  1179. return AllOf(AllOf(Field(&Section::bits_64, bits_64),
  1180. Field(&Section::section_name, section_name),
  1181. Field(&Section::segment_name, segment_name),
  1182. Field(&Section::address, address)),
  1183. AllOf(Field(&Section::align, alignment),
  1184. Field(&Section::flags, flags),
  1185. Field(&Section::contents, contents)));
  1186. }
  1187. static inline Matcher<const Section &> MatchSection(
  1188. Matcher<bool> bits_64,
  1189. Matcher<const string &> section_name,
  1190. Matcher<const string &> segment_name,
  1191. Matcher<uint64_t> address) {
  1192. return AllOf(Field(&Section::bits_64, bits_64),
  1193. Field(&Section::section_name, section_name),
  1194. Field(&Section::segment_name, segment_name),
  1195. Field(&Section::address, address));
  1196. }
  1197. TEST_F(LoadCommand, OneSegmentTwoSections) {
  1198. WithConfiguration config(kBigEndian, 64);
  1199. // Create some sections with some data.
  1200. LoadedSection section1, section2;
  1201. section1.Append("buddha's hand");
  1202. section2.Append("kumquat");
  1203. // Create a segment to hold them.
  1204. LoadedSection segment;
  1205. segment.address() = 0xe1d0eeec;
  1206. segment.Place(&section2).Place(&section1);
  1207. SegmentLoadCommand segment_command;
  1208. segment_command
  1209. .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2)
  1210. .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1)
  1211. .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2);
  1212. LoadCommands commands;
  1213. commands.Place(&segment_command);
  1214. MachOFile file;
  1215. file.Header(&commands).Place(&segment);
  1216. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1217. Segment actual_segment;
  1218. EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1219. .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1220. Return(true)));
  1221. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1222. {
  1223. InSequence s;
  1224. ByteBuffer contents1;
  1225. contents1.start = file_bytes + section1.start().Value();
  1226. contents1.end = contents1.start + section1.final_size().Value();
  1227. EXPECT_EQ("buddha's hand",
  1228. string(reinterpret_cast<const char *>(contents1.start),
  1229. contents1.Size()));
  1230. EXPECT_CALL(section_handler,
  1231. HandleSection(MatchSection(true, "mandarin", "kishu",
  1232. section1.address().Value(), 12,
  1233. 0x8cd4604bU, contents1)))
  1234. .WillOnce(Return(true));
  1235. ByteBuffer contents2;
  1236. contents2.start = file_bytes + section2.start().Value();
  1237. contents2.end = contents2.start + section2.final_size().Value();
  1238. EXPECT_EQ("kumquat",
  1239. string(reinterpret_cast<const char *>(contents2.start),
  1240. contents2.Size()));
  1241. EXPECT_CALL(section_handler,
  1242. HandleSection(MatchSection(true, "bergamot", "cara cara",
  1243. section2.address().Value(), 12,
  1244. 0x98746efaU, contents2)))
  1245. .WillOnce(Return(true));
  1246. }
  1247. EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1248. }
  1249. TEST_F(LoadCommand, MisplacedSectionBefore) {
  1250. WithConfiguration config(kLittleEndian, 64);
  1251. // The segment.
  1252. LoadedSection segment;
  1253. segment.address() = 0x696d83cc;
  1254. segment.Append(10, '0');
  1255. // The contents of the following sections don't matter, because
  1256. // we're not really going to Place them in segment; we're just going
  1257. // to set all their labels by hand to get the (impossible)
  1258. // configurations we want.
  1259. // A section whose starting offset is before that of its section.
  1260. LoadedSection before;
  1261. before.Append(10, '1');
  1262. before.start() = segment.start() - 1;
  1263. before.address() = segment.address() - 1;
  1264. before.final_size() = before.Size();
  1265. SegmentLoadCommand command;
  1266. command
  1267. .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
  1268. .AppendSectionEntry("before", "segment", 0, 0x686c6921, before);
  1269. LoadCommands commands;
  1270. commands.Place(&command);
  1271. MachOFile file;
  1272. file.Header(&commands).Place(&segment);
  1273. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1274. Segment actual_segment;
  1275. EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
  1276. EXPECT_CALL(reporter, MisplacedSectionData("before", "segment"))
  1277. .WillOnce(Return());
  1278. EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1279. }
  1280. TEST_F(LoadCommand, MisplacedSectionAfter) {
  1281. WithConfiguration config(kLittleEndian, 64);
  1282. // The segment.
  1283. LoadedSection segment;
  1284. segment.address() = 0x696d83cc;
  1285. segment.Append(10, '0');
  1286. // The contents of the following sections don't matter, because
  1287. // we're not really going to Place them in segment; we're just going
  1288. // to set all their labels by hand to get the (impossible)
  1289. // configurations we want.
  1290. // A section whose starting offset is after the end of its section.
  1291. LoadedSection after;
  1292. after.Append(10, '2');
  1293. after.start() = segment.start() + 11;
  1294. after.address() = segment.address() + 11;
  1295. after.final_size() = after.Size();
  1296. SegmentLoadCommand command;
  1297. command
  1298. .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
  1299. .AppendSectionEntry("after", "segment", 0, 0x2ee50124, after);
  1300. LoadCommands commands;
  1301. commands.Place(&command);
  1302. MachOFile file;
  1303. file.Header(&commands).Place(&segment);
  1304. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1305. Segment actual_segment;
  1306. EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
  1307. EXPECT_CALL(reporter, MisplacedSectionData("after", "segment"))
  1308. .WillOnce(Return());
  1309. EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1310. }
  1311. TEST_F(LoadCommand, MisplacedSectionTooBig) {
  1312. WithConfiguration config(kLittleEndian, 64);
  1313. // The segment.
  1314. LoadedSection segment;
  1315. segment.address() = 0x696d83cc;
  1316. segment.Append(10, '0');
  1317. // The contents of the following sections don't matter, because
  1318. // we're not really going to Place them in segment; we're just going
  1319. // to set all their labels by hand to get the (impossible)
  1320. // configurations we want.
  1321. // A section that extends beyond the end of its section.
  1322. LoadedSection too_big;
  1323. too_big.Append(10, '3');
  1324. too_big.start() = segment.start() + 1;
  1325. too_big.address() = segment.address() + 1;
  1326. too_big.final_size() = too_big.Size();
  1327. SegmentLoadCommand command;
  1328. command
  1329. .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
  1330. .AppendSectionEntry("too big", "segment", 0, 0x8b53ae5c, too_big);
  1331. LoadCommands commands;
  1332. commands.Place(&command);
  1333. MachOFile file;
  1334. file.Header(&commands).Place(&segment);
  1335. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1336. Segment actual_segment;
  1337. EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
  1338. EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment"))
  1339. .WillOnce(Return());
  1340. EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1341. }
  1342. // The segments in a .dSYM bundle's Mach-O file have their file offset
  1343. // and size set to zero, but the sections don't. The reader shouldn't
  1344. // report an error in this case.
  1345. TEST_F(LoadCommand, ZappedSegment) {
  1346. WithConfiguration config(kBigEndian, 32);
  1347. // The segment.
  1348. LoadedSection segment;
  1349. segment.address() = 0x696d83cc;
  1350. segment.start() = 0;
  1351. segment.final_size() = 0;
  1352. // The section.
  1353. LoadedSection section;
  1354. section.address() = segment.address();
  1355. section.start() = 0;
  1356. section.final_size() = 1000; // extends beyond its segment
  1357. SegmentLoadCommand command;
  1358. command
  1359. .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c)
  1360. .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section);
  1361. LoadCommands commands;
  1362. commands.Place(&command);
  1363. MachOFile file;
  1364. file.Header(&commands);
  1365. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1366. Segment actual_segment;
  1367. EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment));
  1368. ByteBuffer zapped_extent(NULL, 0);
  1369. EXPECT_CALL(section_handler,
  1370. HandleSection(MatchSection(false, "twitching", "zapped",
  1371. 0x696d83cc, 0, 0x93b3bd42,
  1372. zapped_extent)))
  1373. .WillOnce(Return(true));
  1374. EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1375. }
  1376. TEST_F(LoadCommand, MapSegmentSections) {
  1377. WithConfiguration config(kLittleEndian, 32);
  1378. // Create some sections with some data.
  1379. LoadedSection section1, section2, section3, section4;
  1380. section1.Append("buddha's hand");
  1381. section2.start() = 0; // Section 2 is an S_ZEROFILL section.
  1382. section2.final_size() = 0;
  1383. section3.Append("shasta gold");
  1384. section4.Append("satsuma");
  1385. // Create two segments to hold them.
  1386. LoadedSection segment1, segment2;
  1387. segment1.address() = 0x13e6c8a9;
  1388. segment1.Place(&section3).Place(&section1);
  1389. segment2.set_word_size(64);
  1390. segment2.address() = 0x04d462e2;
  1391. segment2.Place(&section4);
  1392. section2.address() = segment2.address() + segment2.Size();
  1393. SegmentLoadCommand segment_command1, segment_command2;
  1394. segment_command1
  1395. .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64)
  1396. .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1)
  1397. .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3);
  1398. segment_command2.set_word_size(64);
  1399. segment_command2
  1400. .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33)
  1401. .AppendSectionEntry("sixteenprecisely", "thorax",
  1402. 12, S_ZEROFILL, section2)
  1403. .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4);
  1404. LoadCommands commands;
  1405. commands.Place(&segment_command1).Place(&segment_command2);
  1406. MachOFile file;
  1407. file.Header(&commands).Place(&segment1).Place(&segment2);
  1408. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1409. Segment segment;
  1410. SectionMap section_map;
  1411. EXPECT_FALSE(reader.FindSegment("smoot", &segment));
  1412. ASSERT_TRUE(reader.FindSegment("thorax", &segment));
  1413. ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
  1414. EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome")
  1415. != section_map.end());
  1416. EXPECT_FALSE(section_map.find("mandarin") != section_map.end());
  1417. ASSERT_TRUE(section_map.find("cara cara") != section_map.end());
  1418. EXPECT_THAT(section_map["cara cara"],
  1419. MatchSection(true, "cara cara", "thorax", 0x04d462e2));
  1420. ASSERT_TRUE(section_map.find("sixteenprecisely")
  1421. != section_map.end());
  1422. ByteBuffer sixteenprecisely_contents(NULL, 0);
  1423. EXPECT_THAT(section_map["sixteenprecisely"],
  1424. MatchSection(true, "sixteenprecisely", "thorax",
  1425. 0x04d462e2 + 7, 12, S_ZEROFILL,
  1426. sixteenprecisely_contents));
  1427. ASSERT_TRUE(reader.FindSegment("head", &segment));
  1428. ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
  1429. ASSERT_TRUE(section_map.find("mandarin") != section_map.end());
  1430. EXPECT_THAT(section_map["mandarin"],
  1431. MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11));
  1432. ASSERT_TRUE(section_map.find("bergamot") != section_map.end());
  1433. EXPECT_THAT(section_map["bergamot"],
  1434. MatchSection(false, "bergamot", "head", 0x13e6c8a9));
  1435. }
  1436. TEST_F(LoadCommand, FindSegment) {
  1437. WithConfiguration config(kBigEndian, 32);
  1438. LoadedSection segment1, segment2, segment3;
  1439. segment1.address() = 0xb8ae5752;
  1440. segment1.Append("Some contents!");
  1441. segment2.address() = 0xd6b0ce83;
  1442. segment2.Append("Different stuff.");
  1443. segment3.address() = 0x7374fd2a;
  1444. segment3.Append("Further materials.");
  1445. SegmentLoadCommand cmd1, cmd2, cmd3;
  1446. cmd1.Header("first", segment1, 0xfadb6932, 0x175bf529, 0x0de790ad);
  1447. cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef);
  1448. cmd3.Header("third", segment3, 0xe172b39e, 0x86012f07, 0x080ac94d);
  1449. LoadCommands commands;
  1450. commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
  1451. MachOFile file;
  1452. file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3);
  1453. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1454. Segment actual_segment;
  1455. EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment));
  1456. EXPECT_TRUE(reader.FindSegment("second", &actual_segment));
  1457. EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr);
  1458. }
  1459. // Symtab tests.
  1460. // A StringAssembler is a class for generating .stabstr sections to present
  1461. // as input to the STABS parser.
  1462. class StringAssembler: public SizedSection {
  1463. public:
  1464. // Add the string S to this StringAssembler, and return the string's
  1465. // offset within this compilation unit's strings.
  1466. size_t Add(const string &s) {
  1467. size_t offset = Size();
  1468. AppendCString(s);
  1469. return offset;
  1470. }
  1471. };
  1472. // A SymbolAssembler is a class for generating .stab sections to present as
  1473. // test input for the STABS parser.
  1474. class SymbolAssembler: public SizedSection {
  1475. public:
  1476. // Create a SymbolAssembler that uses StringAssembler for its strings.
  1477. explicit SymbolAssembler(StringAssembler *string_assembler)
  1478. : string_assembler_(string_assembler),
  1479. entry_count_(0) { }
  1480. // Append a STAB entry to the end of this section with the given
  1481. // characteristics. NAME is the offset of this entry's name string within
  1482. // its compilation unit's portion of the .stabstr section; this can be a
  1483. // value generated by a StringAssembler. Return a reference to this
  1484. // SymbolAssembler.
  1485. SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
  1486. Label value, Label name) {
  1487. D32(name);
  1488. D8(type);
  1489. D8(other);
  1490. D16(descriptor);
  1491. Append(endianness(), word_size_ / 8, value);
  1492. entry_count_++;
  1493. return *this;
  1494. }
  1495. // As above, but automatically add NAME to our StringAssembler.
  1496. SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
  1497. Label value, const string &name) {
  1498. return Symbol(type, other, descriptor, value, string_assembler_->Add(name));
  1499. }
  1500. private:
  1501. // The strings for our STABS entries.
  1502. StringAssembler *string_assembler_;
  1503. // The number of entries in this compilation unit so far.
  1504. size_t entry_count_;
  1505. };
  1506. class Symtab: public ReaderFixture, public Test { };
  1507. TEST_F(Symtab, Symtab32) {
  1508. WithConfiguration config(kLittleEndian, 32);
  1509. StringAssembler strings;
  1510. SymbolAssembler symbols(&strings);
  1511. symbols
  1512. .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu")
  1513. .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith");
  1514. SizedSection symtab_command;
  1515. symtab_command
  1516. .D32(LC_SYMTAB) // command
  1517. .D32(symtab_command.final_size()) // size
  1518. .D32(symbols.start()) // file offset of symbols
  1519. .D32(2) // symbol count
  1520. .D32(strings.start()) // file offset of strings
  1521. .D32(strings.final_size()); // strings size
  1522. LoadCommands load_commands;
  1523. load_commands.Place(&symtab_command);
  1524. MachOFile file;
  1525. file.Header(&load_commands).Place(&symbols).Place(&strings);
  1526. ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1527. ByteBuffer symbols_found, strings_found;
  1528. EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
  1529. .WillOnce(DoAll(SaveArg<0>(&symbols_found),
  1530. SaveArg<1>(&strings_found),
  1531. Return(true)));
  1532. EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1533. EXPECT_EQ(24U, symbols_found.Size());
  1534. EXPECT_EQ(14U, strings_found.Size());
  1535. }
  1536. TEST_F(Symtab, Symtab64) {
  1537. WithConfiguration config(kBigEndian, 64);
  1538. StringAssembler strings;
  1539. SymbolAssembler symbols(&strings);
  1540. symbols
  1541. .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
  1542. .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
  1543. SizedSection symtab_command;
  1544. symtab_command
  1545. .D32(LC_SYMTAB) // command
  1546. .D32(symtab_command.final_size()) // size
  1547. .D32(symbols.start()) // file offset of symbols
  1548. .D32(2) // symbol count
  1549. .D32(strings.start())