xref: /aosp_15_r20/external/google-breakpad/src/common/mac/macho_reader_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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(&section2).Place(&section1);
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, &section_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, &section_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, &section_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, &section_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, &section_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, &section_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(&section3).Place(&section1);
1668   segment2.set_word_size(64);
1669   segment2.address() = 0x04d462e2;
1670   segment2.Place(&section4);
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, &section_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, &section_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