1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1898 @@ 1.4 +// Copyright (c) 2010 Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 1.34 + 1.35 +// macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader 1.36 +// and google_breakpad::Mach_O::Reader. 1.37 + 1.38 +#include <map> 1.39 +#include <string> 1.40 +#include <vector> 1.41 + 1.42 +#include "breakpad_googletest_includes.h" 1.43 +#include "common/mac/macho_reader.h" 1.44 +#include "common/test_assembler.h" 1.45 + 1.46 +namespace mach_o = google_breakpad::mach_o; 1.47 +namespace test_assembler = google_breakpad::test_assembler; 1.48 + 1.49 +using mach_o::FatReader; 1.50 +using mach_o::FileFlags; 1.51 +using mach_o::FileType; 1.52 +using mach_o::LoadCommandType; 1.53 +using mach_o::Reader; 1.54 +using mach_o::Section; 1.55 +using mach_o::SectionMap; 1.56 +using mach_o::Segment; 1.57 +using test_assembler::Endianness; 1.58 +using test_assembler::Label; 1.59 +using test_assembler::kBigEndian; 1.60 +using test_assembler::kLittleEndian; 1.61 +using test_assembler::kUnsetEndian; 1.62 +using google_breakpad::ByteBuffer; 1.63 +using std::map; 1.64 +using std::string; 1.65 +using std::vector; 1.66 +using testing::AllOf; 1.67 +using testing::DoAll; 1.68 +using testing::Field; 1.69 +using testing::InSequence; 1.70 +using testing::Matcher; 1.71 +using testing::Return; 1.72 +using testing::SaveArg; 1.73 +using testing::Test; 1.74 +using testing::_; 1.75 + 1.76 + 1.77 +// Mock classes for the reader's various reporters and handlers. 1.78 + 1.79 +class MockFatReaderReporter: public FatReader::Reporter { 1.80 + public: 1.81 + MockFatReaderReporter(const string &filename) 1.82 + : FatReader::Reporter(filename) { } 1.83 + MOCK_METHOD0(BadHeader, void()); 1.84 + MOCK_METHOD0(MisplacedObjectFile, void()); 1.85 + MOCK_METHOD0(TooShort, void()); 1.86 +}; 1.87 + 1.88 +class MockReaderReporter: public Reader::Reporter { 1.89 + public: 1.90 + MockReaderReporter(const string &filename) : Reader::Reporter(filename) { } 1.91 + MOCK_METHOD0(BadHeader, void()); 1.92 + MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type, 1.93 + cpu_subtype_t cpu_subtype, 1.94 + cpu_type_t expected_cpu_type, 1.95 + cpu_subtype_t expected_cpu_subtype)); 1.96 + MOCK_METHOD0(HeaderTruncated, void()); 1.97 + MOCK_METHOD0(LoadCommandRegionTruncated, void()); 1.98 + MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i, 1.99 + LoadCommandType type)); 1.100 + MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type)); 1.101 + MOCK_METHOD1(SectionsMissing, void(const string &name)); 1.102 + MOCK_METHOD1(MisplacedSegmentData, void(const string &name)); 1.103 + MOCK_METHOD2(MisplacedSectionData, void(const string §ion, 1.104 + const string &segment)); 1.105 + MOCK_METHOD0(MisplacedSymbolTable, void()); 1.106 + MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type)); 1.107 +}; 1.108 + 1.109 +class MockLoadCommandHandler: public Reader::LoadCommandHandler { 1.110 + public: 1.111 + MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &)); 1.112 + MOCK_METHOD1(SegmentCommand, bool(const Segment &)); 1.113 + MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &)); 1.114 +}; 1.115 + 1.116 +class MockSectionHandler: public Reader::SectionHandler { 1.117 + public: 1.118 + MOCK_METHOD1(HandleSection, bool(const Section §ion)); 1.119 +}; 1.120 + 1.121 + 1.122 +// Tests for mach_o::FatReader. 1.123 + 1.124 +// Since the effect of these functions is to write to stderr, the 1.125 +// results of these tests must be inspected by hand. 1.126 +TEST(FatReaderReporter, BadHeader) { 1.127 + FatReader::Reporter reporter("filename"); 1.128 + reporter.BadHeader(); 1.129 +} 1.130 + 1.131 +TEST(FatReaderReporter, MisplacedObjectFile) { 1.132 + FatReader::Reporter reporter("filename"); 1.133 + reporter.MisplacedObjectFile(); 1.134 +} 1.135 + 1.136 +TEST(FatReaderReporter, TooShort) { 1.137 + FatReader::Reporter reporter("filename"); 1.138 + reporter.TooShort(); 1.139 +} 1.140 + 1.141 +TEST(MachOReaderReporter, BadHeader) { 1.142 + Reader::Reporter reporter("filename"); 1.143 + reporter.BadHeader(); 1.144 +} 1.145 + 1.146 +TEST(MachOReaderReporter, CPUTypeMismatch) { 1.147 + Reader::Reporter reporter("filename"); 1.148 + reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, 1.149 + CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); 1.150 +} 1.151 + 1.152 +TEST(MachOReaderReporter, HeaderTruncated) { 1.153 + Reader::Reporter reporter("filename"); 1.154 + reporter.HeaderTruncated(); 1.155 +} 1.156 + 1.157 +TEST(MachOReaderReporter, LoadCommandRegionTruncated) { 1.158 + Reader::Reporter reporter("filename"); 1.159 + reporter.LoadCommandRegionTruncated(); 1.160 +} 1.161 + 1.162 +TEST(MachOReaderReporter, LoadCommandsOverrun) { 1.163 + Reader::Reporter reporter("filename"); 1.164 + reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB); 1.165 + reporter.LoadCommandsOverrun(10, 9, 0); 1.166 +} 1.167 + 1.168 +TEST(MachOReaderReporter, LoadCommandTooShort) { 1.169 + Reader::Reporter reporter("filename"); 1.170 + reporter.LoadCommandTooShort(11, LC_SYMTAB); 1.171 +} 1.172 + 1.173 +TEST(MachOReaderReporter, SectionsMissing) { 1.174 + Reader::Reporter reporter("filename"); 1.175 + reporter.SectionsMissing("segment name"); 1.176 +} 1.177 + 1.178 +TEST(MachOReaderReporter, MisplacedSegmentData) { 1.179 + Reader::Reporter reporter("filename"); 1.180 + reporter.MisplacedSegmentData("segment name"); 1.181 +} 1.182 + 1.183 +TEST(MachOReaderReporter, MisplacedSectionData) { 1.184 + Reader::Reporter reporter("filename"); 1.185 + reporter.MisplacedSectionData("section name", "segment name"); 1.186 +} 1.187 + 1.188 +TEST(MachOReaderReporter, MisplacedSymbolTable) { 1.189 + Reader::Reporter reporter("filename"); 1.190 + reporter.MisplacedSymbolTable(); 1.191 +} 1.192 + 1.193 +TEST(MachOReaderReporter, UnsupportedCPUType) { 1.194 + Reader::Reporter reporter("filename"); 1.195 + reporter.UnsupportedCPUType(CPU_TYPE_HPPA); 1.196 +} 1.197 + 1.198 +struct FatReaderFixture { 1.199 + FatReaderFixture() 1.200 + : fat(kBigEndian), 1.201 + reporter("reporter filename"), 1.202 + reader(&reporter), object_files(), object_files_size() { 1.203 + EXPECT_CALL(reporter, BadHeader()).Times(0); 1.204 + EXPECT_CALL(reporter, TooShort()).Times(0); 1.205 + 1.206 + // here, start, and Mark are file offsets in 'fat'. 1.207 + fat.start() = 0; 1.208 + } 1.209 + // Append a 'fat_arch' entry to 'fat', with the given field values. 1.210 + void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype, 1.211 + Label offset, Label size, uint32_t align) { 1.212 + fat 1.213 + .B32(type) 1.214 + .B32(subtype) 1.215 + .B32(offset) 1.216 + .B32(size) 1.217 + .B32(align); 1.218 + } 1.219 + // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and 1.220 + // subtype have unrealistic values. 1.221 + void AppendDummyArchEntries(int n) { 1.222 + for (int i = 0; i < n; i++) 1.223 + AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1); 1.224 + } 1.225 + void ReadFat(bool expect_parse_success = true) { 1.226 + ASSERT_TRUE(fat.GetContents(&contents)); 1.227 + fat_bytes = reinterpret_cast<const uint8_t *>(contents.data()); 1.228 + if (expect_parse_success) { 1.229 + EXPECT_TRUE(reader.Read(fat_bytes, contents.size())); 1.230 + object_files = reader.object_files(&object_files_size); 1.231 + } 1.232 + else 1.233 + EXPECT_FALSE(reader.Read(fat_bytes, contents.size())); 1.234 + } 1.235 + test_assembler::Section fat; 1.236 + MockFatReaderReporter reporter; 1.237 + FatReader reader; 1.238 + string contents; 1.239 + const uint8_t *fat_bytes; 1.240 + const struct fat_arch *object_files; 1.241 + size_t object_files_size; 1.242 +}; 1.243 + 1.244 +class FatReaderTest: public FatReaderFixture, public Test { }; 1.245 + 1.246 +TEST_F(FatReaderTest, BadMagic) { 1.247 + EXPECT_CALL(reporter, BadHeader()).Times(1); 1.248 + fat 1.249 + .B32(0xcafed00d) // magic number (incorrect) 1.250 + .B32(10); // number of architectures 1.251 + AppendDummyArchEntries(10); 1.252 + ReadFat(false); 1.253 +} 1.254 + 1.255 +TEST_F(FatReaderTest, HeaderTooShort) { 1.256 + EXPECT_CALL(reporter, TooShort()).Times(1); 1.257 + fat 1.258 + .B32(0xcafebabe); // magic number 1.259 + ReadFat(false); 1.260 +} 1.261 + 1.262 +TEST_F(FatReaderTest, ObjectListTooShort) { 1.263 + EXPECT_CALL(reporter, TooShort()).Times(1); 1.264 + fat 1.265 + .B32(0xcafebabe) // magic number 1.266 + .B32(10); // number of architectures 1.267 + AppendDummyArchEntries(9); // nine dummy architecture entries... 1.268 + fat // and a tenth, missing a byte at the end 1.269 + .B32(0x3d46c8fc) // cpu type 1.270 + .B32(0x8a7bfb01) // cpu subtype 1.271 + .B32(0) // offset 1.272 + .B32(0) // size 1.273 + .Append(3, '*'); // one byte short of a four-byte alignment 1.274 + ReadFat(false); 1.275 +} 1.276 + 1.277 +TEST_F(FatReaderTest, DataTooShort) { 1.278 + EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1); 1.279 + Label arch_data; 1.280 + fat 1.281 + .B32(0xcafebabe) // magic number 1.282 + .B32(1); // number of architectures 1.283 + AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0); 1.284 + fat 1.285 + .Mark(&arch_data) // file data begins here 1.286 + .Append(30, '*'); // only 30 bytes, not 40 as header claims 1.287 + ReadFat(false); 1.288 +} 1.289 + 1.290 +TEST_F(FatReaderTest, NoObjectFiles) { 1.291 + fat 1.292 + .B32(0xcafebabe) // magic number 1.293 + .B32(0); // number of architectures 1.294 + ReadFat(); 1.295 + EXPECT_EQ(0U, object_files_size); 1.296 +} 1.297 + 1.298 +TEST_F(FatReaderTest, OneObjectFile) { 1.299 + Label obj1_offset; 1.300 + fat 1.301 + .B32(0xcafebabe) // magic number 1.302 + .B32(1); // number of architectures 1.303 + // First object file list entry 1.304 + AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2); 1.305 + // First object file data 1.306 + fat 1.307 + .Mark(&obj1_offset) 1.308 + .Append(0x42, '*'); // dummy contents 1.309 + ReadFat(); 1.310 + ASSERT_EQ(1U, object_files_size); 1.311 + EXPECT_EQ(0x5e3a6e91, object_files[0].cputype); 1.312 + EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype); 1.313 + EXPECT_EQ(obj1_offset.Value(), object_files[0].offset); 1.314 + EXPECT_EQ(0x42U, object_files[0].size); 1.315 + EXPECT_EQ(0x355b15b2U, object_files[0].align); 1.316 +} 1.317 + 1.318 +TEST_F(FatReaderTest, ThreeObjectFiles) { 1.319 + Label obj1, obj2, obj3; 1.320 + fat 1.321 + .B32(0xcafebabe) // magic number 1.322 + .B32(3); // number of architectures 1.323 + // Three object file list entries. 1.324 + AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8); 1.325 + AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd); 1.326 + AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7); 1.327 + fat 1.328 + // First object file data 1.329 + .Mark(&obj1) 1.330 + .Append(0xfb4, '*') // dummy contents 1.331 + // Second object file data 1.332 + .Mark(&obj2) 1.333 + .Append(0xc31, '%') // dummy contents 1.334 + // Third object file data 1.335 + .Mark(&obj3) 1.336 + .Append(0x4b3, '^'); // dummy contents 1.337 + 1.338 + ReadFat(); 1.339 + 1.340 + ASSERT_EQ(3U, object_files_size); 1.341 + 1.342 + // First object file. 1.343 + EXPECT_EQ(0x0cb92c30, object_files[0].cputype); 1.344 + EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype); 1.345 + EXPECT_EQ(obj1.Value(), object_files[0].offset); 1.346 + EXPECT_EQ(0xfb4U, object_files[0].size); 1.347 + EXPECT_EQ(0x2615dbe8U, object_files[0].align); 1.348 + 1.349 + // Second object file. 1.350 + EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype); 1.351 + EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype); 1.352 + EXPECT_EQ(obj2.Value(), object_files[1].offset); 1.353 + EXPECT_EQ(0xc31U, object_files[1].size); 1.354 + EXPECT_EQ(0x83af6ffdU, object_files[1].align); 1.355 + 1.356 + // Third object file. 1.357 + EXPECT_EQ(0x3717276d, object_files[2].cputype); 1.358 + EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype); 1.359 + EXPECT_EQ(obj3.Value(), object_files[2].offset); 1.360 + EXPECT_EQ(0x4b3U, object_files[2].size); 1.361 + EXPECT_EQ(0x035267d7U, object_files[2].align); 1.362 +} 1.363 + 1.364 +TEST_F(FatReaderTest, BigEndianMachO32) { 1.365 + fat.set_endianness(kBigEndian); 1.366 + fat 1.367 + .D32(0xfeedface) // Mach-O file magic number 1.368 + .D32(0x1a9d0518) // cpu type 1.369 + .D32(0x1b779357) // cpu subtype 1.370 + .D32(0x009df67e) // file type 1.371 + .D32(0) // no load commands 1.372 + .D32(0) // the load commands occupy no bytes 1.373 + .D32(0x21987a99); // flags 1.374 + 1.375 + ReadFat(); 1.376 + 1.377 + // FatReader should treat a Mach-O file as if it were a fat binary file 1.378 + // containing one object file --- the whole thing. 1.379 + ASSERT_EQ(1U, object_files_size); 1.380 + EXPECT_EQ(0x1a9d0518, object_files[0].cputype); 1.381 + EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); 1.382 + EXPECT_EQ(0U, object_files[0].offset); 1.383 + EXPECT_EQ(contents.size(), object_files[0].size); 1.384 +} 1.385 + 1.386 +TEST_F(FatReaderTest, BigEndianMachO64) { 1.387 + fat.set_endianness(kBigEndian); 1.388 + fat 1.389 + .D32(0xfeedfacf) // Mach-O 64-bit file magic number 1.390 + .D32(0x5aff8487) // cpu type 1.391 + .D32(0x4c6a57f7) // cpu subtype 1.392 + .D32(0x4392d2c8) // file type 1.393 + .D32(0) // no load commands 1.394 + .D32(0) // the load commands occupy no bytes 1.395 + .D32(0x1b033eea); // flags 1.396 + 1.397 + ReadFat(); 1.398 + 1.399 + // FatReader should treat a Mach-O file as if it were a fat binary file 1.400 + // containing one object file --- the whole thing. 1.401 + ASSERT_EQ(1U, object_files_size); 1.402 + EXPECT_EQ(0x5aff8487, object_files[0].cputype); 1.403 + EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); 1.404 + EXPECT_EQ(0U, object_files[0].offset); 1.405 + EXPECT_EQ(contents.size(), object_files[0].size); 1.406 +} 1.407 + 1.408 +TEST_F(FatReaderTest, LittleEndianMachO32) { 1.409 + fat.set_endianness(kLittleEndian); 1.410 + fat 1.411 + .D32(0xfeedface) // Mach-O file magic number 1.412 + .D32(0x1a9d0518) // cpu type 1.413 + .D32(0x1b779357) // cpu subtype 1.414 + .D32(0x009df67e) // file type 1.415 + .D32(0) // no load commands 1.416 + .D32(0) // the load commands occupy no bytes 1.417 + .D32(0x21987a99); // flags 1.418 + 1.419 + ReadFat(); 1.420 + 1.421 + // FatReader should treat a Mach-O file as if it were a fat binary file 1.422 + // containing one object file --- the whole thing. 1.423 + ASSERT_EQ(1U, object_files_size); 1.424 + EXPECT_EQ(0x1a9d0518, object_files[0].cputype); 1.425 + EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); 1.426 + EXPECT_EQ(0U, object_files[0].offset); 1.427 + EXPECT_EQ(contents.size(), object_files[0].size); 1.428 +} 1.429 + 1.430 +TEST_F(FatReaderTest, LittleEndianMachO64) { 1.431 + fat.set_endianness(kLittleEndian); 1.432 + fat 1.433 + .D32(0xfeedfacf) // Mach-O 64-bit file magic number 1.434 + .D32(0x5aff8487) // cpu type 1.435 + .D32(0x4c6a57f7) // cpu subtype 1.436 + .D32(0x4392d2c8) // file type 1.437 + .D32(0) // no load commands 1.438 + .D32(0) // the load commands occupy no bytes 1.439 + .D32(0x1b033eea); // flags 1.440 + 1.441 + ReadFat(); 1.442 + 1.443 + // FatReader should treat a Mach-O file as if it were a fat binary file 1.444 + // containing one object file --- the whole thing. 1.445 + ASSERT_EQ(1U, object_files_size); 1.446 + EXPECT_EQ(0x5aff8487, object_files[0].cputype); 1.447 + EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); 1.448 + EXPECT_EQ(0U, object_files[0].offset); 1.449 + EXPECT_EQ(contents.size(), object_files[0].size); 1.450 +} 1.451 + 1.452 +TEST_F(FatReaderTest, IncompleteMach) { 1.453 + fat.set_endianness(kLittleEndian); 1.454 + fat 1.455 + .D32(0xfeedfacf) // Mach-O 64-bit file magic number 1.456 + .D32(0x5aff8487); // cpu type 1.457 + // Truncated! 1.458 + 1.459 + EXPECT_CALL(reporter, TooShort()).WillOnce(Return()); 1.460 + 1.461 + ReadFat(false); 1.462 +} 1.463 + 1.464 + 1.465 +// General mach_o::Reader tests. 1.466 + 1.467 +// Dynamically scoped configuration data. 1.468 +class WithConfiguration { 1.469 + public: 1.470 + // Establish the given parameters as the default for SizedSections 1.471 + // created within the dynamic scope of this instance. 1.472 + WithConfiguration(Endianness endianness, size_t word_size) 1.473 + : endianness_(endianness), word_size_(word_size), saved_(current_) { 1.474 + current_ = this; 1.475 + } 1.476 + ~WithConfiguration() { current_ = saved_; } 1.477 + static Endianness endianness() { 1.478 + assert(current_); 1.479 + return current_->endianness_; 1.480 + } 1.481 + static size_t word_size() { 1.482 + assert(current_); 1.483 + return current_->word_size_; 1.484 + } 1.485 + 1.486 + private: 1.487 + // The innermost WithConfiguration in whose dynamic scope we are 1.488 + // currently executing. 1.489 + static WithConfiguration *current_; 1.490 + 1.491 + // The innermost WithConfiguration whose dynamic scope encloses this 1.492 + // WithConfiguration. 1.493 + Endianness endianness_; 1.494 + size_t word_size_; 1.495 + WithConfiguration *saved_; 1.496 +}; 1.497 + 1.498 +WithConfiguration *WithConfiguration::current_ = NULL; 1.499 + 1.500 +// A test_assembler::Section with a size that we can cite. The start(), 1.501 +// Here() and Mark() member functions of a SizedSection always represent 1.502 +// offsets within the overall file. 1.503 +class SizedSection: public test_assembler::Section { 1.504 + public: 1.505 + // Construct a section of the given endianness and word size. 1.506 + explicit SizedSection(Endianness endianness, size_t word_size) 1.507 + : test_assembler::Section(endianness), word_size_(word_size) { 1.508 + assert(word_size_ == 32 || word_size_ == 64); 1.509 + } 1.510 + SizedSection() 1.511 + : test_assembler::Section(WithConfiguration::endianness()), 1.512 + word_size_(WithConfiguration::word_size()) { 1.513 + assert(word_size_ == 32 || word_size_ == 64); 1.514 + } 1.515 + 1.516 + // Access/set this section's word size. 1.517 + size_t word_size() const { return word_size_; } 1.518 + void set_word_size(size_t word_size) { 1.519 + assert(word_size_ == 32 || word_size_ == 64); 1.520 + word_size_ = word_size; 1.521 + } 1.522 + 1.523 + // Return a label representing the size this section will have when it 1.524 + // is Placed in some containing section. 1.525 + Label final_size() const { return final_size_; } 1.526 + 1.527 + // Append SECTION to the end of this section, and call its Finish member. 1.528 + // Return a reference to this section. 1.529 + SizedSection &Place(SizedSection *section) { 1.530 + assert(section->endianness() == endianness()); 1.531 + section->Finish(); 1.532 + section->start() = Here(); 1.533 + test_assembler::Section::Append(*section); 1.534 + return *this; 1.535 + } 1.536 + 1.537 + protected: 1.538 + // Mark this section's contents as complete. For plain SizedSections, we 1.539 + // set SECTION's start to its position in this section, and its final_size 1.540 + // label to its current size. Derived classes can extend this as needed 1.541 + // for their additional semantics. 1.542 + virtual void Finish() { 1.543 + final_size_ = Size(); 1.544 + } 1.545 + 1.546 + // The word size for this data: either 32 or 64. 1.547 + size_t word_size_; 1.548 + 1.549 + private: 1.550 + // This section's final size, set when we are placed in some other 1.551 + // SizedSection. 1.552 + Label final_size_; 1.553 +}; 1.554 + 1.555 +// A SizedSection that is loaded into memory at a particular address. 1.556 +class LoadedSection: public SizedSection { 1.557 + public: 1.558 + explicit LoadedSection(Label address = Label()) : address_(address) { } 1.559 + 1.560 + // Return a label representing this section's address. 1.561 + Label address() const { return address_; } 1.562 + 1.563 + // Placing a loaded section within a loaded section sets the relationship 1.564 + // between their addresses. 1.565 + LoadedSection &Place(LoadedSection *section) { 1.566 + section->address() = address() + Size(); 1.567 + SizedSection::Place(section); 1.568 + return *this; 1.569 + } 1.570 + 1.571 + protected: 1.572 + // The address at which this section's contents will be loaded. 1.573 + Label address_; 1.574 +}; 1.575 + 1.576 +// A SizedSection representing a segment load command. 1.577 +class SegmentLoadCommand: public SizedSection { 1.578 + public: 1.579 + SegmentLoadCommand() : section_count_(0) { } 1.580 + 1.581 + // Append a segment load command header with the given characteristics. 1.582 + // The load command will refer to CONTENTS, which must be Placed in the 1.583 + // file separately, at the desired position. Return a reference to this 1.584 + // section. 1.585 + SegmentLoadCommand &Header(const string &name, const LoadedSection &contents, 1.586 + uint32_t maxprot, uint32_t initprot, 1.587 + uint32_t flags) { 1.588 + assert(contents.word_size() == word_size()); 1.589 + D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64); 1.590 + D32(final_size()); 1.591 + AppendCString(name, 16); 1.592 + Append(endianness(), word_size() / 8, contents.address()); 1.593 + Append(endianness(), word_size() / 8, vmsize_); 1.594 + Append(endianness(), word_size() / 8, contents.start()); 1.595 + Append(endianness(), word_size() / 8, contents.final_size()); 1.596 + D32(maxprot); 1.597 + D32(initprot); 1.598 + D32(final_section_count_); 1.599 + D32(flags); 1.600 + 1.601 + content_final_size_ = contents.final_size(); 1.602 + 1.603 + return *this; 1.604 + } 1.605 + 1.606 + // Return a label representing the size of this segment when loaded into 1.607 + // memory. If this label is still undefined by the time we place this 1.608 + // segment, it defaults to the final size of the segment's in-file 1.609 + // contents. Return a reference to this load command. 1.610 + Label &vmsize() { return vmsize_; } 1.611 + 1.612 + // Add a section entry with the given characteristics to this segment 1.613 + // load command. Return a reference to this. The section entry will refer 1.614 + // to CONTENTS, which must be Placed in the segment's contents 1.615 + // separately, at the desired position. 1.616 + SegmentLoadCommand &AppendSectionEntry(const string §ion_name, 1.617 + const string &segment_name, 1.618 + uint32_t alignment, uint32_t flags, 1.619 + const LoadedSection &contents) { 1.620 + AppendCString(section_name, 16); 1.621 + AppendCString(segment_name, 16); 1.622 + Append(endianness(), word_size() / 8, contents.address()); 1.623 + Append(endianness(), word_size() / 8, contents.final_size()); 1.624 + D32(contents.start()); 1.625 + D32(alignment); 1.626 + D32(0); // relocations start 1.627 + D32(0); // relocations size 1.628 + D32(flags); 1.629 + D32(0x93656b95); // reserved1 1.630 + D32(0xc35a2473); // reserved2 1.631 + if (word_size() == 64) 1.632 + D32(0x70284b95); // reserved3 1.633 + 1.634 + section_count_++; 1.635 + 1.636 + return *this; 1.637 + } 1.638 + 1.639 + protected: 1.640 + void Finish() { 1.641 + final_section_count_ = section_count_; 1.642 + if (!vmsize_.IsKnownConstant()) 1.643 + vmsize_ = content_final_size_; 1.644 + SizedSection::Finish(); 1.645 + } 1.646 + 1.647 + private: 1.648 + // The number of sections that have been added to this segment so far. 1.649 + size_t section_count_; 1.650 + 1.651 + // A label representing the final number of sections this segment will hold. 1.652 + Label final_section_count_; 1.653 + 1.654 + // The size of the contents for this segment present in the file. 1.655 + Label content_final_size_; 1.656 + 1.657 + // A label representing the size of this segment when loaded; this can be 1.658 + // larger than the size of its file contents, the difference being 1.659 + // zero-filled. If not set explicitly by calling set_vmsize, this is set 1.660 + // equal to the size of the contents. 1.661 + Label vmsize_; 1.662 +}; 1.663 + 1.664 +// A SizedSection holding a list of Mach-O load commands. 1.665 +class LoadCommands: public SizedSection { 1.666 + public: 1.667 + LoadCommands() : command_count_(0) { } 1.668 + 1.669 + // Return a label representing the final load command count. 1.670 + Label final_command_count() const { return final_command_count_; } 1.671 + 1.672 + // Increment the command count; return a reference to this section. 1.673 + LoadCommands &CountCommand() { 1.674 + command_count_++; 1.675 + return *this; 1.676 + } 1.677 + 1.678 + // Place COMMAND, containing a load command, at the end of this section. 1.679 + // Return a reference to this section. 1.680 + LoadCommands &Place(SizedSection *section) { 1.681 + SizedSection::Place(section); 1.682 + CountCommand(); 1.683 + return *this; 1.684 + } 1.685 + 1.686 + protected: 1.687 + // Mark this load command list as complete. 1.688 + void Finish() { 1.689 + SizedSection::Finish(); 1.690 + final_command_count_ = command_count_; 1.691 + } 1.692 + 1.693 + private: 1.694 + // The number of load commands we have added to this file so far. 1.695 + size_t command_count_; 1.696 + 1.697 + // A label representing the final command count. 1.698 + Label final_command_count_; 1.699 +}; 1.700 + 1.701 +// A SizedSection holding the contents of a Mach-O file. Within a 1.702 +// MachOFile, the start, Here, and Mark members refer to file offsets. 1.703 +class MachOFile: public SizedSection { 1.704 + public: 1.705 + MachOFile() { 1.706 + start() = 0; 1.707 + } 1.708 + 1.709 + // Create a Mach-O file header using the given characteristics and load 1.710 + // command list. This Places COMMANDS immediately after the header. 1.711 + // Return a reference to this section. 1.712 + MachOFile &Header(LoadCommands *commands, 1.713 + cpu_type_t cpu_type = CPU_TYPE_X86, 1.714 + cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL, 1.715 + FileType file_type = MH_EXECUTE, 1.716 + uint32_t file_flags = (MH_TWOLEVEL | 1.717 + MH_DYLDLINK | 1.718 + MH_NOUNDEFS)) { 1.719 + D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf); // magic number 1.720 + D32(cpu_type); // cpu type 1.721 + D32(cpu_subtype); // cpu subtype 1.722 + D32(file_type); // file type 1.723 + D32(commands->final_command_count()); // number of load commands 1.724 + D32(commands->final_size()); // their size in bytes 1.725 + D32(file_flags); // flags 1.726 + if (word_size() == 64) 1.727 + D32(0x55638b90); // reserved 1.728 + Place(commands); 1.729 + return *this; 1.730 + } 1.731 +}; 1.732 + 1.733 + 1.734 +struct ReaderFixture { 1.735 + ReaderFixture() 1.736 + : reporter("reporter filename"), 1.737 + reader(&reporter) { 1.738 + EXPECT_CALL(reporter, BadHeader()).Times(0); 1.739 + EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0); 1.740 + EXPECT_CALL(reporter, HeaderTruncated()).Times(0); 1.741 + EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0); 1.742 + EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0); 1.743 + EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0); 1.744 + EXPECT_CALL(reporter, SectionsMissing(_)).Times(0); 1.745 + EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0); 1.746 + EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0); 1.747 + EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0); 1.748 + EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0); 1.749 + 1.750 + EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0); 1.751 + EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0); 1.752 + } 1.753 + 1.754 + void ReadFile(MachOFile *file, 1.755 + bool expect_parse_success, 1.756 + cpu_type_t expected_cpu_type, 1.757 + cpu_subtype_t expected_cpu_subtype) { 1.758 + ASSERT_TRUE(file->GetContents(&file_contents)); 1.759 + file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data()); 1.760 + if (expect_parse_success) { 1.761 + EXPECT_TRUE(reader.Read(file_bytes, 1.762 + file_contents.size(), 1.763 + expected_cpu_type, 1.764 + expected_cpu_subtype)); 1.765 + } else { 1.766 + EXPECT_FALSE(reader.Read(file_bytes, 1.767 + file_contents.size(), 1.768 + expected_cpu_type, 1.769 + expected_cpu_subtype)); 1.770 + } 1.771 + } 1.772 + 1.773 + string file_contents; 1.774 + const uint8_t *file_bytes; 1.775 + MockReaderReporter reporter; 1.776 + Reader reader; 1.777 + MockLoadCommandHandler load_command_handler; 1.778 + MockSectionHandler section_handler; 1.779 +}; 1.780 + 1.781 +class ReaderTest: public ReaderFixture, public Test { }; 1.782 + 1.783 +TEST_F(ReaderTest, BadMagic) { 1.784 + WithConfiguration config(kLittleEndian, 32); 1.785 + const cpu_type_t kCPUType = 0x46b760df; 1.786 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.787 + MachOFile file; 1.788 + file 1.789 + .D32(0x67bdebe1) // Not a proper magic number. 1.790 + .D32(kCPUType) // cpu type 1.791 + .D32(kCPUSubType) // cpu subtype 1.792 + .D32(0x149fc717) // file type 1.793 + .D32(0) // no load commands 1.794 + .D32(0) // they occupy no bytes 1.795 + .D32(0x80e71d64) // flags 1.796 + .D32(0); // reserved 1.797 + EXPECT_CALL(reporter, BadHeader()).WillOnce(Return()); 1.798 + ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); 1.799 +} 1.800 + 1.801 +TEST_F(ReaderTest, MismatchedMagic) { 1.802 + WithConfiguration config(kLittleEndian, 32); 1.803 + const cpu_type_t kCPUType = CPU_TYPE_I386; 1.804 + const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL; 1.805 + MachOFile file; 1.806 + file 1.807 + .D32(MH_CIGAM) // Right magic, but winds up wrong 1.808 + // due to bitswapping 1.809 + .D32(kCPUType) // cpu type 1.810 + .D32(kCPUSubType) // cpu subtype 1.811 + .D32(0x149fc717) // file type 1.812 + .D32(0) // no load commands 1.813 + .D32(0) // they occupy no bytes 1.814 + .D32(0x80e71d64) // flags 1.815 + .D32(0); // reserved 1.816 + EXPECT_CALL(reporter, BadHeader()).WillOnce(Return()); 1.817 + ReadFile(&file, false, kCPUType, kCPUSubType); 1.818 +} 1.819 + 1.820 +TEST_F(ReaderTest, ShortMagic) { 1.821 + WithConfiguration config(kBigEndian, 32); 1.822 + MachOFile file; 1.823 + file 1.824 + .D16(0xfeed); // magic number 1.825 + // truncated! 1.826 + EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return()); 1.827 + ReadFile(&file, false, CPU_TYPE_ANY, 0); 1.828 +} 1.829 + 1.830 +TEST_F(ReaderTest, ShortHeader) { 1.831 + WithConfiguration config(kBigEndian, 32); 1.832 + const cpu_type_t kCPUType = CPU_TYPE_ANY; 1.833 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.834 + MachOFile file; 1.835 + file 1.836 + .D32(0xfeedface) // magic number 1.837 + .D32(kCPUType) // cpu type 1.838 + .D32(kCPUSubType) // cpu subtype 1.839 + .D32(0x149fc717) // file type 1.840 + .D32(0) // no load commands 1.841 + .D32(0); // they occupy no bytes 1.842 + EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return()); 1.843 + ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); 1.844 +} 1.845 + 1.846 +TEST_F(ReaderTest, MismatchedCPU) { 1.847 + WithConfiguration config(kBigEndian, 32); 1.848 + const cpu_type_t kCPUType = CPU_TYPE_I386; 1.849 + const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL; 1.850 + MachOFile file; 1.851 + file 1.852 + .D32(MH_MAGIC) // Right magic for PPC (once bitswapped) 1.853 + .D32(kCPUType) // cpu type 1.854 + .D32(kCPUSubType) // cpu subtype 1.855 + .D32(0x149fc717) // file type 1.856 + .D32(0) // no load commands 1.857 + .D32(0) // they occupy no bytes 1.858 + .D32(0x80e71d64) // flags 1.859 + .D32(0); // reserved 1.860 + EXPECT_CALL(reporter, 1.861 + CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, 1.862 + CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL)) 1.863 + .WillOnce(Return()); 1.864 + ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); 1.865 +} 1.866 + 1.867 +TEST_F(ReaderTest, LittleEndian32Bit) { 1.868 + WithConfiguration config(kLittleEndian, 32); 1.869 + const cpu_type_t kCPUType = 0x46b760df; 1.870 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.871 + MachOFile file; 1.872 + file 1.873 + .D32(0xfeedface) // magic number 1.874 + .D32(kCPUType) // cpu type 1.875 + .D32(kCPUSubType) // cpu subtype 1.876 + .D32(0x149fc717) // file type 1.877 + .D32(0) // no load commands 1.878 + .D32(0) // they occupy no bytes 1.879 + .D32(0x80e71d64) // flags 1.880 + .D32(0); // reserved 1.881 + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); 1.882 + EXPECT_FALSE(reader.bits_64()); 1.883 + EXPECT_FALSE(reader.big_endian()); 1.884 + EXPECT_EQ(kCPUType, reader.cpu_type()); 1.885 + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); 1.886 + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); 1.887 + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); 1.888 +} 1.889 + 1.890 +TEST_F(ReaderTest, LittleEndian64Bit) { 1.891 + WithConfiguration config(kLittleEndian, 64); 1.892 + const cpu_type_t kCPUType = 0x46b760df; 1.893 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.894 + MachOFile file; 1.895 + file 1.896 + .D32(0xfeedfacf) // magic number 1.897 + .D32(kCPUType) // cpu type 1.898 + .D32(kCPUSubType) // cpu subtype 1.899 + .D32(0x149fc717) // file type 1.900 + .D32(0) // no load commands 1.901 + .D32(0) // they occupy no bytes 1.902 + .D32(0x80e71d64) // flags 1.903 + .D32(0); // reserved 1.904 + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); 1.905 + EXPECT_TRUE(reader.bits_64()); 1.906 + EXPECT_FALSE(reader.big_endian()); 1.907 + EXPECT_EQ(kCPUType, reader.cpu_type()); 1.908 + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); 1.909 + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); 1.910 + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); 1.911 +} 1.912 + 1.913 +TEST_F(ReaderTest, BigEndian32Bit) { 1.914 + WithConfiguration config(kBigEndian, 32); 1.915 + const cpu_type_t kCPUType = 0x46b760df; 1.916 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.917 + MachOFile file; 1.918 + file 1.919 + .D32(0xfeedface) // magic number 1.920 + .D32(kCPUType) // cpu type 1.921 + .D32(kCPUSubType) // cpu subtype 1.922 + .D32(0x149fc717) // file type 1.923 + .D32(0) // no load commands 1.924 + .D32(0) // they occupy no bytes 1.925 + .D32(0x80e71d64) // flags 1.926 + .D32(0); // reserved 1.927 + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); 1.928 + EXPECT_FALSE(reader.bits_64()); 1.929 + EXPECT_TRUE(reader.big_endian()); 1.930 + EXPECT_EQ(kCPUType, reader.cpu_type()); 1.931 + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); 1.932 + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); 1.933 + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); 1.934 +} 1.935 + 1.936 +TEST_F(ReaderTest, BigEndian64Bit) { 1.937 + WithConfiguration config(kBigEndian, 64); 1.938 + const cpu_type_t kCPUType = 0x46b760df; 1.939 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.940 + MachOFile file; 1.941 + file 1.942 + .D32(0xfeedfacf) // magic number 1.943 + .D32(kCPUType) // cpu type 1.944 + .D32(kCPUSubType) // cpu subtype 1.945 + .D32(0x149fc717) // file type 1.946 + .D32(0) // no load commands 1.947 + .D32(0) // they occupy no bytes 1.948 + .D32(0x80e71d64) // flags 1.949 + .D32(0); // reserved 1.950 + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); 1.951 + EXPECT_TRUE(reader.bits_64()); 1.952 + EXPECT_TRUE(reader.big_endian()); 1.953 + EXPECT_EQ(kCPUType, reader.cpu_type()); 1.954 + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); 1.955 + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); 1.956 + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); 1.957 +} 1.958 + 1.959 + 1.960 +// Load command tests. 1.961 + 1.962 +class LoadCommand: public ReaderFixture, public Test { }; 1.963 + 1.964 +TEST_F(LoadCommand, RegionTruncated) { 1.965 + WithConfiguration config(kBigEndian, 64); 1.966 + const cpu_type_t kCPUType = 0x46b760df; 1.967 + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; 1.968 + MachOFile file; 1.969 + file 1.970 + .D32(0xfeedfacf) // magic number 1.971 + .D32(kCPUType) // cpu type 1.972 + .D32(kCPUSubType) // cpu subtype 1.973 + .D32(0x149fc717) // file type 1.974 + .D32(1) // one load command 1.975 + .D32(40) // occupying 40 bytes 1.976 + .D32(0x80e71d64) // flags 1.977 + .D32(0) // reserved 1.978 + .Append(20, 0); // load command region, not as long as 1.979 + // Mach-O header promised 1.980 + 1.981 + EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return()); 1.982 + 1.983 + ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); 1.984 +} 1.985 + 1.986 +TEST_F(LoadCommand, None) { 1.987 + WithConfiguration config(kLittleEndian, 32); 1.988 + LoadCommands load_commands; 1.989 + MachOFile file; 1.990 + file.Header(&load_commands); 1.991 + 1.992 + ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL); 1.993 + 1.994 + EXPECT_FALSE(reader.bits_64()); 1.995 + EXPECT_FALSE(reader.big_endian()); 1.996 + EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type()); 1.997 + EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype()); 1.998 + EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type()); 1.999 + EXPECT_EQ(FileFlags(MH_TWOLEVEL | 1.1000 + MH_DYLDLINK | 1.1001 + MH_NOUNDEFS), 1.1002 + FileFlags(reader.flags())); 1.1003 + 1.1004 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1005 +} 1.1006 + 1.1007 +TEST_F(LoadCommand, Unknown) { 1.1008 + WithConfiguration config(kBigEndian, 32); 1.1009 + LoadCommands load_commands; 1.1010 + load_commands 1.1011 + .CountCommand() 1.1012 + .D32(0x33293d4a) // unknown load command 1.1013 + .D32(40) // total size in bytes 1.1014 + .Append(32, '*'); // dummy data 1.1015 + MachOFile file; 1.1016 + file.Header(&load_commands); 1.1017 + 1.1018 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1019 + 1.1020 + EXPECT_FALSE(reader.bits_64()); 1.1021 + EXPECT_TRUE(reader.big_endian()); 1.1022 + EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type()); 1.1023 + EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype()); 1.1024 + EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type()); 1.1025 + EXPECT_EQ(FileFlags(MH_TWOLEVEL | 1.1026 + MH_DYLDLINK | 1.1027 + MH_NOUNDEFS), 1.1028 + reader.flags()); 1.1029 + 1.1030 + ByteBuffer expected; 1.1031 + expected.start = file_bytes + load_commands.start().Value(); 1.1032 + expected.end = expected.start + load_commands.final_size().Value(); 1.1033 + EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a, 1.1034 + expected)) 1.1035 + .WillOnce(Return(true)); 1.1036 + 1.1037 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1038 +} 1.1039 + 1.1040 +TEST_F(LoadCommand, TypeIncomplete) { 1.1041 + WithConfiguration config(kLittleEndian, 32); 1.1042 + LoadCommands load_commands; 1.1043 + load_commands 1.1044 + .CountCommand() 1.1045 + .Append(3, 0); // load command type, incomplete 1.1046 + 1.1047 + MachOFile file; 1.1048 + file.Header(&load_commands); 1.1049 + 1.1050 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1051 + 1.1052 + EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0)) 1.1053 + .WillOnce(Return()); 1.1054 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1055 +} 1.1056 + 1.1057 +TEST_F(LoadCommand, LengthIncomplete) { 1.1058 + WithConfiguration config(kBigEndian, 64); 1.1059 + LoadCommands load_commands; 1.1060 + load_commands 1.1061 + .CountCommand() 1.1062 + .D32(LC_SEGMENT); // load command 1.1063 + // no length 1.1064 + MachOFile file; 1.1065 + file.Header(&load_commands); 1.1066 + 1.1067 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1068 + 1.1069 + EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT)) 1.1070 + .WillOnce(Return()); 1.1071 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1072 +} 1.1073 + 1.1074 +TEST_F(LoadCommand, ContentIncomplete) { 1.1075 + WithConfiguration config(kLittleEndian, 64); 1.1076 + LoadCommands load_commands; 1.1077 + load_commands 1.1078 + .CountCommand() 1.1079 + .D32(LC_SEGMENT) // load command 1.1080 + .D32(40) // total size in bytes 1.1081 + .Append(28, '*'); // not enough dummy data 1.1082 + MachOFile file; 1.1083 + file.Header(&load_commands); 1.1084 + 1.1085 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1086 + 1.1087 + EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT)) 1.1088 + .WillOnce(Return()); 1.1089 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1090 +} 1.1091 + 1.1092 +TEST_F(LoadCommand, SegmentBE32) { 1.1093 + WithConfiguration config(kBigEndian, 32); 1.1094 + LoadedSection segment; 1.1095 + segment.address() = 0x1891139c; 1.1096 + segment.Append(42, '*'); // segment contents 1.1097 + SegmentLoadCommand segment_command; 1.1098 + segment_command 1.1099 + .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd); 1.1100 + segment_command.vmsize() = 0xcb76584fU; 1.1101 + LoadCommands load_commands; 1.1102 + load_commands.Place(&segment_command); 1.1103 + MachOFile file; 1.1104 + file 1.1105 + .Header(&load_commands) 1.1106 + .Place(&segment); 1.1107 + 1.1108 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1109 + 1.1110 + Segment actual_segment; 1.1111 + EXPECT_CALL(load_command_handler, SegmentCommand(_)) 1.1112 + .WillOnce(DoAll(SaveArg<0>(&actual_segment), 1.1113 + Return(true))); 1.1114 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1115 + 1.1116 + EXPECT_EQ(false, actual_segment.bits_64); 1.1117 + EXPECT_EQ("froon", actual_segment.name); 1.1118 + EXPECT_EQ(0x1891139cU, actual_segment.vmaddr); 1.1119 + EXPECT_EQ(0xcb76584fU, actual_segment.vmsize); 1.1120 + EXPECT_EQ(0x94d6dd22U, actual_segment.maxprot); 1.1121 + EXPECT_EQ(0x8bdbc319U, actual_segment.initprot); 1.1122 + EXPECT_EQ(0x990a16ddU, actual_segment.flags); 1.1123 + EXPECT_EQ(0U, actual_segment.nsects); 1.1124 + EXPECT_EQ(0U, actual_segment.section_list.Size()); 1.1125 + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); 1.1126 +} 1.1127 + 1.1128 +TEST_F(LoadCommand, SegmentLE32) { 1.1129 + WithConfiguration config(kLittleEndian, 32); 1.1130 + LoadedSection segment; 1.1131 + segment.address() = 0x4b877866; 1.1132 + segment.Append(42, '*'); // segment contents 1.1133 + SegmentLoadCommand segment_command; 1.1134 + segment_command 1.1135 + .Header("sixteenprecisely", segment, 1.1136 + 0x350759ed, 0x6cf5a62e, 0x990a16dd); 1.1137 + segment_command.vmsize() = 0xcb76584fU; 1.1138 + LoadCommands load_commands; 1.1139 + load_commands.Place(&segment_command); 1.1140 + MachOFile file; 1.1141 + file 1.1142 + .Header(&load_commands) 1.1143 + .Place(&segment); 1.1144 + 1.1145 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1146 + 1.1147 + Segment actual_segment; 1.1148 + EXPECT_CALL(load_command_handler, SegmentCommand(_)) 1.1149 + .WillOnce(DoAll(SaveArg<0>(&actual_segment), 1.1150 + Return(true))); 1.1151 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1152 + 1.1153 + EXPECT_EQ(false, actual_segment.bits_64); 1.1154 + EXPECT_EQ("sixteenprecisely", actual_segment.name); 1.1155 + EXPECT_EQ(0x4b877866U, actual_segment.vmaddr); 1.1156 + EXPECT_EQ(0xcb76584fU, actual_segment.vmsize); 1.1157 + EXPECT_EQ(0x350759edU, actual_segment.maxprot); 1.1158 + EXPECT_EQ(0x6cf5a62eU, actual_segment.initprot); 1.1159 + EXPECT_EQ(0x990a16ddU, actual_segment.flags); 1.1160 + EXPECT_EQ(0U, actual_segment.nsects); 1.1161 + EXPECT_EQ(0U, actual_segment.section_list.Size()); 1.1162 + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); 1.1163 +} 1.1164 + 1.1165 +TEST_F(LoadCommand, SegmentBE64) { 1.1166 + WithConfiguration config(kBigEndian, 64); 1.1167 + LoadedSection segment; 1.1168 + segment.address() = 0x79f484f77009e511ULL; 1.1169 + segment.Append(42, '*'); // segment contents 1.1170 + SegmentLoadCommand segment_command; 1.1171 + segment_command 1.1172 + .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220); 1.1173 + segment_command.vmsize() = 0x8d92397ce6248abaULL; 1.1174 + LoadCommands load_commands; 1.1175 + load_commands.Place(&segment_command); 1.1176 + MachOFile file; 1.1177 + file 1.1178 + .Header(&load_commands) 1.1179 + .Place(&segment); 1.1180 + 1.1181 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1182 + 1.1183 + Segment actual_segment; 1.1184 + EXPECT_CALL(load_command_handler, SegmentCommand(_)) 1.1185 + .WillOnce(DoAll(SaveArg<0>(&actual_segment), 1.1186 + Return(true))); 1.1187 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1188 + 1.1189 + EXPECT_EQ(true, actual_segment.bits_64); 1.1190 + EXPECT_EQ("froon", actual_segment.name); 1.1191 + EXPECT_EQ(0x79f484f77009e511ULL, actual_segment.vmaddr); 1.1192 + EXPECT_EQ(0x8d92397ce6248abaULL, actual_segment.vmsize); 1.1193 + EXPECT_EQ(0x42b45da5U, actual_segment.maxprot); 1.1194 + EXPECT_EQ(0x8bdbc319U, actual_segment.initprot); 1.1195 + EXPECT_EQ(0xb2335220U, actual_segment.flags); 1.1196 + EXPECT_EQ(0U, actual_segment.nsects); 1.1197 + EXPECT_EQ(0U, actual_segment.section_list.Size()); 1.1198 + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); 1.1199 +} 1.1200 + 1.1201 +TEST_F(LoadCommand, SegmentLE64) { 1.1202 + WithConfiguration config(kLittleEndian, 64); 1.1203 + LoadedSection segment; 1.1204 + segment.address() = 0x50c0501dc5922d35ULL; 1.1205 + segment.Append(42, '*'); // segment contents 1.1206 + SegmentLoadCommand segment_command; 1.1207 + segment_command 1.1208 + .Header("sixteenprecisely", segment, 1.1209 + 0x917c339d, 0xdbc446fa, 0xb650b563); 1.1210 + segment_command.vmsize() = 0x84ae73e7c75469bfULL; 1.1211 + LoadCommands load_commands; 1.1212 + load_commands.Place(&segment_command); 1.1213 + MachOFile file; 1.1214 + file 1.1215 + .Header(&load_commands) 1.1216 + .Place(&segment); 1.1217 + 1.1218 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1219 + 1.1220 + Segment actual_segment; 1.1221 + EXPECT_CALL(load_command_handler, SegmentCommand(_)) 1.1222 + .WillOnce(DoAll(SaveArg<0>(&actual_segment), 1.1223 + Return(true))); 1.1224 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1225 + 1.1226 + EXPECT_EQ(true, actual_segment.bits_64); 1.1227 + EXPECT_EQ("sixteenprecisely", actual_segment.name); 1.1228 + EXPECT_EQ(0x50c0501dc5922d35ULL, actual_segment.vmaddr); 1.1229 + EXPECT_EQ(0x84ae73e7c75469bfULL, actual_segment.vmsize); 1.1230 + EXPECT_EQ(0x917c339dU, actual_segment.maxprot); 1.1231 + EXPECT_EQ(0xdbc446faU, actual_segment.initprot); 1.1232 + EXPECT_EQ(0xb650b563U, actual_segment.flags); 1.1233 + EXPECT_EQ(0U, actual_segment.nsects); 1.1234 + EXPECT_EQ(0U, actual_segment.section_list.Size()); 1.1235 + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); 1.1236 +} 1.1237 + 1.1238 +TEST_F(LoadCommand, SegmentCommandTruncated) { 1.1239 + WithConfiguration config(kBigEndian, 32); 1.1240 + LoadedSection segment_contents; 1.1241 + segment_contents.Append(20, '*'); // lah di dah 1.1242 + SizedSection command; 1.1243 + command 1.1244 + .D32(LC_SEGMENT) // command type 1.1245 + .D32(command.final_size()) // command size 1.1246 + .AppendCString("too-short", 16) // segment name 1.1247 + .D32(0x9c759211) // vmaddr 1.1248 + .D32(segment_contents.final_size()) // vmsize 1.1249 + .D32(segment_contents.start()) // file offset 1.1250 + .D32(segment_contents.final_size()) // file size 1.1251 + .D32(0x56f28446) // max protection 1.1252 + .D32(0xe7910dcb) // initial protection 1.1253 + .D32(0) // no sections 1.1254 + .Append(3, 0); // flags (one byte short!) 1.1255 + LoadCommands load_commands; 1.1256 + load_commands.Place(&command); 1.1257 + MachOFile file; 1.1258 + file 1.1259 + .Header(&load_commands) 1.1260 + .Place(&segment_contents); 1.1261 + 1.1262 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1263 + 1.1264 + EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT)) 1.1265 + .WillOnce(Return()); 1.1266 + 1.1267 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1268 +} 1.1269 + 1.1270 +TEST_F(LoadCommand, SegmentBadContentOffset) { 1.1271 + WithConfiguration config(kLittleEndian, 32); 1.1272 + // Instead of letting a Place call set the segment's file offset and size, 1.1273 + // set them ourselves, to check that the parser catches invalid offsets 1.1274 + // instead of handing us bogus pointers. 1.1275 + LoadedSection segment; 1.1276 + segment.address() = 0x4db5489c; 1.1277 + segment.start() = 0x7e189e76; // beyond end of file 1.1278 + segment.final_size() = 0x98b9c3ab; 1.1279 + SegmentLoadCommand segment_command; 1.1280 + segment_command 1.1281 + .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f); 1.1282 + LoadCommands load_commands; 1.1283 + load_commands.Place(&segment_command); 1.1284 + MachOFile file; 1.1285 + file.Header(&load_commands); 1.1286 + 1.1287 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1288 + 1.1289 + EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen")) 1.1290 + .WillOnce(Return()); 1.1291 + 1.1292 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1293 +} 1.1294 + 1.1295 +TEST_F(LoadCommand, ThreeLoadCommands) { 1.1296 + WithConfiguration config(kBigEndian, 32); 1.1297 + LoadedSection seg1, seg2, seg3; 1.1298 + SegmentLoadCommand cmd1, cmd2, cmd3; 1.1299 + 1.1300 + seg1.Append(128, '@'); 1.1301 + seg1.address() = 0xa7f61ef6; 1.1302 + cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87); 1.1303 + // Include some dummy data at the end of the load command. Since we 1.1304 + // didn't claim to have any sections, the reader should ignore this. But 1.1305 + // making sure the commands have different lengths ensures that we're 1.1306 + // using the right command's length to advance the LoadCommandIterator. 1.1307 + cmd1.Append(128, '!'); 1.1308 + 1.1309 + seg2.Append(42, '*'); 1.1310 + seg2.address() = 0xc70fc909; 1.1311 + cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30); 1.1312 + // More dummy data at the end of the load command. 1.1313 + cmd2.Append(32, '^'); 1.1314 + 1.1315 + seg3.Append(42, '%'); 1.1316 + seg3.address() = 0x46b3ab05; 1.1317 + cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b); 1.1318 + // More dummy data at the end of the load command. 1.1319 + cmd3.Append(64, '&'); 1.1320 + 1.1321 + LoadCommands load_commands; 1.1322 + load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3); 1.1323 + 1.1324 + MachOFile file; 1.1325 + file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3); 1.1326 + 1.1327 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1328 + 1.1329 + { 1.1330 + InSequence s; 1.1331 + EXPECT_CALL(load_command_handler, 1.1332 + SegmentCommand(Field(&Segment::name, "head"))) 1.1333 + .WillOnce(Return(true)); 1.1334 + EXPECT_CALL(load_command_handler, 1.1335 + SegmentCommand(Field(&Segment::name, "thorax"))) 1.1336 + .WillOnce(Return(true)); 1.1337 + EXPECT_CALL(load_command_handler, 1.1338 + SegmentCommand(Field(&Segment::name, "abdomen"))) 1.1339 + .WillOnce(Return(true)); 1.1340 + } 1.1341 + 1.1342 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1343 +} 1.1344 + 1.1345 +static inline Matcher<const Section &> MatchSection( 1.1346 + Matcher<bool> bits_64, 1.1347 + Matcher<const string &> section_name, 1.1348 + Matcher<const string &> segment_name, 1.1349 + Matcher<uint64_t> address, 1.1350 + Matcher<uint32_t> alignment, 1.1351 + Matcher<uint32_t> flags, 1.1352 + Matcher<const ByteBuffer &> contents) { 1.1353 + return AllOf(AllOf(Field(&Section::bits_64, bits_64), 1.1354 + Field(&Section::section_name, section_name), 1.1355 + Field(&Section::segment_name, segment_name), 1.1356 + Field(&Section::address, address)), 1.1357 + AllOf(Field(&Section::align, alignment), 1.1358 + Field(&Section::flags, flags), 1.1359 + Field(&Section::contents, contents))); 1.1360 +} 1.1361 + 1.1362 +static inline Matcher<const Section &> MatchSection( 1.1363 + Matcher<bool> bits_64, 1.1364 + Matcher<const string &> section_name, 1.1365 + Matcher<const string &> segment_name, 1.1366 + Matcher<uint64_t> address) { 1.1367 + return AllOf(Field(&Section::bits_64, bits_64), 1.1368 + Field(&Section::section_name, section_name), 1.1369 + Field(&Section::segment_name, segment_name), 1.1370 + Field(&Section::address, address)); 1.1371 +} 1.1372 + 1.1373 +TEST_F(LoadCommand, OneSegmentTwoSections) { 1.1374 + WithConfiguration config(kBigEndian, 64); 1.1375 + 1.1376 + // Create some sections with some data. 1.1377 + LoadedSection section1, section2; 1.1378 + section1.Append("buddha's hand"); 1.1379 + section2.Append("kumquat"); 1.1380 + 1.1381 + // Create a segment to hold them. 1.1382 + LoadedSection segment; 1.1383 + segment.address() = 0xe1d0eeec; 1.1384 + segment.Place(§ion2).Place(§ion1); 1.1385 + 1.1386 + SegmentLoadCommand segment_command; 1.1387 + segment_command 1.1388 + .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2) 1.1389 + .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1) 1.1390 + .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2); 1.1391 + 1.1392 + LoadCommands commands; 1.1393 + commands.Place(&segment_command); 1.1394 + 1.1395 + MachOFile file; 1.1396 + file.Header(&commands).Place(&segment); 1.1397 + 1.1398 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1399 + 1.1400 + Segment actual_segment; 1.1401 + EXPECT_CALL(load_command_handler, SegmentCommand(_)) 1.1402 + .WillOnce(DoAll(SaveArg<0>(&actual_segment), 1.1403 + Return(true))); 1.1404 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1405 + 1.1406 + { 1.1407 + InSequence s; 1.1408 + ByteBuffer contents1; 1.1409 + contents1.start = file_bytes + section1.start().Value(); 1.1410 + contents1.end = contents1.start + section1.final_size().Value(); 1.1411 + EXPECT_EQ("buddha's hand", 1.1412 + string(reinterpret_cast<const char *>(contents1.start), 1.1413 + contents1.Size())); 1.1414 + EXPECT_CALL(section_handler, 1.1415 + HandleSection(MatchSection(true, "mandarin", "kishu", 1.1416 + section1.address().Value(), 12, 1.1417 + 0x8cd4604bU, contents1))) 1.1418 + .WillOnce(Return(true)); 1.1419 + 1.1420 + ByteBuffer contents2; 1.1421 + contents2.start = file_bytes + section2.start().Value(); 1.1422 + contents2.end = contents2.start + section2.final_size().Value(); 1.1423 + EXPECT_EQ("kumquat", 1.1424 + string(reinterpret_cast<const char *>(contents2.start), 1.1425 + contents2.Size())); 1.1426 + EXPECT_CALL(section_handler, 1.1427 + HandleSection(MatchSection(true, "bergamot", "cara cara", 1.1428 + section2.address().Value(), 12, 1.1429 + 0x98746efaU, contents2))) 1.1430 + .WillOnce(Return(true)); 1.1431 + } 1.1432 + 1.1433 + EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); 1.1434 +} 1.1435 + 1.1436 +TEST_F(LoadCommand, MisplacedSectionBefore) { 1.1437 + WithConfiguration config(kLittleEndian, 64); 1.1438 + 1.1439 + // The segment. 1.1440 + LoadedSection segment; 1.1441 + segment.address() = 0x696d83cc; 1.1442 + segment.Append(10, '0'); 1.1443 + 1.1444 + // The contents of the following sections don't matter, because 1.1445 + // we're not really going to Place them in segment; we're just going 1.1446 + // to set all their labels by hand to get the (impossible) 1.1447 + // configurations we want. 1.1448 + 1.1449 + // A section whose starting offset is before that of its section. 1.1450 + LoadedSection before; 1.1451 + before.Append(10, '1'); 1.1452 + before.start() = segment.start() - 1; 1.1453 + before.address() = segment.address() - 1; 1.1454 + before.final_size() = before.Size(); 1.1455 + 1.1456 + SegmentLoadCommand command; 1.1457 + command 1.1458 + .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) 1.1459 + .AppendSectionEntry("before", "segment", 0, 0x686c6921, before); 1.1460 + 1.1461 + LoadCommands commands; 1.1462 + commands.Place(&command); 1.1463 + 1.1464 + MachOFile file; 1.1465 + file.Header(&commands).Place(&segment); 1.1466 + 1.1467 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1468 + 1.1469 + Segment actual_segment; 1.1470 + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); 1.1471 + 1.1472 + EXPECT_CALL(reporter, MisplacedSectionData("before", "segment")) 1.1473 + .WillOnce(Return()); 1.1474 + EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); 1.1475 +} 1.1476 + 1.1477 +TEST_F(LoadCommand, MisplacedSectionAfter) { 1.1478 + WithConfiguration config(kLittleEndian, 64); 1.1479 + 1.1480 + // The segment. 1.1481 + LoadedSection segment; 1.1482 + segment.address() = 0x696d83cc; 1.1483 + segment.Append(10, '0'); 1.1484 + 1.1485 + // The contents of the following sections don't matter, because 1.1486 + // we're not really going to Place them in segment; we're just going 1.1487 + // to set all their labels by hand to get the (impossible) 1.1488 + // configurations we want. 1.1489 + 1.1490 + // A section whose starting offset is after the end of its section. 1.1491 + LoadedSection after; 1.1492 + after.Append(10, '2'); 1.1493 + after.start() = segment.start() + 11; 1.1494 + after.address() = segment.address() + 11; 1.1495 + after.final_size() = after.Size(); 1.1496 + 1.1497 + SegmentLoadCommand command; 1.1498 + command 1.1499 + .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) 1.1500 + .AppendSectionEntry("after", "segment", 0, 0x2ee50124, after); 1.1501 + 1.1502 + LoadCommands commands; 1.1503 + commands.Place(&command); 1.1504 + 1.1505 + MachOFile file; 1.1506 + file.Header(&commands).Place(&segment); 1.1507 + 1.1508 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1509 + 1.1510 + Segment actual_segment; 1.1511 + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); 1.1512 + 1.1513 + EXPECT_CALL(reporter, MisplacedSectionData("after", "segment")) 1.1514 + .WillOnce(Return()); 1.1515 + EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); 1.1516 +} 1.1517 + 1.1518 +TEST_F(LoadCommand, MisplacedSectionTooBig) { 1.1519 + WithConfiguration config(kLittleEndian, 64); 1.1520 + 1.1521 + // The segment. 1.1522 + LoadedSection segment; 1.1523 + segment.address() = 0x696d83cc; 1.1524 + segment.Append(10, '0'); 1.1525 + 1.1526 + // The contents of the following sections don't matter, because 1.1527 + // we're not really going to Place them in segment; we're just going 1.1528 + // to set all their labels by hand to get the (impossible) 1.1529 + // configurations we want. 1.1530 + 1.1531 + // A section that extends beyond the end of its section. 1.1532 + LoadedSection too_big; 1.1533 + too_big.Append(10, '3'); 1.1534 + too_big.start() = segment.start() + 1; 1.1535 + too_big.address() = segment.address() + 1; 1.1536 + too_big.final_size() = too_big.Size(); 1.1537 + 1.1538 + SegmentLoadCommand command; 1.1539 + command 1.1540 + .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) 1.1541 + .AppendSectionEntry("too big", "segment", 0, 0x8b53ae5c, too_big); 1.1542 + 1.1543 + LoadCommands commands; 1.1544 + commands.Place(&command); 1.1545 + 1.1546 + MachOFile file; 1.1547 + file.Header(&commands).Place(&segment); 1.1548 + 1.1549 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1550 + 1.1551 + Segment actual_segment; 1.1552 + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); 1.1553 + 1.1554 + EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment")) 1.1555 + .WillOnce(Return()); 1.1556 + EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); 1.1557 +} 1.1558 + 1.1559 + 1.1560 +// The segments in a .dSYM bundle's Mach-O file have their file offset 1.1561 +// and size set to zero, but the sections don't. The reader shouldn't 1.1562 +// report an error in this case. 1.1563 +TEST_F(LoadCommand, ZappedSegment) { 1.1564 + WithConfiguration config(kBigEndian, 32); 1.1565 + 1.1566 + // The segment. 1.1567 + LoadedSection segment; 1.1568 + segment.address() = 0x696d83cc; 1.1569 + segment.start() = 0; 1.1570 + segment.final_size() = 0; 1.1571 + 1.1572 + // The section. 1.1573 + LoadedSection section; 1.1574 + section.address() = segment.address(); 1.1575 + section.start() = 0; 1.1576 + section.final_size() = 1000; // extends beyond its segment 1.1577 + 1.1578 + SegmentLoadCommand command; 1.1579 + command 1.1580 + .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c) 1.1581 + .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section); 1.1582 + 1.1583 + LoadCommands commands; 1.1584 + commands.Place(&command); 1.1585 + 1.1586 + MachOFile file; 1.1587 + file.Header(&commands); 1.1588 + 1.1589 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1590 + 1.1591 + Segment actual_segment; 1.1592 + EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment)); 1.1593 + 1.1594 + ByteBuffer zapped_extent(NULL, 0); 1.1595 + EXPECT_CALL(section_handler, 1.1596 + HandleSection(MatchSection(false, "twitching", "zapped", 1.1597 + 0x696d83cc, 0, 0x93b3bd42, 1.1598 + zapped_extent))) 1.1599 + .WillOnce(Return(true)); 1.1600 + 1.1601 + EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); 1.1602 +} 1.1603 + 1.1604 +TEST_F(LoadCommand, MapSegmentSections) { 1.1605 + WithConfiguration config(kLittleEndian, 32); 1.1606 + 1.1607 + // Create some sections with some data. 1.1608 + LoadedSection section1, section2, section3, section4; 1.1609 + section1.Append("buddha's hand"); 1.1610 + section2.start() = 0; // Section 2 is an S_ZEROFILL section. 1.1611 + section2.final_size() = 0; 1.1612 + section3.Append("shasta gold"); 1.1613 + section4.Append("satsuma"); 1.1614 + 1.1615 + // Create two segments to hold them. 1.1616 + LoadedSection segment1, segment2; 1.1617 + segment1.address() = 0x13e6c8a9; 1.1618 + segment1.Place(§ion3).Place(§ion1); 1.1619 + segment2.set_word_size(64); 1.1620 + segment2.address() = 0x04d462e2; 1.1621 + segment2.Place(§ion4); 1.1622 + section2.address() = segment2.address() + segment2.Size(); 1.1623 + 1.1624 + SegmentLoadCommand segment_command1, segment_command2; 1.1625 + segment_command1 1.1626 + .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64) 1.1627 + .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1) 1.1628 + .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3); 1.1629 + segment_command2.set_word_size(64); 1.1630 + segment_command2 1.1631 + .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33) 1.1632 + .AppendSectionEntry("sixteenprecisely", "thorax", 1.1633 + 12, S_ZEROFILL, section2) 1.1634 + .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4); 1.1635 + 1.1636 + LoadCommands commands; 1.1637 + commands.Place(&segment_command1).Place(&segment_command2); 1.1638 + 1.1639 + MachOFile file; 1.1640 + file.Header(&commands).Place(&segment1).Place(&segment2); 1.1641 + 1.1642 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1643 + 1.1644 + Segment segment; 1.1645 + SectionMap section_map; 1.1646 + 1.1647 + EXPECT_FALSE(reader.FindSegment("smoot", &segment)); 1.1648 + 1.1649 + ASSERT_TRUE(reader.FindSegment("thorax", &segment)); 1.1650 + ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map)); 1.1651 + 1.1652 + EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome") 1.1653 + != section_map.end()); 1.1654 + EXPECT_FALSE(section_map.find("mandarin") != section_map.end()); 1.1655 + ASSERT_TRUE(section_map.find("cara cara") != section_map.end()); 1.1656 + EXPECT_THAT(section_map["cara cara"], 1.1657 + MatchSection(true, "cara cara", "thorax", 0x04d462e2)); 1.1658 + ASSERT_TRUE(section_map.find("sixteenprecisely") 1.1659 + != section_map.end()); 1.1660 + ByteBuffer sixteenprecisely_contents(NULL, 0); 1.1661 + EXPECT_THAT(section_map["sixteenprecisely"], 1.1662 + MatchSection(true, "sixteenprecisely", "thorax", 1.1663 + 0x04d462e2 + 7, 12, S_ZEROFILL, 1.1664 + sixteenprecisely_contents)); 1.1665 + 1.1666 + ASSERT_TRUE(reader.FindSegment("head", &segment)); 1.1667 + ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map)); 1.1668 + 1.1669 + ASSERT_TRUE(section_map.find("mandarin") != section_map.end()); 1.1670 + EXPECT_THAT(section_map["mandarin"], 1.1671 + MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11)); 1.1672 + ASSERT_TRUE(section_map.find("bergamot") != section_map.end()); 1.1673 + EXPECT_THAT(section_map["bergamot"], 1.1674 + MatchSection(false, "bergamot", "head", 0x13e6c8a9)); 1.1675 +} 1.1676 + 1.1677 +TEST_F(LoadCommand, FindSegment) { 1.1678 + WithConfiguration config(kBigEndian, 32); 1.1679 + 1.1680 + LoadedSection segment1, segment2, segment3; 1.1681 + segment1.address() = 0xb8ae5752; 1.1682 + segment1.Append("Some contents!"); 1.1683 + segment2.address() = 0xd6b0ce83; 1.1684 + segment2.Append("Different stuff."); 1.1685 + segment3.address() = 0x7374fd2a; 1.1686 + segment3.Append("Further materials."); 1.1687 + 1.1688 + SegmentLoadCommand cmd1, cmd2, cmd3; 1.1689 + cmd1.Header("first", segment1, 0xfadb6932, 0x175bf529, 0x0de790ad); 1.1690 + cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef); 1.1691 + cmd3.Header("third", segment3, 0xe172b39e, 0x86012f07, 0x080ac94d); 1.1692 + 1.1693 + LoadCommands commands; 1.1694 + commands.Place(&cmd1).Place(&cmd2).Place(&cmd3); 1.1695 + 1.1696 + MachOFile file; 1.1697 + file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3); 1.1698 + 1.1699 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1700 + 1.1701 + Segment actual_segment; 1.1702 + 1.1703 + EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment)); 1.1704 + 1.1705 + EXPECT_TRUE(reader.FindSegment("second", &actual_segment)); 1.1706 + EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr); 1.1707 +} 1.1708 + 1.1709 + 1.1710 +// Symtab tests. 1.1711 + 1.1712 +// A StringAssembler is a class for generating .stabstr sections to present 1.1713 +// as input to the STABS parser. 1.1714 +class StringAssembler: public SizedSection { 1.1715 + public: 1.1716 + // Add the string S to this StringAssembler, and return the string's 1.1717 + // offset within this compilation unit's strings. 1.1718 + size_t Add(const string &s) { 1.1719 + size_t offset = Size(); 1.1720 + AppendCString(s); 1.1721 + return offset; 1.1722 + } 1.1723 +}; 1.1724 + 1.1725 +// A SymbolAssembler is a class for generating .stab sections to present as 1.1726 +// test input for the STABS parser. 1.1727 +class SymbolAssembler: public SizedSection { 1.1728 + public: 1.1729 + // Create a SymbolAssembler that uses StringAssembler for its strings. 1.1730 + explicit SymbolAssembler(StringAssembler *string_assembler) 1.1731 + : string_assembler_(string_assembler), 1.1732 + entry_count_(0) { } 1.1733 + 1.1734 + // Append a STAB entry to the end of this section with the given 1.1735 + // characteristics. NAME is the offset of this entry's name string within 1.1736 + // its compilation unit's portion of the .stabstr section; this can be a 1.1737 + // value generated by a StringAssembler. Return a reference to this 1.1738 + // SymbolAssembler. 1.1739 + SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, 1.1740 + Label value, Label name) { 1.1741 + D32(name); 1.1742 + D8(type); 1.1743 + D8(other); 1.1744 + D16(descriptor); 1.1745 + Append(endianness(), word_size_ / 8, value); 1.1746 + entry_count_++; 1.1747 + return *this; 1.1748 + } 1.1749 + 1.1750 + // As above, but automatically add NAME to our StringAssembler. 1.1751 + SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, 1.1752 + Label value, const string &name) { 1.1753 + return Symbol(type, other, descriptor, value, string_assembler_->Add(name)); 1.1754 + } 1.1755 + 1.1756 + private: 1.1757 + // The strings for our STABS entries. 1.1758 + StringAssembler *string_assembler_; 1.1759 + 1.1760 + // The number of entries in this compilation unit so far. 1.1761 + size_t entry_count_; 1.1762 +}; 1.1763 + 1.1764 +class Symtab: public ReaderFixture, public Test { }; 1.1765 + 1.1766 +TEST_F(Symtab, Symtab32) { 1.1767 + WithConfiguration config(kLittleEndian, 32); 1.1768 + 1.1769 + StringAssembler strings; 1.1770 + SymbolAssembler symbols(&strings); 1.1771 + symbols 1.1772 + .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu") 1.1773 + .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith"); 1.1774 + 1.1775 + SizedSection symtab_command; 1.1776 + symtab_command 1.1777 + .D32(LC_SYMTAB) // command 1.1778 + .D32(symtab_command.final_size()) // size 1.1779 + .D32(symbols.start()) // file offset of symbols 1.1780 + .D32(2) // symbol count 1.1781 + .D32(strings.start()) // file offset of strings 1.1782 + .D32(strings.final_size()); // strings size 1.1783 + 1.1784 + LoadCommands load_commands; 1.1785 + load_commands.Place(&symtab_command); 1.1786 + 1.1787 + MachOFile file; 1.1788 + file.Header(&load_commands).Place(&symbols).Place(&strings); 1.1789 + 1.1790 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1791 + 1.1792 + ByteBuffer symbols_found, strings_found; 1.1793 + EXPECT_CALL(load_command_handler, SymtabCommand(_, _)) 1.1794 + .WillOnce(DoAll(SaveArg<0>(&symbols_found), 1.1795 + SaveArg<1>(&strings_found), 1.1796 + Return(true))); 1.1797 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1798 + 1.1799 + EXPECT_EQ(24U, symbols_found.Size()); 1.1800 + EXPECT_EQ(14U, strings_found.Size()); 1.1801 +} 1.1802 + 1.1803 +TEST_F(Symtab, Symtab64) { 1.1804 + WithConfiguration config(kBigEndian, 64); 1.1805 + 1.1806 + StringAssembler strings; 1.1807 + SymbolAssembler symbols(&strings); 1.1808 + symbols 1.1809 + .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") 1.1810 + .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); 1.1811 + 1.1812 + SizedSection symtab_command; 1.1813 + symtab_command 1.1814 + .D32(LC_SYMTAB) // command 1.1815 + .D32(symtab_command.final_size()) // size 1.1816 + .D32(symbols.start()) // file offset of symbols 1.1817 + .D32(2) // symbol count 1.1818 + .D32(strings.start()) // file offset of strings 1.1819 + .D32(strings.final_size()); // strings size 1.1820 + 1.1821 + LoadCommands load_commands; 1.1822 + load_commands.Place(&symtab_command); 1.1823 + 1.1824 + MachOFile file; 1.1825 + file.Header(&load_commands).Place(&symbols).Place(&strings); 1.1826 + 1.1827 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1828 + 1.1829 + ByteBuffer symbols_found, strings_found; 1.1830 + EXPECT_CALL(load_command_handler, SymtabCommand(_, _)) 1.1831 + .WillOnce(DoAll(SaveArg<0>(&symbols_found), 1.1832 + SaveArg<1>(&strings_found), 1.1833 + Return(true))); 1.1834 + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); 1.1835 + 1.1836 + EXPECT_EQ(32U, symbols_found.Size()); 1.1837 + EXPECT_EQ(8U, strings_found.Size()); 1.1838 +} 1.1839 + 1.1840 +TEST_F(Symtab, SymtabMisplacedSymbols) { 1.1841 + WithConfiguration config(kBigEndian, 32); 1.1842 + 1.1843 + StringAssembler strings; 1.1844 + SymbolAssembler symbols(&strings); 1.1845 + symbols 1.1846 + .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") 1.1847 + .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); 1.1848 + 1.1849 + SizedSection symtab_command; 1.1850 + symtab_command 1.1851 + .D32(LC_SYMTAB) // command 1.1852 + .D32(symtab_command.final_size()) // size 1.1853 + .D32(symbols.start()) // file offset of symbols 1.1854 + .D32(3) // symbol count (too many) 1.1855 + .D32(strings.start()) // file offset of strings 1.1856 + .D32(strings.final_size()); // strings size 1.1857 + 1.1858 + LoadCommands load_commands; 1.1859 + load_commands.Place(&symtab_command); 1.1860 + 1.1861 + MachOFile file; 1.1862 + // Put symbols at end, so the excessive length will be noticed. 1.1863 + file.Header(&load_commands).Place(&strings).Place(&symbols); 1.1864 + 1.1865 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1866 + 1.1867 + EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1); 1.1868 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1869 +} 1.1870 + 1.1871 +TEST_F(Symtab, SymtabMisplacedStrings) { 1.1872 + WithConfiguration config(kLittleEndian, 32); 1.1873 + 1.1874 + StringAssembler strings; 1.1875 + SymbolAssembler symbols(&strings); 1.1876 + symbols 1.1877 + .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") 1.1878 + .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); 1.1879 + 1.1880 + SizedSection symtab_command; 1.1881 + symtab_command 1.1882 + .D32(LC_SYMTAB) // command 1.1883 + .D32(symtab_command.final_size()) // size 1.1884 + .D32(symbols.start()) // file offset of symbols 1.1885 + .D32(2) // symbol count 1.1886 + .D32(strings.start()) // file offset of strings 1.1887 + .D32(strings.final_size() + 1); // strings size (too long) 1.1888 + 1.1889 + LoadCommands load_commands; 1.1890 + load_commands.Place(&symtab_command); 1.1891 + 1.1892 + MachOFile file; 1.1893 + // Put strings at end, so the excessive length will be noticed. 1.1894 + file.Header(&load_commands).Place(&symbols).Place(&strings); 1.1895 + 1.1896 + ReadFile(&file, true, CPU_TYPE_ANY, 0); 1.1897 + 1.1898 + EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1); 1.1899 + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); 1.1900 +} 1.1901 +