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