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