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