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