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