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
43namespace mach_o = google_breakpad::mach_o;
44namespace test_assembler = google_breakpad::test_assembler;
45
46using mach_o::FatReader;
47using mach_o::FileFlags;
48using mach_o::FileType;
49using mach_o::LoadCommandType;
50using mach_o::Reader;
51using mach_o::Section;
52using mach_o::SectionMap;
53using mach_o::Segment;
54using test_assembler::Endianness;
55using test_assembler::Label;
56using test_assembler::kBigEndian;
57using test_assembler::kLittleEndian;
58using test_assembler::kUnsetEndian;
59using google_breakpad::ByteBuffer;
60using std::map;
61using std::string;
62using std::vector;
63using testing::AllOf;
64using testing::DoAll;
65using testing::Field;
66using testing::InSequence;
67using testing::Matcher;
68using testing::Return;
69using testing::SaveArg;
70using testing::Test;
71using testing::_;
72
73
74// Mock classes for the reader's various reporters and handlers.
75
76class MockFatReaderReporter: public FatReader::Reporter {
77 public:
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
85class MockReaderReporter: public Reader::Reporter {
86 public:
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
106class 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
113class 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.
123TEST(FatReaderReporter, BadHeader) {
124  FatReader::Reporter reporter("filename");
125  reporter.BadHeader();
126}
127
128TEST(FatReaderReporter, MisplacedObjectFile) {
129  FatReader::Reporter reporter("filename");
130  reporter.MisplacedObjectFile();
131}
132
133TEST(FatReaderReporter, TooShort) {
134  FatReader::Reporter reporter("filename");
135  reporter.TooShort();
136}
137
138TEST(MachOReaderReporter, BadHeader) {
139  Reader::Reporter reporter("filename");
140  reporter.BadHeader();
141}
142
143TEST(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
149TEST(MachOReaderReporter, HeaderTruncated) {
150  Reader::Reporter reporter("filename");
151  reporter.HeaderTruncated();
152}
153
154TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
155  Reader::Reporter reporter("filename");
156  reporter.LoadCommandRegionTruncated();
157}
158
159TEST(MachOReaderReporter, LoadCommandsOverrun) {
160  Reader::Reporter reporter("filename");
161  reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
162  reporter.LoadCommandsOverrun(10, 9, 0);
163}
164
165TEST(MachOReaderReporter, LoadCommandTooShort) {
166  Reader::Reporter reporter("filename");
167  reporter.LoadCommandTooShort(11, LC_SYMTAB);
168}
169
170TEST(MachOReaderReporter, SectionsMissing) {
171  Reader::Reporter reporter("filename");
172  reporter.SectionsMissing("segment name");
173}
174
175TEST(MachOReaderReporter, MisplacedSegmentData) {
176  Reader::Reporter reporter("filename");
177  reporter.MisplacedSegmentData("segment name");
178}
179
180TEST(MachOReaderReporter, MisplacedSectionData) {
181  Reader::Reporter reporter("filename");
182  reporter.MisplacedSectionData("section name", "segment name");
183}
184
185TEST(MachOReaderReporter, MisplacedSymbolTable) {
186  Reader::Reporter reporter("filename");
187  reporter.MisplacedSymbolTable();
188}
189
190TEST(MachOReaderReporter, UnsupportedCPUType) {
191  Reader::Reporter reporter("filename");
192  reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
193}
194
195struct FatReaderFixture {
196  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.
207  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.
218  void AppendDummyArchEntries(int n) {
219    for (int i = 0; i < n; i++)
220      AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1);
221  }
222  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
241class FatReaderTest: public FatReaderFixture, public Test { };
242
243TEST_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
252TEST_F(FatReaderTest, HeaderTooShort) {
253  EXPECT_CALL(reporter, TooShort()).Times(1);
254  fat
255      .B32(0xcafebabe);             // magic number
256  ReadFat(false);
257}
258
259TEST_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
274TEST_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
287TEST_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
295TEST_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
315TEST_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
361TEST_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
383TEST_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
405TEST_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
427TEST_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
449TEST_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.
465class WithConfiguration {
466 public:
467  // Establish the given parameters as the default for SizedSections
468  // created within the dynamic scope of this instance.
469  WithConfiguration(Endianness endianness, size_t word_size)
470      : endianness_(endianness), word_size_(word_size), saved_(current_) {
471    current_ = this;
472  }
473  ~WithConfiguration() { current_ = saved_; }
474  static Endianness endianness() {
475    assert(current_);
476    return current_->endianness_;
477  }
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
495WithConfiguration *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.
500class SizedSection: public test_assembler::Section {
501 public:
502  // Construct a section of the given endianness and 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  }
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.
514  size_t word_size() const { return 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.
522  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.
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.
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.
553class LoadedSection: public SizedSection {
554 public:
555  explicit LoadedSection(Label address = Label()) : address_(address) { }
556
557  // Return a label representing this section's address.
558  Label address() const { return address_; }
559
560  // Placing a loaded section within a loaded section sets the relationship
561  // between their addresses.
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.
574class SegmentLoadCommand: public SizedSection {
575 public:
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.
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.
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.
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:
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.
662class LoadCommands: public SizedSection {
663 public:
664  LoadCommands() : command_count_(0) { }
665
666  // Return a label representing the final load command count.
667  Label final_command_count() const { return final_command_count_; }
668
669  // Increment the command count; return a reference to this section.
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.
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.
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.
700class MachOFile: public SizedSection {
701 public:
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.
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
731struct ReaderFixture {
732  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
751  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
778class ReaderTest: public ReaderFixture, public Test { };
779
780TEST_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
798TEST_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
817TEST_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
827TEST_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
843TEST_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
864TEST_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
887TEST_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
910TEST_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
933TEST_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
959class LoadCommand: public ReaderFixture, public Test { };
960
961TEST_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
983TEST_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
1004TEST_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
1037TEST_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
1054TEST_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
1071TEST_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
1089TEST_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
1125TEST_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
1162TEST_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
1198TEST_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
1235TEST_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
1267TEST_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
1292TEST_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
1342static 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
1359static 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
1370TEST_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
1433TEST_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
1474TEST_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
1515TEST_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.
1560TEST_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
1601TEST_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
1674TEST_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.
1711class 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.
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.
1724class SymbolAssembler: public SizedSection {
1725 public:
1726  // Create a SymbolAssembler that uses StringAssembler for its strings.
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.
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.
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
1761class Symtab: public ReaderFixture, public Test { };
1762
1763TEST_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
1800TEST_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
1837TEST_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
1868TEST_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