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