~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to thirdparty/breakpad/common/mac/macho_reader_unittest.cc

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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:
 
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:
 
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.
 
123
TEST(FatReaderReporter, BadHeader) {
 
124
  FatReader::Reporter reporter("filename");
 
125
  reporter.BadHeader();
 
126
}
 
127
 
 
128
TEST(FatReaderReporter, MisplacedObjectFile) {
 
129
  FatReader::Reporter reporter("filename");
 
130
  reporter.MisplacedObjectFile();
 
131
}
 
132
 
 
133
TEST(FatReaderReporter, TooShort) {
 
134
  FatReader::Reporter reporter("filename");
 
135
  reporter.TooShort();
 
136
}
 
137
 
 
138
TEST(MachOReaderReporter, BadHeader) {
 
139
  Reader::Reporter reporter("filename");
 
140
  reporter.BadHeader();
 
141
}
 
142
 
 
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
 
 
149
TEST(MachOReaderReporter, HeaderTruncated) {
 
150
  Reader::Reporter reporter("filename");
 
151
  reporter.HeaderTruncated();
 
152
}
 
153
 
 
154
TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
 
155
  Reader::Reporter reporter("filename");
 
156
  reporter.LoadCommandRegionTruncated();
 
157
}
 
158
 
 
159
TEST(MachOReaderReporter, LoadCommandsOverrun) {
 
160
  Reader::Reporter reporter("filename");
 
161
  reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
 
162
  reporter.LoadCommandsOverrun(10, 9, 0);
 
163
}
 
164
 
 
165
TEST(MachOReaderReporter, LoadCommandTooShort) {
 
166
  Reader::Reporter reporter("filename");
 
167
  reporter.LoadCommandTooShort(11, LC_SYMTAB);
 
168
}
 
169
 
 
170
TEST(MachOReaderReporter, SectionsMissing) {
 
171
  Reader::Reporter reporter("filename");
 
172
  reporter.SectionsMissing("segment name");
 
173
}
 
174
 
 
175
TEST(MachOReaderReporter, MisplacedSegmentData) {
 
176
  Reader::Reporter reporter("filename");
 
177
  reporter.MisplacedSegmentData("segment name");
 
178
}
 
179
 
 
180
TEST(MachOReaderReporter, MisplacedSectionData) {
 
181
  Reader::Reporter reporter("filename");
 
182
  reporter.MisplacedSectionData("section name", "segment name");
 
183
}
 
184
 
 
185
TEST(MachOReaderReporter, MisplacedSymbolTable) {
 
186
  Reader::Reporter reporter("filename");
 
187
  reporter.MisplacedSymbolTable();
 
188
}
 
189
 
 
190
TEST(MachOReaderReporter, UnsupportedCPUType) {
 
191
  Reader::Reporter reporter("filename");
 
192
  reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
 
193
}
 
194
 
 
195
struct 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
 
 
241
class FatReaderTest: public FatReaderFixture, public Test { };
 
242
 
 
243
TEST_F(FatReaderTest, BadMagic) {
 
244
  EXPECT_CALL(reporter, BadHeader()).Times(1);
 
245
  fat
 
246
      .B32(0xcafed00d)           // magic number (incorrect)
 
247
      .B32(10);                  // number of architectures
 
248
  AppendDummyArchEntries(10);
 
249
  ReadFat(false);
 
250
}
 
251
 
 
252
TEST_F(FatReaderTest, HeaderTooShort) {
 
253
  EXPECT_CALL(reporter, TooShort()).Times(1);
 
254
  fat
 
255
      .B32(0xcafebabe);             // magic number
 
256
  ReadFat(false);
 
257
}
 
258
 
 
259
TEST_F(FatReaderTest, ObjectListTooShort) {
 
260
  EXPECT_CALL(reporter, TooShort()).Times(1);
 
261
  fat
 
262
      .B32(0xcafebabe)              // magic number
 
263
      .B32(10);                     // number of architectures
 
264
  AppendDummyArchEntries(9);        // nine dummy architecture entries...
 
265
  fat                               // and a tenth, missing a byte at the end
 
266
      .B32(0x3d46c8fc)              // cpu type
 
267
      .B32(0x8a7bfb01)              // cpu subtype
 
268
      .B32(0)                       // offset
 
269
      .B32(0)                       // size
 
270
      .Append(3, '*');              // one byte short of a four-byte alignment
 
271
  ReadFat(false);
 
272
}
 
273
 
 
274
TEST_F(FatReaderTest, DataTooShort) {
 
275
  EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1);
 
276
  Label arch_data;
 
277
  fat
 
278
      .B32(0xcafebabe)              // magic number
 
279
      .B32(1);                      // number of architectures
 
280
  AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0);
 
281
  fat
 
282
      .Mark(&arch_data)             // file data begins here
 
283
      .Append(30, '*');             // only 30 bytes, not 40 as header claims
 
284
  ReadFat(false);
 
285
}
 
286
 
 
287
TEST_F(FatReaderTest, NoObjectFiles) {
 
288
  fat
 
289
      .B32(0xcafebabe)              // magic number
 
290
      .B32(0);                      // number of architectures
 
291
  ReadFat();
 
292
  EXPECT_EQ(0U, object_files_size);
 
293
}
 
294
 
 
295
TEST_F(FatReaderTest, OneObjectFile) {
 
296
  Label obj1_offset;
 
297
  fat
 
298
      .B32(0xcafebabe)              // magic number
 
299
      .B32(1);                      // number of architectures
 
300
  // First object file list entry
 
301
  AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2);
 
302
  // First object file data
 
303
  fat
 
304
      .Mark(&obj1_offset)           
 
305
      .Append(0x42, '*');           // dummy contents
 
306
  ReadFat();
 
307
  ASSERT_EQ(1U, object_files_size);
 
308
  EXPECT_EQ(0x5e3a6e91, object_files[0].cputype);
 
309
  EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype);
 
310
  EXPECT_EQ(obj1_offset.Value(), object_files[0].offset);
 
311
  EXPECT_EQ(0x42U, object_files[0].size);
 
312
  EXPECT_EQ(0x355b15b2U, object_files[0].align);
 
313
}
 
314
 
 
315
TEST_F(FatReaderTest, ThreeObjectFiles) {
 
316
  Label obj1, obj2, obj3;
 
317
  fat
 
318
      .B32(0xcafebabe)              // magic number
 
319
      .B32(3);                      // number of architectures
 
320
  // Three object file list entries.
 
321
  AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8);
 
322
  AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd);
 
323
  AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7);
 
324
  fat
 
325
      // First object file data
 
326
      .Mark(&obj1)           
 
327
      .Append(0xfb4, '*')           // dummy contents
 
328
      // Second object file data
 
329
      .Mark(&obj2)           
 
330
      .Append(0xc31, '%')           // dummy contents
 
331
      // Third object file data
 
332
      .Mark(&obj3)           
 
333
      .Append(0x4b3, '^');          // dummy contents
 
334
  
 
335
  ReadFat();
 
336
 
 
337
  ASSERT_EQ(3U, object_files_size);
 
338
 
 
339
  // First object file.
 
340
  EXPECT_EQ(0x0cb92c30, object_files[0].cputype);
 
341
  EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype);
 
342
  EXPECT_EQ(obj1.Value(), object_files[0].offset);
 
343
  EXPECT_EQ(0xfb4U, object_files[0].size);
 
344
  EXPECT_EQ(0x2615dbe8U, object_files[0].align);
 
345
 
 
346
  // Second object file.
 
347
  EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype);
 
348
  EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype);
 
349
  EXPECT_EQ(obj2.Value(), object_files[1].offset);
 
350
  EXPECT_EQ(0xc31U, object_files[1].size);
 
351
  EXPECT_EQ(0x83af6ffdU, object_files[1].align);
 
352
 
 
353
  // Third object file.
 
354
  EXPECT_EQ(0x3717276d, object_files[2].cputype);
 
355
  EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype);
 
356
  EXPECT_EQ(obj3.Value(), object_files[2].offset);
 
357
  EXPECT_EQ(0x4b3U, object_files[2].size);
 
358
  EXPECT_EQ(0x035267d7U, object_files[2].align);
 
359
}
 
360
 
 
361
TEST_F(FatReaderTest, BigEndianMachO32) {
 
362
  fat.set_endianness(kBigEndian);
 
363
  fat
 
364
      .D32(0xfeedface)                  // Mach-O file magic number
 
365
      .D32(0x1a9d0518)                  // cpu type
 
366
      .D32(0x1b779357)                  // cpu subtype
 
367
      .D32(0x009df67e)                  // file type
 
368
      .D32(0)                           // no load commands
 
369
      .D32(0)                           // the load commands occupy no bytes
 
370
      .D32(0x21987a99);                 // flags
 
371
 
 
372
  ReadFat();
 
373
 
 
374
  // FatReader should treat a Mach-O file as if it were a fat binary file
 
375
  // containing one object file --- the whole thing.
 
376
  ASSERT_EQ(1U, object_files_size);
 
377
  EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
 
378
  EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
 
379
  EXPECT_EQ(0U, object_files[0].offset);
 
380
  EXPECT_EQ(contents.size(), object_files[0].size);
 
381
}
 
382
 
 
383
TEST_F(FatReaderTest, BigEndianMachO64) {
 
384
  fat.set_endianness(kBigEndian);
 
385
  fat
 
386
      .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
 
387
      .D32(0x5aff8487)                  // cpu type
 
388
      .D32(0x4c6a57f7)                  // cpu subtype
 
389
      .D32(0x4392d2c8)                  // file type
 
390
      .D32(0)                           // no load commands
 
391
      .D32(0)                           // the load commands occupy no bytes
 
392
      .D32(0x1b033eea);                 // flags
 
393
 
 
394
  ReadFat();
 
395
 
 
396
  // FatReader should treat a Mach-O file as if it were a fat binary file
 
397
  // containing one object file --- the whole thing.
 
398
  ASSERT_EQ(1U, object_files_size);
 
399
  EXPECT_EQ(0x5aff8487, object_files[0].cputype);
 
400
  EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
 
401
  EXPECT_EQ(0U, object_files[0].offset);
 
402
  EXPECT_EQ(contents.size(), object_files[0].size);
 
403
}
 
404
 
 
405
TEST_F(FatReaderTest, LittleEndianMachO32) {
 
406
  fat.set_endianness(kLittleEndian);
 
407
  fat
 
408
      .D32(0xfeedface)                  // Mach-O file magic number
 
409
      .D32(0x1a9d0518)                  // cpu type
 
410
      .D32(0x1b779357)                  // cpu subtype
 
411
      .D32(0x009df67e)                  // file type
 
412
      .D32(0)                           // no load commands
 
413
      .D32(0)                           // the load commands occupy no bytes
 
414
      .D32(0x21987a99);                 // flags
 
415
 
 
416
  ReadFat();
 
417
 
 
418
  // FatReader should treat a Mach-O file as if it were a fat binary file
 
419
  // containing one object file --- the whole thing.
 
420
  ASSERT_EQ(1U, object_files_size);
 
421
  EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
 
422
  EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
 
423
  EXPECT_EQ(0U, object_files[0].offset);
 
424
  EXPECT_EQ(contents.size(), object_files[0].size);
 
425
}
 
426
 
 
427
TEST_F(FatReaderTest, LittleEndianMachO64) {
 
428
  fat.set_endianness(kLittleEndian);
 
429
  fat
 
430
      .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
 
431
      .D32(0x5aff8487)                  // cpu type
 
432
      .D32(0x4c6a57f7)                  // cpu subtype
 
433
      .D32(0x4392d2c8)                  // file type
 
434
      .D32(0)                           // no load commands
 
435
      .D32(0)                           // the load commands occupy no bytes
 
436
      .D32(0x1b033eea);                 // flags
 
437
 
 
438
  ReadFat();
 
439
 
 
440
  // FatReader should treat a Mach-O file as if it were a fat binary file
 
441
  // containing one object file --- the whole thing.
 
442
  ASSERT_EQ(1U, object_files_size);
 
443
  EXPECT_EQ(0x5aff8487, object_files[0].cputype);
 
444
  EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
 
445
  EXPECT_EQ(0U, object_files[0].offset);
 
446
  EXPECT_EQ(contents.size(), object_files[0].size);
 
447
}
 
448
 
 
449
TEST_F(FatReaderTest, IncompleteMach) {
 
450
  fat.set_endianness(kLittleEndian);
 
451
  fat
 
452
      .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
 
453
      .D32(0x5aff8487);                 // cpu type
 
454
      // Truncated!
 
455
 
 
456
  EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
 
457
 
 
458
  ReadFat(false);
 
459
}
 
460
 
 
461
 
 
462
// General mach_o::Reader tests.
 
463
 
 
464
// Dynamically scoped configuration data.
 
465
class WithConfiguration {
 
466
 public:
 
467
  // Establish the given parameters as the default for SizedSections
 
468
  // created within the dynamic scope of this instance.
 
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
 
 
495
WithConfiguration *WithConfiguration::current_ = NULL;
 
496
 
 
497
// A test_assembler::Section with a size that we can cite. The start(),
 
498
// Here() and Mark() member functions of a SizedSection always represent
 
499
// offsets within the overall file.
 
500
class SizedSection: public test_assembler::Section {
 
501
 public:
 
502
  // Construct a section of the given endianness and word size.
 
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.
 
553
class 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.
 
574
class 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.
 
662
class 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.
 
700
class 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
 
 
731
struct 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
 
 
778
class ReaderTest: public ReaderFixture, public Test { };
 
779
 
 
780
TEST_F(ReaderTest, BadMagic) {
 
781
  WithConfiguration config(kLittleEndian, 32);
 
782
  const cpu_type_t kCPUType = 0x46b760df;
 
783
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
784
  MachOFile file;
 
785
  file
 
786
      .D32(0x67bdebe1)                  // Not a proper magic number.
 
787
      .D32(kCPUType)                    // cpu type
 
788
      .D32(kCPUSubType)                 // cpu subtype
 
789
      .D32(0x149fc717)                  // file type
 
790
      .D32(0)                           // no load commands
 
791
      .D32(0)                           // they occupy no bytes
 
792
      .D32(0x80e71d64)                  // flags
 
793
      .D32(0);                          // reserved
 
794
  EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
 
795
  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
 
796
}
 
797
 
 
798
TEST_F(ReaderTest, MismatchedMagic) {
 
799
  WithConfiguration config(kLittleEndian, 32);
 
800
  const cpu_type_t kCPUType = CPU_TYPE_I386;
 
801
  const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
 
802
  MachOFile file;
 
803
  file
 
804
      .D32(MH_CIGAM)                    // Right magic, but winds up wrong
 
805
                                        // due to bitswapping
 
806
      .D32(kCPUType)                    // cpu type
 
807
      .D32(kCPUSubType)                 // cpu subtype
 
808
      .D32(0x149fc717)                  // file type
 
809
      .D32(0)                           // no load commands
 
810
      .D32(0)                           // they occupy no bytes
 
811
      .D32(0x80e71d64)                  // flags
 
812
      .D32(0);                          // reserved
 
813
  EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
 
814
  ReadFile(&file, false, kCPUType, kCPUSubType);
 
815
}
 
816
 
 
817
TEST_F(ReaderTest, ShortMagic) {
 
818
  WithConfiguration config(kBigEndian, 32);
 
819
  MachOFile file;
 
820
  file
 
821
      .D16(0xfeed);                     // magic number
 
822
                                        // truncated!
 
823
  EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
 
824
  ReadFile(&file, false, CPU_TYPE_ANY, 0);
 
825
}
 
826
 
 
827
TEST_F(ReaderTest, ShortHeader) {
 
828
  WithConfiguration config(kBigEndian, 32);
 
829
  const cpu_type_t kCPUType = CPU_TYPE_ANY;
 
830
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
831
  MachOFile file;
 
832
  file
 
833
      .D32(0xfeedface)                  // magic number
 
834
      .D32(kCPUType)                    // cpu type
 
835
      .D32(kCPUSubType)                 // cpu subtype
 
836
      .D32(0x149fc717)                  // file type
 
837
      .D32(0)                           // no load commands
 
838
      .D32(0);                          // they occupy no bytes
 
839
  EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
 
840
  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
 
841
}
 
842
 
 
843
TEST_F(ReaderTest, MismatchedCPU) {
 
844
  WithConfiguration config(kBigEndian, 32);
 
845
  const cpu_type_t kCPUType = CPU_TYPE_I386;
 
846
  const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
 
847
  MachOFile file;
 
848
  file
 
849
      .D32(MH_MAGIC)                    // Right magic for PPC (once bitswapped)
 
850
      .D32(kCPUType)                    // cpu type
 
851
      .D32(kCPUSubType)                 // cpu subtype
 
852
      .D32(0x149fc717)                  // file type
 
853
      .D32(0)                           // no load commands
 
854
      .D32(0)                           // they occupy no bytes
 
855
      .D32(0x80e71d64)                  // flags
 
856
      .D32(0);                          // reserved
 
857
  EXPECT_CALL(reporter,
 
858
              CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
 
859
                              CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL))
 
860
    .WillOnce(Return());
 
861
  ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
 
862
}
 
863
 
 
864
TEST_F(ReaderTest, LittleEndian32Bit) {
 
865
  WithConfiguration config(kLittleEndian, 32);
 
866
  const cpu_type_t kCPUType = 0x46b760df;
 
867
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
868
  MachOFile file;
 
869
  file
 
870
      .D32(0xfeedface)                  // magic number
 
871
      .D32(kCPUType)                    // cpu type
 
872
      .D32(kCPUSubType)                 // cpu subtype
 
873
      .D32(0x149fc717)                  // file type
 
874
      .D32(0)                           // no load commands
 
875
      .D32(0)                           // they occupy no bytes
 
876
      .D32(0x80e71d64)                  // flags
 
877
      .D32(0);                          // reserved
 
878
           ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
 
879
  EXPECT_FALSE(reader.bits_64());
 
880
  EXPECT_FALSE(reader.big_endian());
 
881
  EXPECT_EQ(kCPUType,               reader.cpu_type());
 
882
  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
 
883
  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
 
884
  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
 
885
}
 
886
 
 
887
TEST_F(ReaderTest, LittleEndian64Bit) {
 
888
  WithConfiguration config(kLittleEndian, 64);
 
889
  const cpu_type_t kCPUType = 0x46b760df;
 
890
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
891
  MachOFile file;
 
892
  file
 
893
      .D32(0xfeedfacf)                  // magic number
 
894
      .D32(kCPUType)                    // cpu type
 
895
      .D32(kCPUSubType)                 // cpu subtype
 
896
      .D32(0x149fc717)                  // file type
 
897
      .D32(0)                           // no load commands
 
898
      .D32(0)                           // they occupy no bytes
 
899
      .D32(0x80e71d64)                  // flags
 
900
      .D32(0);                          // reserved
 
901
  ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
 
902
  EXPECT_TRUE(reader.bits_64());
 
903
  EXPECT_FALSE(reader.big_endian());
 
904
  EXPECT_EQ(kCPUType,               reader.cpu_type());
 
905
  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
 
906
  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
 
907
  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
 
908
}
 
909
 
 
910
TEST_F(ReaderTest, BigEndian32Bit) {
 
911
  WithConfiguration config(kBigEndian, 32);
 
912
  const cpu_type_t kCPUType = 0x46b760df;
 
913
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
914
  MachOFile file;
 
915
  file
 
916
      .D32(0xfeedface)                  // magic number
 
917
      .D32(kCPUType)                    // cpu type
 
918
      .D32(kCPUSubType)                 // cpu subtype
 
919
      .D32(0x149fc717)                  // file type
 
920
      .D32(0)                           // no load commands
 
921
      .D32(0)                           // they occupy no bytes
 
922
      .D32(0x80e71d64)                  // flags
 
923
      .D32(0);                          // reserved
 
924
  ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
 
925
  EXPECT_FALSE(reader.bits_64());
 
926
  EXPECT_TRUE(reader.big_endian());
 
927
  EXPECT_EQ(kCPUType,               reader.cpu_type());
 
928
  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
 
929
  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
 
930
  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
 
931
}
 
932
 
 
933
TEST_F(ReaderTest, BigEndian64Bit) {
 
934
  WithConfiguration config(kBigEndian, 64);
 
935
  const cpu_type_t kCPUType = 0x46b760df;
 
936
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
937
  MachOFile file;
 
938
  file
 
939
      .D32(0xfeedfacf)                  // magic number
 
940
      .D32(kCPUType)                    // cpu type
 
941
      .D32(kCPUSubType)                 // cpu subtype
 
942
      .D32(0x149fc717)                  // file type
 
943
      .D32(0)                           // no load commands
 
944
      .D32(0)                           // they occupy no bytes
 
945
      .D32(0x80e71d64)                  // flags
 
946
      .D32(0);                          // reserved
 
947
  ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
 
948
  EXPECT_TRUE(reader.bits_64());
 
949
  EXPECT_TRUE(reader.big_endian());
 
950
  EXPECT_EQ(kCPUType,               reader.cpu_type());
 
951
  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
 
952
  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
 
953
  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
 
954
}
 
955
 
 
956
 
 
957
// Load command tests.
 
958
 
 
959
class LoadCommand: public ReaderFixture, public Test { };
 
960
 
 
961
TEST_F(LoadCommand, RegionTruncated) {
 
962
  WithConfiguration config(kBigEndian, 64);
 
963
  const cpu_type_t kCPUType = 0x46b760df;
 
964
  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
 
965
  MachOFile file;
 
966
  file
 
967
      .D32(0xfeedfacf)                  // magic number
 
968
      .D32(kCPUType)                    // cpu type
 
969
      .D32(kCPUSubType)                 // cpu subtype
 
970
      .D32(0x149fc717)                  // file type
 
971
      .D32(1)                           // one load command
 
972
      .D32(40)                          // occupying 40 bytes
 
973
      .D32(0x80e71d64)                  // flags
 
974
      .D32(0)                           // reserved
 
975
      .Append(20, 0);                   // load command region, not as long as
 
976
                                        // Mach-O header promised
 
977
 
 
978
  EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
 
979
 
 
980
  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
 
981
}
 
982
 
 
983
TEST_F(LoadCommand, None) {
 
984
  WithConfiguration config(kLittleEndian, 32);
 
985
  LoadCommands load_commands;
 
986
  MachOFile file;
 
987
  file.Header(&load_commands);
 
988
 
 
989
  ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
 
990
 
 
991
  EXPECT_FALSE(reader.bits_64());
 
992
  EXPECT_FALSE(reader.big_endian());
 
993
  EXPECT_EQ(CPU_TYPE_X86,         reader.cpu_type());
 
994
  EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
 
995
  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
 
996
  EXPECT_EQ(FileFlags(MH_TWOLEVEL |
 
997
                      MH_DYLDLINK |
 
998
                      MH_NOUNDEFS),
 
999
            FileFlags(reader.flags()));
 
1000
  
 
1001
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1002
}
 
1003
 
 
1004
TEST_F(LoadCommand, Unknown) {
 
1005
  WithConfiguration config(kBigEndian, 32);
 
1006
  LoadCommands load_commands;
 
1007
  load_commands
 
1008
      .CountCommand()
 
1009
      .D32(0x33293d4a)                  // unknown load command
 
1010
      .D32(40)                          // total size in bytes
 
1011
      .Append(32, '*');                 // dummy data
 
1012
  MachOFile file;
 
1013
  file.Header(&load_commands);
 
1014
 
 
1015
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1016
 
 
1017
  EXPECT_FALSE(reader.bits_64());
 
1018
  EXPECT_TRUE(reader.big_endian());
 
1019
  EXPECT_EQ(CPU_TYPE_X86,         reader.cpu_type());
 
1020
  EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
 
1021
  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
 
1022
  EXPECT_EQ(FileFlags(MH_TWOLEVEL |
 
1023
                      MH_DYLDLINK |
 
1024
                      MH_NOUNDEFS),
 
1025
            reader.flags());
 
1026
 
 
1027
  ByteBuffer expected;
 
1028
  expected.start = file_bytes + load_commands.start().Value();
 
1029
  expected.end = expected.start + load_commands.final_size().Value();
 
1030
  EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a,
 
1031
                                                   expected))
 
1032
      .WillOnce(Return(true));
 
1033
 
 
1034
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1035
}
 
1036
 
 
1037
TEST_F(LoadCommand, TypeIncomplete) {
 
1038
  WithConfiguration config(kLittleEndian, 32);
 
1039
  LoadCommands load_commands;
 
1040
  load_commands
 
1041
      .CountCommand()
 
1042
      .Append(3, 0);                    // load command type, incomplete
 
1043
 
 
1044
  MachOFile file;
 
1045
  file.Header(&load_commands);
 
1046
 
 
1047
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1048
 
 
1049
  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
 
1050
      .WillOnce(Return());
 
1051
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1052
}
 
1053
 
 
1054
TEST_F(LoadCommand, LengthIncomplete) {
 
1055
  WithConfiguration config(kBigEndian, 64);
 
1056
  LoadCommands load_commands;
 
1057
  load_commands
 
1058
      .CountCommand()
 
1059
      .D32(LC_SEGMENT);                 // load command
 
1060
                                                // no length
 
1061
  MachOFile file;
 
1062
  file.Header(&load_commands);
 
1063
 
 
1064
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1065
 
 
1066
  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
 
1067
      .WillOnce(Return());
 
1068
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1069
}
 
1070
 
 
1071
TEST_F(LoadCommand, ContentIncomplete) {
 
1072
  WithConfiguration config(kLittleEndian, 64);
 
1073
  LoadCommands load_commands;
 
1074
  load_commands
 
1075
      .CountCommand()
 
1076
      .D32(LC_SEGMENT)          // load command
 
1077
      .D32(40)                          // total size in bytes
 
1078
      .Append(28, '*');                 // not enough dummy data
 
1079
  MachOFile file;
 
1080
  file.Header(&load_commands);
 
1081
 
 
1082
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1083
 
 
1084
  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
 
1085
      .WillOnce(Return());
 
1086
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1087
}
 
1088
 
 
1089
TEST_F(LoadCommand, SegmentBE32) {
 
1090
  WithConfiguration config(kBigEndian, 32);
 
1091
  LoadedSection segment;
 
1092
  segment.address() = 0x1891139c;
 
1093
  segment.Append(42, '*');              // segment contents
 
1094
  SegmentLoadCommand segment_command;
 
1095
  segment_command
 
1096
      .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd);
 
1097
  segment_command.vmsize() = 0xcb76584fU;
 
1098
  LoadCommands load_commands;
 
1099
  load_commands.Place(&segment_command);
 
1100
  MachOFile file;
 
1101
  file
 
1102
      .Header(&load_commands)
 
1103
      .Place(&segment);
 
1104
 
 
1105
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1106
 
 
1107
  Segment actual_segment;
 
1108
  EXPECT_CALL(load_command_handler, SegmentCommand(_))
 
1109
    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
 
1110
                    Return(true)));
 
1111
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1112
 
 
1113
  EXPECT_EQ(false,                        actual_segment.bits_64);
 
1114
  EXPECT_EQ("froon",                      actual_segment.name);
 
1115
  EXPECT_EQ(0x1891139cU,                  actual_segment.vmaddr);
 
1116
  EXPECT_EQ(0xcb76584fU,                  actual_segment.vmsize);
 
1117
  EXPECT_EQ(0x94d6dd22U,                  actual_segment.maxprot);
 
1118
  EXPECT_EQ(0x8bdbc319U,                  actual_segment.initprot);
 
1119
  EXPECT_EQ(0x990a16ddU,                  actual_segment.flags);
 
1120
  EXPECT_EQ(0U,                           actual_segment.nsects);
 
1121
  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
 
1122
  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
 
1123
}
 
1124
 
 
1125
TEST_F(LoadCommand, SegmentLE32) {
 
1126
  WithConfiguration config(kLittleEndian, 32);
 
1127
  LoadedSection segment;
 
1128
  segment.address() = 0x4b877866;
 
1129
  segment.Append(42, '*');              // segment contents
 
1130
  SegmentLoadCommand segment_command;
 
1131
  segment_command
 
1132
      .Header("sixteenprecisely", segment,
 
1133
              0x350759ed, 0x6cf5a62e, 0x990a16dd);
 
1134
  segment_command.vmsize() = 0xcb76584fU;
 
1135
  LoadCommands load_commands;
 
1136
  load_commands.Place(&segment_command);
 
1137
  MachOFile file;
 
1138
  file
 
1139
      .Header(&load_commands)
 
1140
      .Place(&segment);
 
1141
 
 
1142
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1143
 
 
1144
  Segment actual_segment;
 
1145
  EXPECT_CALL(load_command_handler, SegmentCommand(_))
 
1146
    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
 
1147
                    Return(true)));
 
1148
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1149
 
 
1150
  EXPECT_EQ(false,                        actual_segment.bits_64);
 
1151
  EXPECT_EQ("sixteenprecisely",           actual_segment.name);
 
1152
  EXPECT_EQ(0x4b877866U,                  actual_segment.vmaddr);
 
1153
  EXPECT_EQ(0xcb76584fU,                  actual_segment.vmsize);
 
1154
  EXPECT_EQ(0x350759edU,                  actual_segment.maxprot);
 
1155
  EXPECT_EQ(0x6cf5a62eU,                  actual_segment.initprot);
 
1156
  EXPECT_EQ(0x990a16ddU,                  actual_segment.flags);
 
1157
  EXPECT_EQ(0U,                           actual_segment.nsects);
 
1158
  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
 
1159
  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
 
1160
}
 
1161
 
 
1162
TEST_F(LoadCommand, SegmentBE64) {
 
1163
  WithConfiguration config(kBigEndian, 64);
 
1164
  LoadedSection segment;
 
1165
  segment.address() = 0x79f484f77009e511ULL;
 
1166
  segment.Append(42, '*');              // segment contents
 
1167
  SegmentLoadCommand segment_command;
 
1168
  segment_command
 
1169
      .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220);
 
1170
  segment_command.vmsize() = 0x8d92397ce6248abaULL;
 
1171
  LoadCommands load_commands;
 
1172
  load_commands.Place(&segment_command);
 
1173
  MachOFile file;
 
1174
  file
 
1175
      .Header(&load_commands)
 
1176
      .Place(&segment);
 
1177
 
 
1178
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1179
 
 
1180
  Segment actual_segment;
 
1181
  EXPECT_CALL(load_command_handler, SegmentCommand(_))
 
1182
    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
 
1183
                    Return(true)));
 
1184
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1185
 
 
1186
  EXPECT_EQ(true,                         actual_segment.bits_64);
 
1187
  EXPECT_EQ("froon",                      actual_segment.name);
 
1188
  EXPECT_EQ(0x79f484f77009e511ULL,        actual_segment.vmaddr);
 
1189
  EXPECT_EQ(0x8d92397ce6248abaULL,        actual_segment.vmsize);
 
1190
  EXPECT_EQ(0x42b45da5U,                  actual_segment.maxprot);
 
1191
  EXPECT_EQ(0x8bdbc319U,                  actual_segment.initprot);
 
1192
  EXPECT_EQ(0xb2335220U,                  actual_segment.flags);
 
1193
  EXPECT_EQ(0U,                           actual_segment.nsects);
 
1194
  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
 
1195
  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
 
1196
}
 
1197
 
 
1198
TEST_F(LoadCommand, SegmentLE64) {
 
1199
  WithConfiguration config(kLittleEndian, 64);
 
1200
  LoadedSection segment;
 
1201
  segment.address() = 0x50c0501dc5922d35ULL;
 
1202
  segment.Append(42, '*');              // segment contents
 
1203
  SegmentLoadCommand segment_command;
 
1204
  segment_command
 
1205
      .Header("sixteenprecisely", segment,
 
1206
              0x917c339d, 0xdbc446fa, 0xb650b563);
 
1207
  segment_command.vmsize() = 0x84ae73e7c75469bfULL;
 
1208
  LoadCommands load_commands;
 
1209
  load_commands.Place(&segment_command);
 
1210
  MachOFile file;
 
1211
  file
 
1212
      .Header(&load_commands)
 
1213
      .Place(&segment);
 
1214
 
 
1215
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1216
 
 
1217
  Segment actual_segment;
 
1218
  EXPECT_CALL(load_command_handler, SegmentCommand(_))
 
1219
    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
 
1220
                    Return(true)));
 
1221
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1222
 
 
1223
  EXPECT_EQ(true,                         actual_segment.bits_64);
 
1224
  EXPECT_EQ("sixteenprecisely",           actual_segment.name);
 
1225
  EXPECT_EQ(0x50c0501dc5922d35ULL,        actual_segment.vmaddr);
 
1226
  EXPECT_EQ(0x84ae73e7c75469bfULL,        actual_segment.vmsize);
 
1227
  EXPECT_EQ(0x917c339dU,                  actual_segment.maxprot);
 
1228
  EXPECT_EQ(0xdbc446faU,                  actual_segment.initprot);
 
1229
  EXPECT_EQ(0xb650b563U,                  actual_segment.flags);
 
1230
  EXPECT_EQ(0U,                           actual_segment.nsects);
 
1231
  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
 
1232
  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
 
1233
}
 
1234
 
 
1235
TEST_F(LoadCommand, SegmentCommandTruncated) {
 
1236
  WithConfiguration config(kBigEndian, 32);
 
1237
  LoadedSection segment_contents;
 
1238
  segment_contents.Append(20, '*');             // lah di dah
 
1239
  SizedSection command;
 
1240
  command
 
1241
      .D32(LC_SEGMENT)                  // command type
 
1242
      .D32(command.final_size())                // command size
 
1243
      .AppendCString("too-short", 16)           // segment name
 
1244
      .D32(0x9c759211)                          // vmaddr
 
1245
      .D32(segment_contents.final_size())       // vmsize
 
1246
      .D32(segment_contents.start())            // file offset
 
1247
      .D32(segment_contents.final_size())       // file size
 
1248
      .D32(0x56f28446)                          // max protection
 
1249
      .D32(0xe7910dcb)                          // initial protection
 
1250
      .D32(0)                                   // no sections
 
1251
      .Append(3, 0);                            // flags (one byte short!)
 
1252
  LoadCommands load_commands;
 
1253
  load_commands.Place(&command);
 
1254
  MachOFile file;
 
1255
  file
 
1256
      .Header(&load_commands)
 
1257
      .Place(&segment_contents);
 
1258
  
 
1259
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1260
 
 
1261
  EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
 
1262
      .WillOnce(Return());
 
1263
 
 
1264
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1265
}
 
1266
 
 
1267
TEST_F(LoadCommand, SegmentBadContentOffset) {
 
1268
  WithConfiguration config(kLittleEndian, 32);
 
1269
  // Instead of letting a Place call set the segment's file offset and size,
 
1270
  // set them ourselves, to check that the parser catches invalid offsets
 
1271
  // instead of handing us bogus pointers.
 
1272
  LoadedSection segment;
 
1273
  segment.address() = 0x4db5489c;
 
1274
  segment.start() = 0x7e189e76;         // beyond end of file
 
1275
  segment.final_size() = 0x98b9c3ab;
 
1276
  SegmentLoadCommand segment_command;
 
1277
  segment_command
 
1278
      .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f);
 
1279
  LoadCommands load_commands;
 
1280
  load_commands.Place(&segment_command);
 
1281
  MachOFile file;
 
1282
  file.Header(&load_commands);
 
1283
 
 
1284
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1285
 
 
1286
  EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
 
1287
      .WillOnce(Return());
 
1288
 
 
1289
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1290
}
 
1291
 
 
1292
TEST_F(LoadCommand, ThreeLoadCommands) {
 
1293
  WithConfiguration config(kBigEndian, 32);
 
1294
  LoadedSection seg1, seg2, seg3;
 
1295
  SegmentLoadCommand cmd1, cmd2, cmd3;
 
1296
 
 
1297
  seg1.Append(128, '@');
 
1298
  seg1.address() = 0xa7f61ef6;
 
1299
  cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87);
 
1300
  // Include some dummy data at the end of the load command. Since we
 
1301
  // didn't claim to have any sections, the reader should ignore this. But
 
1302
  // making sure the commands have different lengths ensures that we're
 
1303
  // using the right command's length to advance the LoadCommandIterator.
 
1304
  cmd1.Append(128, '!');
 
1305
 
 
1306
  seg2.Append(42, '*');
 
1307
  seg2.address() = 0xc70fc909;
 
1308
  cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30);
 
1309
  // More dummy data at the end of the load command. 
 
1310
  cmd2.Append(32, '^');
 
1311
 
 
1312
  seg3.Append(42, '%');
 
1313
  seg3.address() = 0x46b3ab05;
 
1314
  cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b);
 
1315
  // More dummy data at the end of the load command. 
 
1316
  cmd3.Append(64, '&');
 
1317
 
 
1318
  LoadCommands load_commands;
 
1319
  load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
 
1320
 
 
1321
  MachOFile file;
 
1322
  file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
 
1323
 
 
1324
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1325
 
 
1326
  {
 
1327
    InSequence s;
 
1328
    EXPECT_CALL(load_command_handler,
 
1329
                SegmentCommand(Field(&Segment::name, "head")))
 
1330
      .WillOnce(Return(true));
 
1331
    EXPECT_CALL(load_command_handler,
 
1332
                SegmentCommand(Field(&Segment::name, "thorax")))
 
1333
      .WillOnce(Return(true));
 
1334
    EXPECT_CALL(load_command_handler,
 
1335
                SegmentCommand(Field(&Segment::name, "abdomen")))
 
1336
      .WillOnce(Return(true));
 
1337
  }
 
1338
 
 
1339
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1340
}
 
1341
 
 
1342
static inline Matcher<const Section &> MatchSection(
 
1343
    Matcher<bool> bits_64,
 
1344
    Matcher<const string &> section_name,
 
1345
    Matcher<const string &> segment_name,
 
1346
    Matcher<uint64_t> address,
 
1347
    Matcher<uint32_t> alignment,
 
1348
    Matcher<uint32_t> flags,
 
1349
    Matcher<const ByteBuffer &> contents) {
 
1350
  return AllOf(AllOf(Field(&Section::bits_64, bits_64),
 
1351
                     Field(&Section::section_name, section_name),
 
1352
                     Field(&Section::segment_name, segment_name),
 
1353
                     Field(&Section::address, address)),
 
1354
               AllOf(Field(&Section::align, alignment),
 
1355
                     Field(&Section::flags, flags),
 
1356
                     Field(&Section::contents, contents)));
 
1357
}
 
1358
 
 
1359
static inline Matcher<const Section &> MatchSection(
 
1360
    Matcher<bool> bits_64,
 
1361
    Matcher<const string &> section_name,
 
1362
    Matcher<const string &> segment_name,
 
1363
    Matcher<uint64_t> address) {
 
1364
  return AllOf(Field(&Section::bits_64, bits_64),
 
1365
               Field(&Section::section_name, section_name),
 
1366
               Field(&Section::segment_name, segment_name),
 
1367
               Field(&Section::address, address));
 
1368
}
 
1369
 
 
1370
TEST_F(LoadCommand, OneSegmentTwoSections) {
 
1371
  WithConfiguration config(kBigEndian, 64);
 
1372
 
 
1373
  // Create some sections with some data.
 
1374
  LoadedSection section1, section2;
 
1375
  section1.Append("buddha's hand");
 
1376
  section2.Append("kumquat");
 
1377
 
 
1378
  // Create a segment to hold them.
 
1379
  LoadedSection segment;
 
1380
  segment.address() = 0xe1d0eeec;
 
1381
  segment.Place(&section2).Place(&section1);
 
1382
 
 
1383
  SegmentLoadCommand segment_command;
 
1384
  segment_command
 
1385
      .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2)
 
1386
      .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1)
 
1387
      .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2);
 
1388
 
 
1389
  LoadCommands commands;
 
1390
  commands.Place(&segment_command);
 
1391
 
 
1392
  MachOFile file;
 
1393
  file.Header(&commands).Place(&segment);
 
1394
 
 
1395
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1396
  
 
1397
  Segment actual_segment;
 
1398
  EXPECT_CALL(load_command_handler, SegmentCommand(_))
 
1399
      .WillOnce(DoAll(SaveArg<0>(&actual_segment),
 
1400
                      Return(true)));
 
1401
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1402
 
 
1403
  {
 
1404
    InSequence s;
 
1405
    ByteBuffer contents1;
 
1406
    contents1.start = file_bytes + section1.start().Value();
 
1407
    contents1.end = contents1.start + section1.final_size().Value();
 
1408
    EXPECT_EQ("buddha's hand",
 
1409
              string(reinterpret_cast<const char *>(contents1.start),
 
1410
                     contents1.Size()));
 
1411
    EXPECT_CALL(section_handler,
 
1412
                HandleSection(MatchSection(true, "mandarin", "kishu",
 
1413
                                           section1.address().Value(), 12,
 
1414
                                           0x8cd4604bU, contents1)))
 
1415
      .WillOnce(Return(true));
 
1416
    
 
1417
    ByteBuffer contents2;
 
1418
    contents2.start = file_bytes + section2.start().Value();
 
1419
    contents2.end = contents2.start + section2.final_size().Value();
 
1420
    EXPECT_EQ("kumquat",
 
1421
              string(reinterpret_cast<const char *>(contents2.start),
 
1422
                     contents2.Size()));
 
1423
    EXPECT_CALL(section_handler,
 
1424
                HandleSection(MatchSection(true, "bergamot", "cara cara",
 
1425
                                           section2.address().Value(), 12,
 
1426
                                           0x98746efaU, contents2)))
 
1427
      .WillOnce(Return(true));
 
1428
  }
 
1429
 
 
1430
  EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
 
1431
}
 
1432
 
 
1433
TEST_F(LoadCommand, MisplacedSectionBefore) {
 
1434
  WithConfiguration config(kLittleEndian, 64);
 
1435
 
 
1436
  // The segment.
 
1437
  LoadedSection segment;
 
1438
  segment.address() = 0x696d83cc;
 
1439
  segment.Append(10, '0');
 
1440
 
 
1441
  // The contents of the following sections don't matter, because
 
1442
  // we're not really going to Place them in segment; we're just going
 
1443
  // to set all their labels by hand to get the (impossible)
 
1444
  // configurations we want.
 
1445
 
 
1446
  // A section whose starting offset is before that of its section.
 
1447
  LoadedSection before;
 
1448
  before.Append(10, '1');
 
1449
  before.start()   = segment.start() - 1;
 
1450
  before.address() = segment.address() - 1;
 
1451
  before.final_size() = before.Size();
 
1452
  
 
1453
  SegmentLoadCommand command;
 
1454
  command
 
1455
    .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
 
1456
    .AppendSectionEntry("before",     "segment", 0, 0x686c6921, before);
 
1457
 
 
1458
  LoadCommands commands;
 
1459
  commands.Place(&command);
 
1460
 
 
1461
  MachOFile file;
 
1462
  file.Header(&commands).Place(&segment);
 
1463
 
 
1464
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1465
 
 
1466
  Segment actual_segment;
 
1467
  EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
 
1468
 
 
1469
  EXPECT_CALL(reporter, MisplacedSectionData("before", "segment"))
 
1470
    .WillOnce(Return());
 
1471
  EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
 
1472
}
 
1473
 
 
1474
TEST_F(LoadCommand, MisplacedSectionAfter) {
 
1475
  WithConfiguration config(kLittleEndian, 64);
 
1476
 
 
1477
  // The segment.
 
1478
  LoadedSection segment;
 
1479
  segment.address() = 0x696d83cc;
 
1480
  segment.Append(10, '0');
 
1481
 
 
1482
  // The contents of the following sections don't matter, because
 
1483
  // we're not really going to Place them in segment; we're just going
 
1484
  // to set all their labels by hand to get the (impossible)
 
1485
  // configurations we want.
 
1486
 
 
1487
  // A section whose starting offset is after the end of its section.
 
1488
  LoadedSection after;
 
1489
  after.Append(10, '2');
 
1490
  after.start()    = segment.start() + 11;
 
1491
  after.address()   = segment.address() + 11;
 
1492
  after.final_size() = after.Size();
 
1493
 
 
1494
  SegmentLoadCommand command;
 
1495
  command
 
1496
    .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
 
1497
    .AppendSectionEntry("after",      "segment", 0, 0x2ee50124, after);
 
1498
 
 
1499
  LoadCommands commands;
 
1500
  commands.Place(&command);
 
1501
 
 
1502
  MachOFile file;
 
1503
  file.Header(&commands).Place(&segment);
 
1504
 
 
1505
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1506
 
 
1507
  Segment actual_segment;
 
1508
  EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
 
1509
 
 
1510
  EXPECT_CALL(reporter, MisplacedSectionData("after", "segment"))
 
1511
    .WillOnce(Return());
 
1512
  EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
 
1513
}
 
1514
 
 
1515
TEST_F(LoadCommand, MisplacedSectionTooBig) {
 
1516
  WithConfiguration config(kLittleEndian, 64);
 
1517
 
 
1518
  // The segment.
 
1519
  LoadedSection segment;
 
1520
  segment.address() = 0x696d83cc;
 
1521
  segment.Append(10, '0');
 
1522
 
 
1523
  // The contents of the following sections don't matter, because
 
1524
  // we're not really going to Place them in segment; we're just going
 
1525
  // to set all their labels by hand to get the (impossible)
 
1526
  // configurations we want.
 
1527
 
 
1528
  // A section that extends beyond the end of its section.
 
1529
  LoadedSection too_big;
 
1530
  too_big.Append(10, '3');
 
1531
  too_big.start()   = segment.start() + 1;
 
1532
  too_big.address() = segment.address() + 1;
 
1533
  too_big.final_size() = too_big.Size();
 
1534
 
 
1535
  SegmentLoadCommand command;
 
1536
  command
 
1537
    .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
 
1538
    .AppendSectionEntry("too big",    "segment", 0, 0x8b53ae5c, too_big);
 
1539
 
 
1540
  LoadCommands commands;
 
1541
  commands.Place(&command);
 
1542
 
 
1543
  MachOFile file;
 
1544
  file.Header(&commands).Place(&segment);
 
1545
 
 
1546
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1547
 
 
1548
  Segment actual_segment;
 
1549
  EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
 
1550
 
 
1551
  EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment"))
 
1552
    .WillOnce(Return());
 
1553
  EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
 
1554
}
 
1555
 
 
1556
 
 
1557
// The segments in a .dSYM bundle's Mach-O file have their file offset
 
1558
// and size set to zero, but the sections don't.  The reader shouldn't
 
1559
// report an error in this case.
 
1560
TEST_F(LoadCommand, ZappedSegment) {
 
1561
  WithConfiguration config(kBigEndian, 32);
 
1562
 
 
1563
  // The segment.
 
1564
  LoadedSection segment;
 
1565
  segment.address() = 0x696d83cc;
 
1566
  segment.start() = 0;
 
1567
  segment.final_size() = 0;
 
1568
 
 
1569
  // The section.
 
1570
  LoadedSection section;
 
1571
  section.address() = segment.address();
 
1572
  section.start() = 0;
 
1573
  section.final_size() = 1000;          // extends beyond its segment
 
1574
  
 
1575
  SegmentLoadCommand command;
 
1576
  command
 
1577
    .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c)
 
1578
    .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section);
 
1579
 
 
1580
  LoadCommands commands;
 
1581
  commands.Place(&command);
 
1582
 
 
1583
  MachOFile file;
 
1584
  file.Header(&commands);
 
1585
 
 
1586
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1587
 
 
1588
  Segment actual_segment;
 
1589
  EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment));
 
1590
 
 
1591
  ByteBuffer zapped_extent(NULL, 0);
 
1592
  EXPECT_CALL(section_handler,
 
1593
              HandleSection(MatchSection(false, "twitching", "zapped",
 
1594
                                         0x696d83cc, 0, 0x93b3bd42,
 
1595
                                         zapped_extent)))
 
1596
    .WillOnce(Return(true));
 
1597
 
 
1598
  EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
 
1599
}
 
1600
 
 
1601
TEST_F(LoadCommand, MapSegmentSections) {
 
1602
  WithConfiguration config(kLittleEndian, 32);
 
1603
 
 
1604
  // Create some sections with some data.
 
1605
  LoadedSection section1, section2, section3, section4;
 
1606
  section1.Append("buddha's hand");
 
1607
  section2.start() = 0;                 // Section 2 is an S_ZEROFILL section.
 
1608
  section2.final_size() = 0;
 
1609
  section3.Append("shasta gold");
 
1610
  section4.Append("satsuma");
 
1611
 
 
1612
  // Create two segments to hold them.
 
1613
  LoadedSection segment1, segment2;
 
1614
  segment1.address() = 0x13e6c8a9;
 
1615
  segment1.Place(&section3).Place(&section1);
 
1616
  segment2.set_word_size(64);
 
1617
  segment2.address() = 0x04d462e2;
 
1618
  segment2.Place(&section4);
 
1619
  section2.address() = segment2.address() + segment2.Size();
 
1620
 
 
1621
  SegmentLoadCommand segment_command1, segment_command2;
 
1622
  segment_command1
 
1623
      .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64)
 
1624
      .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1)
 
1625
      .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3);
 
1626
  segment_command2.set_word_size(64);
 
1627
  segment_command2
 
1628
      .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33)
 
1629
      .AppendSectionEntry("sixteenprecisely", "thorax",
 
1630
                          12, S_ZEROFILL, section2)
 
1631
      .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4);
 
1632
 
 
1633
  LoadCommands commands;
 
1634
  commands.Place(&segment_command1).Place(&segment_command2);
 
1635
 
 
1636
  MachOFile file;
 
1637
  file.Header(&commands).Place(&segment1).Place(&segment2);
 
1638
 
 
1639
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1640
 
 
1641
  Segment segment;
 
1642
  SectionMap section_map;
 
1643
 
 
1644
  EXPECT_FALSE(reader.FindSegment("smoot", &segment));
 
1645
 
 
1646
  ASSERT_TRUE(reader.FindSegment("thorax", &segment));
 
1647
  ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
 
1648
 
 
1649
  EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome")
 
1650
               != section_map.end());
 
1651
  EXPECT_FALSE(section_map.find("mandarin") != section_map.end());
 
1652
  ASSERT_TRUE(section_map.find("cara cara") != section_map.end());
 
1653
  EXPECT_THAT(section_map["cara cara"],
 
1654
              MatchSection(true, "cara cara", "thorax", 0x04d462e2));
 
1655
  ASSERT_TRUE(section_map.find("sixteenprecisely")
 
1656
              != section_map.end());
 
1657
  ByteBuffer sixteenprecisely_contents(NULL, 0);
 
1658
  EXPECT_THAT(section_map["sixteenprecisely"],
 
1659
              MatchSection(true, "sixteenprecisely", "thorax",
 
1660
                           0x04d462e2 + 7, 12, S_ZEROFILL,
 
1661
                           sixteenprecisely_contents));
 
1662
 
 
1663
  ASSERT_TRUE(reader.FindSegment("head", &segment));
 
1664
  ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
 
1665
 
 
1666
  ASSERT_TRUE(section_map.find("mandarin") != section_map.end());
 
1667
  EXPECT_THAT(section_map["mandarin"],
 
1668
              MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11));
 
1669
  ASSERT_TRUE(section_map.find("bergamot") != section_map.end());
 
1670
  EXPECT_THAT(section_map["bergamot"],
 
1671
              MatchSection(false, "bergamot", "head", 0x13e6c8a9));
 
1672
}
 
1673
 
 
1674
TEST_F(LoadCommand, FindSegment) {
 
1675
  WithConfiguration config(kBigEndian, 32);
 
1676
 
 
1677
  LoadedSection segment1, segment2, segment3;
 
1678
  segment1.address() = 0xb8ae5752;
 
1679
  segment1.Append("Some contents!");
 
1680
  segment2.address() = 0xd6b0ce83;
 
1681
  segment2.Append("Different stuff.");
 
1682
  segment3.address() = 0x7374fd2a;
 
1683
  segment3.Append("Further materials.");
 
1684
 
 
1685
  SegmentLoadCommand cmd1, cmd2, cmd3;
 
1686
  cmd1.Header("first",  segment1, 0xfadb6932, 0x175bf529, 0x0de790ad);
 
1687
  cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef);
 
1688
  cmd3.Header("third",  segment3, 0xe172b39e, 0x86012f07, 0x080ac94d);
 
1689
 
 
1690
  LoadCommands commands;
 
1691
  commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
 
1692
 
 
1693
  MachOFile file;
 
1694
  file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3);
 
1695
 
 
1696
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1697
 
 
1698
  Segment actual_segment;
 
1699
 
 
1700
  EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment));
 
1701
 
 
1702
  EXPECT_TRUE(reader.FindSegment("second", &actual_segment));
 
1703
  EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr);
 
1704
}
 
1705
 
 
1706
 
 
1707
// Symtab tests.
 
1708
 
 
1709
// A StringAssembler is a class for generating .stabstr sections to present
 
1710
// as input to the STABS parser.
 
1711
class StringAssembler: public SizedSection {
 
1712
 public:
 
1713
  // Add the string S to this StringAssembler, and return the string's
 
1714
  // offset within this compilation unit's strings.
 
1715
  size_t Add(const string &s) {
 
1716
    size_t offset = Size();
 
1717
    AppendCString(s);
 
1718
    return offset;
 
1719
  }
 
1720
};
 
1721
 
 
1722
// A SymbolAssembler is a class for generating .stab sections to present as
 
1723
// test input for the STABS parser.
 
1724
class SymbolAssembler: public SizedSection {
 
1725
 public:
 
1726
  // Create a SymbolAssembler that uses StringAssembler for its strings.
 
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
 
 
1761
class Symtab: public ReaderFixture, public Test { };
 
1762
 
 
1763
TEST_F(Symtab, Symtab32) {
 
1764
  WithConfiguration config(kLittleEndian, 32);
 
1765
 
 
1766
  StringAssembler strings;
 
1767
  SymbolAssembler symbols(&strings);
 
1768
  symbols
 
1769
      .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu")
 
1770
      .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith");
 
1771
 
 
1772
  SizedSection symtab_command;
 
1773
  symtab_command
 
1774
      .D32(LC_SYMTAB)                    // command
 
1775
      .D32(symtab_command.final_size())  // size
 
1776
      .D32(symbols.start())              // file offset of symbols
 
1777
      .D32(2)                            // symbol count
 
1778
      .D32(strings.start())              // file offset of strings
 
1779
      .D32(strings.final_size());        // strings size
 
1780
 
 
1781
  LoadCommands load_commands;
 
1782
  load_commands.Place(&symtab_command);
 
1783
 
 
1784
  MachOFile file;
 
1785
  file.Header(&load_commands).Place(&symbols).Place(&strings);
 
1786
 
 
1787
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1788
 
 
1789
  ByteBuffer symbols_found, strings_found;
 
1790
  EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
 
1791
      .WillOnce(DoAll(SaveArg<0>(&symbols_found),
 
1792
                      SaveArg<1>(&strings_found),
 
1793
                      Return(true)));
 
1794
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1795
 
 
1796
  EXPECT_EQ(24U, symbols_found.Size());
 
1797
  EXPECT_EQ(14U, strings_found.Size());
 
1798
}
 
1799
 
 
1800
TEST_F(Symtab, Symtab64) {
 
1801
  WithConfiguration config(kBigEndian, 64);
 
1802
 
 
1803
  StringAssembler strings;
 
1804
  SymbolAssembler symbols(&strings);
 
1805
  symbols
 
1806
      .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
 
1807
      .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
 
1808
 
 
1809
  SizedSection symtab_command;
 
1810
  symtab_command
 
1811
      .D32(LC_SYMTAB)                    // command
 
1812
      .D32(symtab_command.final_size())  // size
 
1813
      .D32(symbols.start())              // file offset of symbols
 
1814
      .D32(2)                            // symbol count
 
1815
      .D32(strings.start())              // file offset of strings
 
1816
      .D32(strings.final_size());        // strings size
 
1817
 
 
1818
  LoadCommands load_commands;
 
1819
  load_commands.Place(&symtab_command);
 
1820
 
 
1821
  MachOFile file;
 
1822
  file.Header(&load_commands).Place(&symbols).Place(&strings);
 
1823
 
 
1824
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1825
 
 
1826
  ByteBuffer symbols_found, strings_found;
 
1827
  EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
 
1828
      .WillOnce(DoAll(SaveArg<0>(&symbols_found),
 
1829
                      SaveArg<1>(&strings_found),
 
1830
                      Return(true)));
 
1831
  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
 
1832
 
 
1833
  EXPECT_EQ(32U, symbols_found.Size());
 
1834
  EXPECT_EQ(8U,  strings_found.Size());
 
1835
}
 
1836
 
 
1837
TEST_F(Symtab, SymtabMisplacedSymbols) {
 
1838
  WithConfiguration config(kBigEndian, 32);
 
1839
 
 
1840
  StringAssembler strings;
 
1841
  SymbolAssembler symbols(&strings);
 
1842
  symbols
 
1843
      .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
 
1844
      .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
 
1845
 
 
1846
  SizedSection symtab_command;
 
1847
  symtab_command
 
1848
      .D32(LC_SYMTAB)                    // command
 
1849
      .D32(symtab_command.final_size())  // size
 
1850
      .D32(symbols.start())              // file offset of symbols
 
1851
      .D32(3)                            // symbol count (too many)
 
1852
      .D32(strings.start())              // file offset of strings
 
1853
      .D32(strings.final_size());        // strings size
 
1854
 
 
1855
  LoadCommands load_commands;
 
1856
  load_commands.Place(&symtab_command);
 
1857
 
 
1858
  MachOFile file;
 
1859
  // Put symbols at end, so the excessive length will be noticed.
 
1860
  file.Header(&load_commands).Place(&strings).Place(&symbols);
 
1861
 
 
1862
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1863
 
 
1864
  EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
 
1865
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1866
}
 
1867
 
 
1868
TEST_F(Symtab, SymtabMisplacedStrings) {
 
1869
  WithConfiguration config(kLittleEndian, 32);
 
1870
 
 
1871
  StringAssembler strings;
 
1872
  SymbolAssembler symbols(&strings);
 
1873
  symbols
 
1874
      .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
 
1875
      .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
 
1876
 
 
1877
  SizedSection symtab_command;
 
1878
  symtab_command
 
1879
      .D32(LC_SYMTAB)                    // command
 
1880
      .D32(symtab_command.final_size())  // size
 
1881
      .D32(symbols.start())              // file offset of symbols
 
1882
      .D32(2)                            // symbol count
 
1883
      .D32(strings.start())              // file offset of strings
 
1884
      .D32(strings.final_size() + 1);    // strings size (too long)
 
1885
 
 
1886
  LoadCommands load_commands;
 
1887
  load_commands.Place(&symtab_command);
 
1888
 
 
1889
  MachOFile file;
 
1890
  // Put strings at end, so the excessive length will be noticed.
 
1891
  file.Header(&load_commands).Place(&symbols).Place(&strings);
 
1892
 
 
1893
  ReadFile(&file, true, CPU_TYPE_ANY, 0);
 
1894
 
 
1895
  EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
 
1896
  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
 
1897
}
 
1898