135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// Copyright (c) 2010, Google Inc. 235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// All rights reserved. 335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// 435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// Redistribution and use in source and binary forms, with or without 535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// modification, are permitted provided that the following conditions are 635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// met: 735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// 835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// * Redistributions of source code must retain the above copyright 935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// notice, this list of conditions and the following disclaimer. 1035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// * Redistributions in binary form must reproduce the above 1135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// copyright notice, this list of conditions and the following disclaimer 1235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// in the documentation and/or other materials provided with the 1335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// distribution. 1435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// * Neither the name of Google Inc. nor the names of its 1535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// contributors may be used to endorse or promote products derived from 1635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// this software without specific prior written permission. 1735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// 1835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 3035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 3135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 3235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and 3335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// google_breakpad::Mach_O::Reader. See macho_reader.h for details. 3435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 3535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include "common/mac/macho_reader.h" 3635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 3735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include <assert.h> 3835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include <stdio.h> 3935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include <stdlib.h> 4035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 41316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org// Unfortunately, CPU_TYPE_ARM is not define for 10.4. 42316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org#if !defined(CPU_TYPE_ARM) 43316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org#define CPU_TYPE_ARM 12 44316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org#endif 45316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org 46d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org#if !defined(CPU_TYPE_ARM_64) 47d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org#define CPU_TYPE_ARM_64 16777228 48d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org#endif 49d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org 5035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczareknamespace google_breakpad { 5135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczareknamespace mach_o { 5235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 5335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its 5435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// arguments, so you can't place expressions that do necessary work in 5535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// the argument of an assert. Nor can you assign the result of the 5635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// expression to a variable and assert that the variable's value is 5735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// true: you'll get unused variable warnings when NDEBUG is #defined. 5835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// 5935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that 6035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// the result is true if NDEBUG is not #defined. 6135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#if defined(NDEBUG) 6235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#define ASSERT_ALWAYS_EVAL(x) (x) 6335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#else 6435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#define ASSERT_ALWAYS_EVAL(x) assert(x) 6535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#endif 6635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 6735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid FatReader::Reporter::BadHeader() { 6835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file is neither a fat binary file" 6935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " nor a Mach-O object file\n", filename_.c_str()); 7035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 7135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 7235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid FatReader::Reporter::TooShort() { 7335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file too short for the data it claims to contain\n", 7435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str()); 7535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 7635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 7735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid FatReader::Reporter::MisplacedObjectFile() { 7835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file too short for the object files it claims" 7935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " to contain\n", filename_.c_str()); 8035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 8135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 8235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool FatReader::Read(const uint8_t *buffer, size_t size) { 8335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek buffer_.start = buffer; 8435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek buffer_.end = buffer + size; 8535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteCursor cursor(&buffer_); 8635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 8735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Fat binaries always use big-endian, so read the magic number in 8835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // that endianness. To recognize Mach-O magic numbers, which can use 8935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // either endianness, check for both the proper and reversed forms 9035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // of the magic numbers. 9135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor.set_big_endian(true); 9235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (cursor >> magic_) { 9335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (magic_ == FAT_MAGIC) { 9435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // How many object files does this fat binary contain? 9535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t object_files_count; 9635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!(cursor >> object_files_count)) { // nfat_arch 9735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->TooShort(); 9835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 9935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 10035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 10135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Read the list of object files. 10235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek object_files_.resize(object_files_count); 10335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek for (size_t i = 0; i < object_files_count; i++) { 10435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek struct fat_arch *objfile = &object_files_[i]; 10535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 10635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Read this object file entry, byte-swapping as appropriate. 10735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor >> objfile->cputype 10835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> objfile->cpusubtype 10935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> objfile->offset 11035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> objfile->size 11135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> objfile->align; 11235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!cursor) { 11335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->TooShort(); 11435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 11535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 11635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Does the file actually have the bytes this entry refers to? 11735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t fat_size = buffer_.Size(); 11835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (objfile->offset > fat_size || 11935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek objfile->size > fat_size - objfile->offset) { 12035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->MisplacedObjectFile(); 12135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 12235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 12335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 12435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 12535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 12635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 || 12735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) { 12835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // If this is a little-endian Mach-O file, fix the cursor's endianness. 12935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) 13035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor.set_big_endian(false); 13135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Record the entire file as a single entry in the object file list. 13235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek object_files_.resize(1); 13335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 13435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Get the cpu type and subtype from the Mach-O header. 13535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!(cursor >> object_files_[0].cputype 13635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> object_files_[0].cpusubtype)) { 13735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->TooShort(); 13835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 13935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 14035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 14135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek object_files_[0].offset = 0; 1424ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach object_files_[0].size = static_cast<uint32_t>(buffer_.Size()); 14335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // This alignment is correct for 32 and 64-bit x86 and ppc. 14435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // See get_align in the lipo source for other architectures: 14535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c 14635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek object_files_[0].align = 12; // 2^12 == 4096 14735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 14835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 14935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 15035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 15135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 15235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->BadHeader(); 15335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 15435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 15535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 15635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::BadHeader() { 15735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str()); 15835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 15935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 16035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type, 16135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cpu_subtype_t cpu_subtype, 16235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cpu_type_t expected_cpu_type, 16335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cpu_subtype_t expected_cpu_subtype) { 16435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected" 16535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " type %d, subtype %d\n", 16635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str(), cpu_type, cpu_subtype, 16735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_cpu_type, expected_cpu_subtype); 16835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 16935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 17035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::HeaderTruncated() { 17135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file does not contain a complete Mach-O header\n", 17235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str()); 17335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 17435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 17535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::LoadCommandRegionTruncated() { 17635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file too short to hold load command region" 17735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " given in Mach-O header\n", filename_.c_str()); 17835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 17935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 18035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i, 18135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek LoadCommandType type) { 18235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: file's header claims there are %ld" 18335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " load commands, but load command #%ld", 18435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str(), claimed, i); 18535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (type) fprintf(stderr, ", of type %d,", type); 18635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, " extends beyond the end of the load command region\n"); 18735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 18835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 18935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) { 19035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: the contents of load command #%ld, of type %d," 19135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " extend beyond the size given in the load command's header\n", 19235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str(), i, type); 19335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 19435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 19535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::SectionsMissing(const string &name) { 19635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: the load command for segment '%s'" 19735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " is too short to hold the section headers it claims to have\n", 19835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str(), name.c_str()); 19935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 20035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 20135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::MisplacedSegmentData(const string &name) { 20235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond" 20335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " the end of the file\n", filename_.c_str(), name.c_str()); 20435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 20535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 20635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::MisplacedSectionData(const string §ion, 20735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek const string &segment) { 20835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: the section '%s' in segment '%s'" 20935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " claims its contents lie outside the segment's contents\n", 21035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str(), section.c_str(), segment.c_str()); 21135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 21235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 21335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::MisplacedSymbolTable() { 21435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol" 21535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek " table's contents are located beyond the end of the file\n", 21635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str()); 21735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 21835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 21935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) { 22035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek fprintf(stderr, "%s: CPU type %d is not supported\n", 22135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek filename_.c_str(), cpu_type); 22235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 22335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 22435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::Read(const uint8_t *buffer, 22535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t size, 22635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cpu_type_t expected_cpu_type, 22735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cpu_subtype_t expected_cpu_subtype) { 22835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek assert(!buffer_.start); 22935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek buffer_.start = buffer; 23035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek buffer_.end = buffer + size; 23135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteCursor cursor(&buffer_, true); 23235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t magic; 23335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!(cursor >> magic)) { 23435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->HeaderTruncated(); 23535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 23635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 23735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 23835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (expected_cpu_type != CPU_TYPE_ANY) { 23935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t expected_magic; 24035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // validate that magic matches the expected cpu type 24135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek switch (expected_cpu_type) { 242316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org case CPU_TYPE_ARM: 24335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case CPU_TYPE_I386: 24435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_magic = MH_CIGAM; 24535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 24635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case CPU_TYPE_POWERPC: 24735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_magic = MH_MAGIC; 24835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 249d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org case CPU_TYPE_ARM_64: 25035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case CPU_TYPE_X86_64: 25135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_magic = MH_CIGAM_64; 25235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 25335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case CPU_TYPE_POWERPC64: 25435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_magic = MH_MAGIC_64; 25535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 25635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek default: 25735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->UnsupportedCPUType(expected_cpu_type); 25835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 25935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 26035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 26135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (expected_magic != magic) { 26235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->BadHeader(); 26335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 26435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 26535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 26635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 26735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Since the byte cursor is in big-endian mode, a reversed magic number 26835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // always indicates a little-endian file, regardless of our own endianness. 26935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek switch (magic) { 27035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case MH_MAGIC: big_endian_ = true; bits_64_ = false; break; 27135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case MH_CIGAM: big_endian_ = false; bits_64_ = false; break; 27235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case MH_MAGIC_64: big_endian_ = true; bits_64_ = true; break; 27335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case MH_CIGAM_64: big_endian_ = false; bits_64_ = true; break; 27435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek default: 27535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->BadHeader(); 27635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 27735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 27835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor.set_big_endian(big_endian_); 27935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t commands_size, reserved; 28035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_ 28135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> commands_size >> flags_; 28235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (bits_64_) 28335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor >> reserved; 28435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!cursor) { 28535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->HeaderTruncated(); 28635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 28735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 28835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 28935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (expected_cpu_type != CPU_TYPE_ANY && 29035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek (expected_cpu_type != cpu_type_ || 29135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_cpu_subtype != cpu_subtype_)) { 29235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_, 29335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek expected_cpu_type, expected_cpu_subtype); 29435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 29535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 29635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 29735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor 29835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .PointTo(&load_commands_.start, commands_size) 29935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .PointTo(&load_commands_.end, 0); 30035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!cursor) { 30135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->LoadCommandRegionTruncated(); 30235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 30335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 30435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 30535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 30635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 30735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 30835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { 30935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteCursor list_cursor(&load_commands_, big_endian_); 31035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 31135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek for (size_t index = 0; index < load_command_count_; ++index) { 31235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // command refers to this load command alone, so that cursor will 31335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // refuse to read past the load command's end. But since we haven't 31435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // read the size yet, let command initially refer to the entire 31535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // remainder of the load command series. 31635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteBuffer command(list_cursor.here(), list_cursor.Available()); 31735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteCursor cursor(&command, big_endian_); 31835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 31935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Read the command type and size --- fields common to all commands. 32035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t type, size; 32135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!(cursor >> type)) { 32235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->LoadCommandsOverrun(load_command_count_, index, 0); 32335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 32435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 32535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!(cursor >> size) || size > command.Size()) { 32635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->LoadCommandsOverrun(load_command_count_, index, type); 32735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 32835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 32935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 33035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Now that we've read the length, restrict command's range to this 33135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // load command only. 33235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek command.end = command.start + size; 33335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 33435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek switch (type) { 33535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case LC_SEGMENT: 33635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case LC_SEGMENT_64: { 33735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek Segment segment; 33835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.bits_64 = (type == LC_SEGMENT_64); 33935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t word_size = segment.bits_64 ? 8 : 4; 34035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor.CString(&segment.name, 16); 34135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t file_offset, file_size; 34235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor 34335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .Read(word_size, false, &segment.vmaddr) 34435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .Read(word_size, false, &segment.vmsize) 34535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .Read(word_size, false, &file_offset) 34635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .Read(word_size, false, &file_size); 34735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor >> segment.maxprot 34835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> segment.initprot 34935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> segment.nsects 35035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> segment.flags; 35135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!cursor) { 35235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->LoadCommandTooShort(index, type); 35335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 35435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 35535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (file_offset > buffer_.Size() || 35635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek file_size > buffer_.Size() - file_offset) { 35735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->MisplacedSegmentData(segment.name); 35835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 35935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 36035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Mach-O files in .dSYM bundles have the contents of the loaded 36135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // segments removed, and their file offsets and file sizes zeroed 36235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // out. To help us handle this special case properly, give such 36335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // segments' contents NULL starting and ending pointers. 36435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (file_offset == 0 && file_size == 0) { 36535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.contents.start = segment.contents.end = NULL; 36635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } else { 36735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.contents.start = buffer_.start + file_offset; 36835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.contents.end = segment.contents.start + file_size; 36935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 37035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // The section list occupies the remainder of this load command's space. 37135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.section_list.start = cursor.here(); 37235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.section_list.end = command.end; 37335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 37435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!handler->SegmentCommand(segment)) 37535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 37635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 37735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 37835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 37935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek case LC_SYMTAB: { 38035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t symoff, nsyms, stroff, strsize; 38135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor >> symoff >> nsyms >> stroff >> strsize; 38235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!cursor) { 38335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->LoadCommandTooShort(index, type); 38435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 38535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 38635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // How big are the entries in the symbol table? 38735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // sizeof(struct nlist_64) : sizeof(struct nlist), 38835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // but be paranoid about alignment vs. target architecture. 38935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t symbol_size = bits_64_ ? 16 : 12; 39035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // How big is the entire symbol array? 39135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t symbols_size = nsyms * symbol_size; 39235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff || 39335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) { 39435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->MisplacedSymbolTable(); 39535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 39635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 39735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteBuffer entries(buffer_.start + symoff, symbols_size); 39835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteBuffer names(buffer_.start + stroff, strsize); 39935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!handler->SymtabCommand(entries, names)) 40035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 40135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 40235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 40335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 40435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek default: { 40535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!handler->UnknownCommand(type, command)) 40635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 40735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek break; 40835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 40935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 41035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 41135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek list_cursor.set_here(command.end); 41235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 41335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 41435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 41535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 41635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 41735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// A load command handler that looks for a segment of a given name. 41835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekclass Reader::SegmentFinder : public LoadCommandHandler { 41935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek public: 42035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Create a load command handler that looks for a segment named NAME, 42135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // and sets SEGMENT to describe it if found. 42235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SegmentFinder(const string &name, Segment *segment) 42335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek : name_(name), segment_(segment), found_() { } 42435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 42535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Return true if the traversal found the segment, false otherwise. 42635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek bool found() const { return found_; } 42735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 42835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek bool SegmentCommand(const Segment &segment) { 42935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (segment.name == name_) { 43035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek *segment_ = segment; 43135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek found_ = true; 43235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 43335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 43435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 43535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 43635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 43735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek private: 43835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // The name of the segment our creator is looking for. 43935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek const string &name_; 44035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 44135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Where we should store the segment if found. (WEAK) 44235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek Segment *segment_; 44335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 44435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // True if we found the segment. 44535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek bool found_; 44635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}; 44735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 44835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::FindSegment(const string &name, Segment *segment) const { 44935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SegmentFinder finder(name, segment); 45035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek WalkLoadCommands(&finder); 45135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return finder.found(); 45235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 45335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 45435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::WalkSegmentSections(const Segment &segment, 45535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SectionHandler *handler) const { 45635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size_t word_size = segment.bits_64 ? 8 : 4; 45735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek ByteCursor cursor(&segment.section_list, big_endian_); 45835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 45935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek for (size_t i = 0; i < segment.nsects; i++) { 46035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek Section section; 46135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section.bits_64 = segment.bits_64; 46235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint64_t size; 46335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek uint32_t offset, dummy32; 46435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor 46535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .CString(§ion.section_name, 16) 46635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .CString(§ion.segment_name, 16) 46735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .Read(word_size, false, §ion.address) 46835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek .Read(word_size, false, &size) 46935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> offset 47035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> section.align 47135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> dummy32 47235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> dummy32 47335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> section.flags 47435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> dummy32 47535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek >> dummy32; 47635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (section.bits_64) 47735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek cursor >> dummy32; 47835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!cursor) { 47935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->SectionsMissing(segment.name); 48035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 48135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 48235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if ((section.flags & SECTION_TYPE) == S_ZEROFILL) { 48335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Zero-fill sections have a size, but no contents. 48435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section.contents.start = section.contents.end = NULL; 48535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } else if (segment.contents.start == NULL && 48635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek segment.contents.end == NULL) { 48735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Mach-O files in .dSYM bundles have the contents of the loaded 48835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // segments removed, and their file offsets and file sizes zeroed 48935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // out. However, the sections within those segments still have 49035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // non-zero sizes. There's no reason to call MisplacedSectionData in 49135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // this case; the caller may just need the section's load 49235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // address. But do set the contents' limits to NULL, for safety. 49335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section.contents.start = section.contents.end = NULL; 49435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } else { 49535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (offset < size_t(segment.contents.start - buffer_.start) || 49635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek offset > size_t(segment.contents.end - buffer_.start) || 49735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek size > size_t(segment.contents.end - buffer_.start - offset)) { 49835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek reporter_->MisplacedSectionData(section.section_name, 49935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section.segment_name); 50035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 50135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 50235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section.contents.start = buffer_.start + offset; 50335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section.contents.end = section.contents.start + size; 50435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 50535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek if (!handler->HandleSection(section)) 50635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return false; 50735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 50835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 50935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 51035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 51135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// A SectionHandler that builds a SectionMap for the sections within a 51235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// given segment. 51335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekclass Reader::SectionMapper: public SectionHandler { 51435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek public: 51535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // Create a SectionHandler that populates MAP with an entry for 51635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // each section it is given. 51735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SectionMapper(SectionMap *map) : map_(map) { } 51835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek bool HandleSection(const Section §ion) { 51935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek (*map_)[section.section_name] = section; 52035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return true; 52135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek } 52235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek private: 52335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek // The map under construction. (WEAK) 52435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SectionMap *map_; 52535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}; 52635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 52735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::MapSegmentSections(const Segment &segment, 52835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SectionMap *section_map) const { 52935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek section_map->clear(); 53035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek SectionMapper mapper(section_map); 53135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek return WalkSegmentSections(segment, &mapper); 53235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} 53335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek 53435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} // namespace mach_o 53535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek} // namespace google_breakpad 536