• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &section,
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 &section));
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 &section_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(&section2).Place(&section1);
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, &section_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, &section_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, &section_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, &section_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, &section_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(&section3).Place(&section1);
1616   segment2.set_word_size(64);
1617   segment2.address() = 0x04d462e2;
1618   segment2.Place(&section4);
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, &section_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, &section_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