1
// Copyright (c) 2010 Google Inc.
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
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
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.
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.
30
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
32
// macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader
33
// and google_breakpad::Mach_O::Reader.
39
#include "breakpad_googletest_includes.h"
40
#include "common/mac/macho_reader.h"
41
#include "common/test_assembler.h"
43
namespace mach_o = google_breakpad::mach_o;
44
namespace test_assembler = google_breakpad::test_assembler;
46
using mach_o::FatReader;
47
using mach_o::FileFlags;
48
using mach_o::FileType;
49
using mach_o::LoadCommandType;
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;
66
using testing::InSequence;
67
using testing::Matcher;
68
using testing::Return;
69
using testing::SaveArg;
74
// Mock classes for the reader's various reporters and handlers.
76
class MockFatReaderReporter: public FatReader::Reporter {
78
MockFatReaderReporter(const string &filename)
79
: FatReader::Reporter(filename) { }
80
MOCK_METHOD0(BadHeader, void());
81
MOCK_METHOD0(MisplacedObjectFile, void());
82
MOCK_METHOD0(TooShort, void());
85
class MockReaderReporter: public Reader::Reporter {
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));
106
class MockLoadCommandHandler: public Reader::LoadCommandHandler {
108
MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
109
MOCK_METHOD1(SegmentCommand, bool(const Segment &));
110
MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &));
113
class MockSectionHandler: public Reader::SectionHandler {
115
MOCK_METHOD1(HandleSection, bool(const Section §ion));
119
// Tests for mach_o::FatReader.
121
// Since the effect of these functions is to write to stderr, the
122
// results of these tests must be inspected by hand.
123
TEST(FatReaderReporter, BadHeader) {
124
FatReader::Reporter reporter("filename");
125
reporter.BadHeader();
128
TEST(FatReaderReporter, MisplacedObjectFile) {
129
FatReader::Reporter reporter("filename");
130
reporter.MisplacedObjectFile();
133
TEST(FatReaderReporter, TooShort) {
134
FatReader::Reporter reporter("filename");
138
TEST(MachOReaderReporter, BadHeader) {
139
Reader::Reporter reporter("filename");
140
reporter.BadHeader();
143
TEST(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);
149
TEST(MachOReaderReporter, HeaderTruncated) {
150
Reader::Reporter reporter("filename");
151
reporter.HeaderTruncated();
154
TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
155
Reader::Reporter reporter("filename");
156
reporter.LoadCommandRegionTruncated();
159
TEST(MachOReaderReporter, LoadCommandsOverrun) {
160
Reader::Reporter reporter("filename");
161
reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
162
reporter.LoadCommandsOverrun(10, 9, 0);
165
TEST(MachOReaderReporter, LoadCommandTooShort) {
166
Reader::Reporter reporter("filename");
167
reporter.LoadCommandTooShort(11, LC_SYMTAB);
170
TEST(MachOReaderReporter, SectionsMissing) {
171
Reader::Reporter reporter("filename");
172
reporter.SectionsMissing("segment name");
175
TEST(MachOReaderReporter, MisplacedSegmentData) {
176
Reader::Reporter reporter("filename");
177
reporter.MisplacedSegmentData("segment name");
180
TEST(MachOReaderReporter, MisplacedSectionData) {
181
Reader::Reporter reporter("filename");
182
reporter.MisplacedSectionData("section name", "segment name");
185
TEST(MachOReaderReporter, MisplacedSymbolTable) {
186
Reader::Reporter reporter("filename");
187
reporter.MisplacedSymbolTable();
190
TEST(MachOReaderReporter, UnsupportedCPUType) {
191
Reader::Reporter reporter("filename");
192
reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
195
struct FatReaderFixture {
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);
203
// here, start, and Mark are file offsets in 'fat'.
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) {
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);
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);
230
EXPECT_FALSE(reader.Read(fat_bytes, contents.size()));
232
test_assembler::Section fat;
233
MockFatReaderReporter reporter;
236
const uint8_t *fat_bytes;
237
const struct fat_arch *object_files;
238
size_t object_files_size;
241
class FatReaderTest: public FatReaderFixture, public Test { };
243
TEST_F(FatReaderTest, BadMagic) {
244
EXPECT_CALL(reporter, BadHeader()).Times(1);
246
.B32(0xcafed00d) // magic number (incorrect)
247
.B32(10); // number of architectures
248
AppendDummyArchEntries(10);
252
TEST_F(FatReaderTest, HeaderTooShort) {
253
EXPECT_CALL(reporter, TooShort()).Times(1);
255
.B32(0xcafebabe); // magic number
259
TEST_F(FatReaderTest, ObjectListTooShort) {
260
EXPECT_CALL(reporter, TooShort()).Times(1);
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
270
.Append(3, '*'); // one byte short of a four-byte alignment
274
TEST_F(FatReaderTest, DataTooShort) {
275
EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1);
278
.B32(0xcafebabe) // magic number
279
.B32(1); // number of architectures
280
AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0);
282
.Mark(&arch_data) // file data begins here
283
.Append(30, '*'); // only 30 bytes, not 40 as header claims
287
TEST_F(FatReaderTest, NoObjectFiles) {
289
.B32(0xcafebabe) // magic number
290
.B32(0); // number of architectures
292
EXPECT_EQ(0U, object_files_size);
295
TEST_F(FatReaderTest, OneObjectFile) {
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
305
.Append(0x42, '*'); // dummy contents
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);
315
TEST_F(FatReaderTest, ThreeObjectFiles) {
316
Label obj1, obj2, obj3;
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);
325
// First object file data
327
.Append(0xfb4, '*') // dummy contents
328
// Second object file data
330
.Append(0xc31, '%') // dummy contents
331
// Third object file data
333
.Append(0x4b3, '^'); // dummy contents
337
ASSERT_EQ(3U, object_files_size);
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);
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);
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);
361
TEST_F(FatReaderTest, BigEndianMachO32) {
362
fat.set_endianness(kBigEndian);
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
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);
383
TEST_F(FatReaderTest, BigEndianMachO64) {
384
fat.set_endianness(kBigEndian);
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
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);
405
TEST_F(FatReaderTest, LittleEndianMachO32) {
406
fat.set_endianness(kLittleEndian);
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
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);
427
TEST_F(FatReaderTest, LittleEndianMachO64) {
428
fat.set_endianness(kLittleEndian);
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
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);
449
TEST_F(FatReaderTest, IncompleteMach) {
450
fat.set_endianness(kLittleEndian);
452
.D32(0xfeedfacf) // Mach-O 64-bit file magic number
453
.D32(0x5aff8487); // cpu type
456
EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
462
// General mach_o::Reader tests.
464
// Dynamically scoped configuration data.
465
class WithConfiguration {
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_) {
473
~WithConfiguration() { current_ = saved_; }
474
static Endianness endianness() {
476
return current_->endianness_;
478
static size_t word_size() {
480
return current_->word_size_;
484
// The innermost WithConfiguration in whose dynamic scope we are
485
// currently executing.
486
static WithConfiguration *current_;
488
// The innermost WithConfiguration whose dynamic scope encloses this
489
// WithConfiguration.
490
Endianness endianness_;
492
WithConfiguration *saved_;
495
WithConfiguration *WithConfiguration::current_ = NULL;
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.
500
class SizedSection: public test_assembler::Section {
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);
508
: test_assembler::Section(WithConfiguration::endianness()),
509
word_size_(WithConfiguration::word_size()) {
510
assert(word_size_ == 32 || word_size_ == 64);
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;
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_; }
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());
529
section->start() = Here();
530
test_assembler::Section::Append(*section);
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();
543
// The word size for this data: either 32 or 64.
547
// This section's final size, set when we are placed in some other
552
// A SizedSection that is loaded into memory at a particular address.
553
class LoadedSection: public SizedSection {
555
explicit LoadedSection(Label address = Label()) : address_(address) { }
557
// Return a label representing this section's address.
558
Label address() const { return address_; }
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);
569
// The address at which this section's contents will be loaded.
573
// A SizedSection representing a segment load command.
574
class SegmentLoadCommand: public SizedSection {
576
SegmentLoadCommand() : section_count_(0) { }
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
582
SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
583
uint32_t maxprot, uint32_t initprot,
585
assert(contents.word_size() == word_size());
586
D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64);
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());
595
D32(final_section_count_);
598
content_final_size_ = contents.final_size();
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_; }
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());
623
D32(0); // relocations start
624
D32(0); // relocations size
626
D32(0x93656b95); // reserved1
627
D32(0xc35a2473); // reserved2
628
if (word_size() == 64)
629
D32(0x70284b95); // reserved3
638
final_section_count_ = section_count_;
639
if (!vmsize_.IsKnownConstant())
640
vmsize_ = content_final_size_;
641
SizedSection::Finish();
645
// The number of sections that have been added to this segment so far.
646
size_t section_count_;
648
// A label representing the final number of sections this segment will hold.
649
Label final_section_count_;
651
// The size of the contents for this segment present in the file.
652
Label content_final_size_;
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.
661
// A SizedSection holding a list of Mach-O load commands.
662
class LoadCommands: public SizedSection {
664
LoadCommands() : command_count_(0) { }
666
// Return a label representing the final load command count.
667
Label final_command_count() const { return final_command_count_; }
669
// Increment the command count; return a reference to this section.
670
LoadCommands &CountCommand() {
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);
684
// Mark this load command list as complete.
686
SizedSection::Finish();
687
final_command_count_ = command_count_;
691
// The number of load commands we have added to this file so far.
692
size_t command_count_;
694
// A label representing the final command count.
695
Label final_command_count_;
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.
700
class MachOFile: public SizedSection {
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 |
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
731
struct ReaderFixture {
733
: reporter("reporter filename"),
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);
747
EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0);
748
EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
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(),
761
expected_cpu_subtype));
763
EXPECT_FALSE(reader.Read(file_bytes,
764
file_contents.size(),
766
expected_cpu_subtype));
770
string file_contents;
771
const uint8_t *file_bytes;
772
MockReaderReporter reporter;
774
MockLoadCommandHandler load_command_handler;
775
MockSectionHandler section_handler;
778
class ReaderTest: public ReaderFixture, public Test { };
780
TEST_F(ReaderTest, BadMagic) {
781
WithConfiguration config(kLittleEndian, 32);
782
const cpu_type_t kCPUType = 0x46b760df;
783
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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
794
EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
795
ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
798
TEST_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;
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
813
EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
814
ReadFile(&file, false, kCPUType, kCPUSubType);
817
TEST_F(ReaderTest, ShortMagic) {
818
WithConfiguration config(kBigEndian, 32);
821
.D16(0xfeed); // magic number
823
EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
824
ReadFile(&file, false, CPU_TYPE_ANY, 0);
827
TEST_F(ReaderTest, ShortHeader) {
828
WithConfiguration config(kBigEndian, 32);
829
const cpu_type_t kCPUType = CPU_TYPE_ANY;
830
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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);
843
TEST_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;
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
857
EXPECT_CALL(reporter,
858
CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
859
CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL))
861
ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
864
TEST_F(ReaderTest, LittleEndian32Bit) {
865
WithConfiguration config(kLittleEndian, 32);
866
const cpu_type_t kCPUType = 0x46b760df;
867
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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
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());
887
TEST_F(ReaderTest, LittleEndian64Bit) {
888
WithConfiguration config(kLittleEndian, 64);
889
const cpu_type_t kCPUType = 0x46b760df;
890
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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
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());
910
TEST_F(ReaderTest, BigEndian32Bit) {
911
WithConfiguration config(kBigEndian, 32);
912
const cpu_type_t kCPUType = 0x46b760df;
913
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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
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());
933
TEST_F(ReaderTest, BigEndian64Bit) {
934
WithConfiguration config(kBigEndian, 64);
935
const cpu_type_t kCPUType = 0x46b760df;
936
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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
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());
957
// Load command tests.
959
class LoadCommand: public ReaderFixture, public Test { };
961
TEST_F(LoadCommand, RegionTruncated) {
962
WithConfiguration config(kBigEndian, 64);
963
const cpu_type_t kCPUType = 0x46b760df;
964
const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
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
975
.Append(20, 0); // load command region, not as long as
976
// Mach-O header promised
978
EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
980
ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
983
TEST_F(LoadCommand, None) {
984
WithConfiguration config(kLittleEndian, 32);
985
LoadCommands load_commands;
987
file.Header(&load_commands);
989
ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
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 |
999
FileFlags(reader.flags()));
1001
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1004
TEST_F(LoadCommand, Unknown) {
1005
WithConfiguration config(kBigEndian, 32);
1006
LoadCommands load_commands;
1009
.D32(0x33293d4a) // unknown load command
1010
.D32(40) // total size in bytes
1011
.Append(32, '*'); // dummy data
1013
file.Header(&load_commands);
1015
ReadFile(&file, true, CPU_TYPE_ANY, 0);
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 |
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,
1032
.WillOnce(Return(true));
1034
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1037
TEST_F(LoadCommand, TypeIncomplete) {
1038
WithConfiguration config(kLittleEndian, 32);
1039
LoadCommands load_commands;
1042
.Append(3, 0); // load command type, incomplete
1045
file.Header(&load_commands);
1047
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1049
EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
1050
.WillOnce(Return());
1051
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1054
TEST_F(LoadCommand, LengthIncomplete) {
1055
WithConfiguration config(kBigEndian, 64);
1056
LoadCommands load_commands;
1059
.D32(LC_SEGMENT); // load command
1062
file.Header(&load_commands);
1064
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1066
EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
1067
.WillOnce(Return());
1068
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1071
TEST_F(LoadCommand, ContentIncomplete) {
1072
WithConfiguration config(kLittleEndian, 64);
1073
LoadCommands load_commands;
1076
.D32(LC_SEGMENT) // load command
1077
.D32(40) // total size in bytes
1078
.Append(28, '*'); // not enough dummy data
1080
file.Header(&load_commands);
1082
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1084
EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
1085
.WillOnce(Return());
1086
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1089
TEST_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;
1096
.Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd);
1097
segment_command.vmsize() = 0xcb76584fU;
1098
LoadCommands load_commands;
1099
load_commands.Place(&segment_command);
1102
.Header(&load_commands)
1105
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1107
Segment actual_segment;
1108
EXPECT_CALL(load_command_handler, SegmentCommand(_))
1109
.WillOnce(DoAll(SaveArg<0>(&actual_segment),
1111
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
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());
1125
TEST_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;
1132
.Header("sixteenprecisely", segment,
1133
0x350759ed, 0x6cf5a62e, 0x990a16dd);
1134
segment_command.vmsize() = 0xcb76584fU;
1135
LoadCommands load_commands;
1136
load_commands.Place(&segment_command);
1139
.Header(&load_commands)
1142
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1144
Segment actual_segment;
1145
EXPECT_CALL(load_command_handler, SegmentCommand(_))
1146
.WillOnce(DoAll(SaveArg<0>(&actual_segment),
1148
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
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());
1162
TEST_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;
1169
.Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220);
1170
segment_command.vmsize() = 0x8d92397ce6248abaULL;
1171
LoadCommands load_commands;
1172
load_commands.Place(&segment_command);
1175
.Header(&load_commands)
1178
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1180
Segment actual_segment;
1181
EXPECT_CALL(load_command_handler, SegmentCommand(_))
1182
.WillOnce(DoAll(SaveArg<0>(&actual_segment),
1184
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
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());
1198
TEST_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;
1205
.Header("sixteenprecisely", segment,
1206
0x917c339d, 0xdbc446fa, 0xb650b563);
1207
segment_command.vmsize() = 0x84ae73e7c75469bfULL;
1208
LoadCommands load_commands;
1209
load_commands.Place(&segment_command);
1212
.Header(&load_commands)
1215
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1217
Segment actual_segment;
1218
EXPECT_CALL(load_command_handler, SegmentCommand(_))
1219
.WillOnce(DoAll(SaveArg<0>(&actual_segment),
1221
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
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());
1235
TEST_F(LoadCommand, SegmentCommandTruncated) {
1236
WithConfiguration config(kBigEndian, 32);
1237
LoadedSection segment_contents;
1238
segment_contents.Append(20, '*'); // lah di dah
1239
SizedSection 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);
1256
.Header(&load_commands)
1257
.Place(&segment_contents);
1259
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1261
EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
1262
.WillOnce(Return());
1264
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1267
TEST_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;
1278
.Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f);
1279
LoadCommands load_commands;
1280
load_commands.Place(&segment_command);
1282
file.Header(&load_commands);
1284
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1286
EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
1287
.WillOnce(Return());
1289
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1292
TEST_F(LoadCommand, ThreeLoadCommands) {
1293
WithConfiguration config(kBigEndian, 32);
1294
LoadedSection seg1, seg2, seg3;
1295
SegmentLoadCommand cmd1, cmd2, cmd3;
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, '!');
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, '^');
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, '&');
1318
LoadCommands load_commands;
1319
load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
1322
file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
1324
ReadFile(&file, true, CPU_TYPE_ANY, 0);
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));
1339
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1342
static 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)));
1359
static 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));
1370
TEST_F(LoadCommand, OneSegmentTwoSections) {
1371
WithConfiguration config(kBigEndian, 64);
1373
// Create some sections with some data.
1374
LoadedSection section1, section2;
1375
section1.Append("buddha's hand");
1376
section2.Append("kumquat");
1378
// Create a segment to hold them.
1379
LoadedSection segment;
1380
segment.address() = 0xe1d0eeec;
1381
segment.Place(§ion2).Place(§ion1);
1383
SegmentLoadCommand segment_command;
1385
.Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2)
1386
.AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1)
1387
.AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2);
1389
LoadCommands commands;
1390
commands.Place(&segment_command);
1393
file.Header(&commands).Place(&segment);
1395
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1397
Segment actual_segment;
1398
EXPECT_CALL(load_command_handler, SegmentCommand(_))
1399
.WillOnce(DoAll(SaveArg<0>(&actual_segment),
1401
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
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),
1411
EXPECT_CALL(section_handler,
1412
HandleSection(MatchSection(true, "mandarin", "kishu",
1413
section1.address().Value(), 12,
1414
0x8cd4604bU, contents1)))
1415
.WillOnce(Return(true));
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),
1423
EXPECT_CALL(section_handler,
1424
HandleSection(MatchSection(true, "bergamot", "cara cara",
1425
section2.address().Value(), 12,
1426
0x98746efaU, contents2)))
1427
.WillOnce(Return(true));
1430
EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler));
1433
TEST_F(LoadCommand, MisplacedSectionBefore) {
1434
WithConfiguration config(kLittleEndian, 64);
1437
LoadedSection segment;
1438
segment.address() = 0x696d83cc;
1439
segment.Append(10, '0');
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.
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();
1453
SegmentLoadCommand command;
1455
.Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
1456
.AppendSectionEntry("before", "segment", 0, 0x686c6921, before);
1458
LoadCommands commands;
1459
commands.Place(&command);
1462
file.Header(&commands).Place(&segment);
1464
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1466
Segment actual_segment;
1467
EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
1469
EXPECT_CALL(reporter, MisplacedSectionData("before", "segment"))
1470
.WillOnce(Return());
1471
EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler));
1474
TEST_F(LoadCommand, MisplacedSectionAfter) {
1475
WithConfiguration config(kLittleEndian, 64);
1478
LoadedSection segment;
1479
segment.address() = 0x696d83cc;
1480
segment.Append(10, '0');
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.
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();
1494
SegmentLoadCommand command;
1496
.Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
1497
.AppendSectionEntry("after", "segment", 0, 0x2ee50124, after);
1499
LoadCommands commands;
1500
commands.Place(&command);
1503
file.Header(&commands).Place(&segment);
1505
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1507
Segment actual_segment;
1508
EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
1510
EXPECT_CALL(reporter, MisplacedSectionData("after", "segment"))
1511
.WillOnce(Return());
1512
EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler));
1515
TEST_F(LoadCommand, MisplacedSectionTooBig) {
1516
WithConfiguration config(kLittleEndian, 64);
1519
LoadedSection segment;
1520
segment.address() = 0x696d83cc;
1521
segment.Append(10, '0');
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.
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();
1535
SegmentLoadCommand command;
1537
.Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
1538
.AppendSectionEntry("too big", "segment", 0, 0x8b53ae5c, too_big);
1540
LoadCommands commands;
1541
commands.Place(&command);
1544
file.Header(&commands).Place(&segment);
1546
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1548
Segment actual_segment;
1549
EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
1551
EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment"))
1552
.WillOnce(Return());
1553
EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler));
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.
1560
TEST_F(LoadCommand, ZappedSegment) {
1561
WithConfiguration config(kBigEndian, 32);
1564
LoadedSection segment;
1565
segment.address() = 0x696d83cc;
1566
segment.start() = 0;
1567
segment.final_size() = 0;
1570
LoadedSection section;
1571
section.address() = segment.address();
1572
section.start() = 0;
1573
section.final_size() = 1000; // extends beyond its segment
1575
SegmentLoadCommand command;
1577
.Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c)
1578
.AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section);
1580
LoadCommands commands;
1581
commands.Place(&command);
1584
file.Header(&commands);
1586
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1588
Segment actual_segment;
1589
EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment));
1591
ByteBuffer zapped_extent(NULL, 0);
1592
EXPECT_CALL(section_handler,
1593
HandleSection(MatchSection(false, "twitching", "zapped",
1594
0x696d83cc, 0, 0x93b3bd42,
1596
.WillOnce(Return(true));
1598
EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler));
1601
TEST_F(LoadCommand, MapSegmentSections) {
1602
WithConfiguration config(kLittleEndian, 32);
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");
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();
1621
SegmentLoadCommand segment_command1, segment_command2;
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);
1628
.Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33)
1629
.AppendSectionEntry("sixteenprecisely", "thorax",
1630
12, S_ZEROFILL, section2)
1631
.AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4);
1633
LoadCommands commands;
1634
commands.Place(&segment_command1).Place(&segment_command2);
1637
file.Header(&commands).Place(&segment1).Place(&segment2);
1639
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1642
SectionMap section_map;
1644
EXPECT_FALSE(reader.FindSegment("smoot", &segment));
1646
ASSERT_TRUE(reader.FindSegment("thorax", &segment));
1647
ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map));
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));
1663
ASSERT_TRUE(reader.FindSegment("head", &segment));
1664
ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map));
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));
1674
TEST_F(LoadCommand, FindSegment) {
1675
WithConfiguration config(kBigEndian, 32);
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.");
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);
1690
LoadCommands commands;
1691
commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
1694
file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3);
1696
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1698
Segment actual_segment;
1700
EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment));
1702
EXPECT_TRUE(reader.FindSegment("second", &actual_segment));
1703
EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr);
1709
// A StringAssembler is a class for generating .stabstr sections to present
1710
// as input to the STABS parser.
1711
class StringAssembler: public SizedSection {
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();
1722
// A SymbolAssembler is a class for generating .stab sections to present as
1723
// test input for the STABS parser.
1724
class SymbolAssembler: public SizedSection {
1726
// Create a SymbolAssembler that uses StringAssembler for its strings.
1727
explicit SymbolAssembler(StringAssembler *string_assembler)
1728
: string_assembler_(string_assembler),
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
1736
SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
1737
Label value, Label name) {
1742
Append(endianness(), word_size_ / 8, value);
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));
1754
// The strings for our STABS entries.
1755
StringAssembler *string_assembler_;
1757
// The number of entries in this compilation unit so far.
1758
size_t entry_count_;
1761
class Symtab: public ReaderFixture, public Test { };
1763
TEST_F(Symtab, Symtab32) {
1764
WithConfiguration config(kLittleEndian, 32);
1766
StringAssembler strings;
1767
SymbolAssembler symbols(&strings);
1769
.Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu")
1770
.Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith");
1772
SizedSection 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
1781
LoadCommands load_commands;
1782
load_commands.Place(&symtab_command);
1785
file.Header(&load_commands).Place(&symbols).Place(&strings);
1787
ReadFile(&file, true, CPU_TYPE_ANY, 0);
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),
1794
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1796
EXPECT_EQ(24U, symbols_found.Size());
1797
EXPECT_EQ(14U, strings_found.Size());
1800
TEST_F(Symtab, Symtab64) {
1801
WithConfiguration config(kBigEndian, 64);
1803
StringAssembler strings;
1804
SymbolAssembler symbols(&strings);
1806
.Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
1807
.Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
1809
SizedSection 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
1818
LoadCommands load_commands;
1819
load_commands.Place(&symtab_command);
1822
file.Header(&load_commands).Place(&symbols).Place(&strings);
1824
ReadFile(&file, true, CPU_TYPE_ANY, 0);
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),
1831
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1833
EXPECT_EQ(32U, symbols_found.Size());
1834
EXPECT_EQ(8U, strings_found.Size());
1837
TEST_F(Symtab, SymtabMisplacedSymbols) {
1838
WithConfiguration config(kBigEndian, 32);
1840
StringAssembler strings;
1841
SymbolAssembler symbols(&strings);
1843
.Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
1844
.Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
1846
SizedSection 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
1855
LoadCommands load_commands;
1856
load_commands.Place(&symtab_command);
1859
// Put symbols at end, so the excessive length will be noticed.
1860
file.Header(&load_commands).Place(&strings).Place(&symbols);
1862
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1864
EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
1865
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1868
TEST_F(Symtab, SymtabMisplacedStrings) {
1869
WithConfiguration config(kLittleEndian, 32);
1871
StringAssembler strings;
1872
SymbolAssembler symbols(&strings);
1874
.Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
1875
.Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
1877
SizedSection 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)
1886
LoadCommands load_commands;
1887
load_commands.Place(&symtab_command);
1890
// Put strings at end, so the excessive length will be noticed.
1891
file.Header(&load_commands).Place(&symbols).Place(&strings);
1893
ReadFile(&file, true, CPU_TYPE_ANY, 0);
1895
EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
1896
EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));