X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/07feaf2cb00322d025073eb8ec22189ada5e4180..a645023da60d22e86be13f7b4d97adeff8bc6665:/src/ld/MachOReaderRelocatable.hpp diff --git a/src/ld/MachOReaderRelocatable.hpp b/src/ld/MachOReaderRelocatable.hpp deleted file mode 100644 index 2aa7926..0000000 --- a/src/ld/MachOReaderRelocatable.hpp +++ /dev/null @@ -1,6125 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2005-2009 Apple Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef __OBJECT_FILE_MACH_O__ -#define __OBJECT_FILE_MACH_O__ - -#include -#include -#include -#include - -#include -#include -#include - -#include "MachOFileAbstraction.hpp" -#include "Architectures.hpp" -#include "ObjectFile.h" -#include "dwarf2.h" -#include "debugline.h" - -#include -#include -#include - -// -// -// To implement architecture xxx, you must write template specializations for the following six methods: -// Reader::validFile() -// Reader::validSectionType() -// Reader::addRelocReference() -// Reference::getDescription() -// -// - - - -extern __attribute__((noreturn)) void throwf(const char* format, ...); -extern void warning(const char* format, ...); - -namespace mach_o { -namespace relocatable { - - - -class ReferenceSorter -{ -public: - bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right) - { - return ( left->getFixUpOffset() < right->getFixUpOffset() ); - } -}; - - -// forward reference -template class Reader; - -struct AtomAndOffset -{ - AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {} - AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {} - ObjectFile::Atom* atom; - uint32_t offset; -}; - - -template -class Reference : public ObjectFile::Reference -{ -public: - typedef typename A::P P; - typedef typename A::P::uint_t pint_t; - typedef typename A::ReferenceKinds Kinds; - - Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget); - Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget); - Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset); - - virtual ~Reference() {} - - - virtual ObjectFile::Reference::TargetBinding getTargetBinding() const; - virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const; - virtual uint8_t getKind() const { return (uint8_t)fKind; } - virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; } - virtual const char* getTargetName() const { return (fToTarget.atom != NULL) ? fToTarget.atom->getName() : fToTargetName; } - virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; } - virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); } - virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; } - virtual const char* getFromTargetName() const { return (fFromTarget.atom != NULL) ? fFromTarget.atom->getName() : fFromTargetName; } - virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = ⌖ fToTarget.offset = offset; } - virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; } - virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = ⌖ } - virtual void setFromTargetName(const char* name) { fFromTargetName = name; } - virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; } - virtual const char* getDescription() const; - virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; } - virtual bool isBranch() const; - virtual const char* getTargetDisplayName() const { return (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName; } - virtual const char* getFromTargetDisplayName() const { return (fFromTarget.atom != NULL) ? fFromTarget.atom->getDisplayName() : fFromTargetName; } - - static bool fgForFinalLinkedImage; - -private: - pint_t fFixUpOffsetInSrc; - AtomAndOffset fToTarget; - AtomAndOffset fFromTarget; - const char* fToTargetName; - const char* fFromTargetName; - Kinds fKind; - -}; - - -template bool Reference::fgForFinalLinkedImage = true; - -template -Reference::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget) - : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL), - fKind(kind) -{ - // make reference a by-name unless: - // - the reference type is only used with direct references - // - the target is translation unit scoped - // - the target kind is not regular (is weak or tentative) - if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate) - && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) - && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) - && (toTarget.atom != at.atom) ) { - fToTargetName = toTarget.atom->getName(); - //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d, target section=%s\n", toTarget.atom, fToTargetName, toTarget.atom->getScope(), toTarget.atom->getSectionName()); - fToTarget.atom = NULL; - } - ((class BaseAtom*)at.atom)->addReference(this); - //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset); -} - -template -Reference::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget) - : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget), - fToTargetName(NULL), fFromTargetName(NULL), fKind(kind) -{ - // make reference a by-name where needed - if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate) - && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) - && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) - && (toTarget.atom != at.atom) ) { - fToTargetName = toTarget.atom->getName(); - fToTarget.atom = NULL; - } - ((class BaseAtom*)at.atom)->addReference(this); - //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind, - // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset); -} - -template -Reference::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset) - : fFixUpOffsetInSrc(at.offset), - fToTargetName(toName), fFromTargetName(NULL), fKind(kind) -{ - fToTarget.offset = toOffset; - ((class BaseAtom*)at.atom)->addReference(this); -} - -template -ObjectFile::Reference::TargetBinding Reference::getTargetBinding() const -{ - if ( fgForFinalLinkedImage ) { - if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) ) - return ObjectFile::Reference::kDontBind; - } - if ( fToTarget.atom == NULL ) - return ObjectFile::Reference::kUnboundByName; - if ( fToTargetName == NULL ) - return ObjectFile::Reference::kBoundDirectly; - else - return ObjectFile::Reference::kBoundByName; -} - -template -ObjectFile::Reference::TargetBinding Reference::getFromTargetBinding() const -{ - if ( fFromTarget.atom == NULL ) { - if ( fFromTargetName == NULL ) - return ObjectFile::Reference::kDontBind; - else - return ObjectFile::Reference::kUnboundByName; - } - else { - if ( fFromTargetName == NULL ) - return ObjectFile::Reference::kBoundDirectly; - else - return ObjectFile::Reference::kBoundByName; - } -} - - - -template -class Segment : public ObjectFile::Segment -{ -public: - Segment(const macho_section* sect); - virtual const char* getName() const { return fSection->segname(); } - virtual bool isContentReadable() const { return true; } - virtual bool isContentWritable() const { return fWritable; } - virtual bool isContentExecutable() const { return fExecutable; } -private: - const macho_section* fSection; - bool fWritable; - bool fExecutable; -}; - -template -Segment::Segment(const macho_section* sect) - : fSection(sect), fWritable(true), fExecutable(false) -{ - if ( strcmp(fSection->segname(), "__TEXT") == 0 ) { - fWritable = false; - fExecutable = true; - } - else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) { - fWritable = true; - fExecutable = true; - } -} - - -class DataSegment : public ObjectFile::Segment -{ -public: - virtual const char* getName() const { return "__DATA"; } - virtual bool isContentReadable() const { return true; } - virtual bool isContentWritable() const { return true; } - virtual bool isContentExecutable() const { return false; } - - static DataSegment fgSingleton; -}; - -DataSegment DataSegment::fgSingleton; - -class LinkEditSegment : public ObjectFile::Segment -{ -public: - virtual const char* getName() const { return "__LINKEDIT"; } - virtual bool isContentReadable() const { return true; } - virtual bool isContentWritable() const { return false; } - virtual bool isContentExecutable() const { return false; } - - static LinkEditSegment fgSingleton; -}; - -LinkEditSegment LinkEditSegment::fgSingleton; - -class BaseAtom : public ObjectFile::Atom -{ -public: - BaseAtom() : fStabsStartIndex(0), fStabsCount(0), fHasCompactUnwindInfo(false) {} - - virtual void setSize(uint64_t size) = 0; - virtual void addReference(ObjectFile::Reference* ref) = 0; - virtual void sortReferences() = 0; - virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0; - virtual const ObjectFile::ReaderOptions& getOptions() const = 0; - virtual uint64_t getObjectAddress() const = 0; - virtual uint32_t getOrdinal() const { return fOrdinal; } - virtual void setOrdinal(uint32_t value) { fOrdinal = value; } - virtual const void* getSectionRecord() const = 0; - virtual unsigned int getSectionIndex() const = 0; - virtual bool isAlias() const { return false; } - virtual uint8_t getLSDAReferenceKind() const { return 0; } - virtual uint8_t getPersonalityReferenceKind() const { return 0; } - virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress) { return 0; } - virtual ObjectFile::UnwindInfo::iterator beginUnwind() { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[0] : NULL; } - virtual ObjectFile::UnwindInfo::iterator endUnwind() { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[1] : NULL; } - virtual ObjectFile::Reference* getLSDA(); - virtual ObjectFile::Reference* getFDE(); - virtual Atom* getPersonalityPointer(); - virtual void setCompactUnwindEncoding(uint64_t ehAtomAddress); - - uint32_t fStabsStartIndex; - uint32_t fStabsCount; - uint32_t fOrdinal; - ObjectFile::UnwindInfo fSingleUnwindInfo[1]; - bool fHasCompactUnwindInfo; -}; - - -ObjectFile::Reference* BaseAtom::getLSDA() -{ - const uint8_t groupKind = this->getLSDAReferenceKind(); - const std::vector& refs = this->getReferences(); - for (std::vector::const_iterator it=refs.begin(); it != refs.end(); it++) { - ObjectFile::Reference* ref = *it; - if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kLSDAType) ) { - return ref; - } - } - return NULL; -} - -ObjectFile::Reference* BaseAtom::getFDE() -{ - const uint8_t groupKind = this->getLSDAReferenceKind(); - const std::vector& refs = this->getReferences(); - for (std::vector::const_iterator it=refs.begin(); it != refs.end(); it++) { - ObjectFile::Reference* ref = *it; - if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kCFIType) ) { - return ref; - } - } - return NULL; -} - -ObjectFile::Atom* BaseAtom::getPersonalityPointer() -{ - const uint8_t personalityKind = this->getPersonalityReferenceKind(); - const std::vector& refs = this->getReferences(); - for (std::vector::const_iterator it=refs.begin(); it != refs.end(); it++) { - ObjectFile::Reference* ref = *it; - if ( ref->getKind() == personalityKind ) { - if ( strcmp(ref->getTarget().getSectionName(), "__nl_symbol_ptr") == 0 ) - return &ref->getTarget(); - if ( strcmp(ref->getTarget().getSectionName(), "__pointers") == 0 ) - return &ref->getTarget(); - } - } - return NULL; -} - - -void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - fSingleUnwindInfo[0].unwindInfo = this->getCompactUnwindEncoding(ehAtomAddress); - fHasCompactUnwindInfo = true; -} - - -class BaseAtomSorter -{ -public: - bool operator()(const class BaseAtom* left, const class BaseAtom* right) { - if ( left == right ) - return false; - uint64_t leftAddr = left->getObjectAddress(); - uint64_t rightAddr = right->getObjectAddress(); - if ( leftAddr < rightAddr ) { - return true; - } - else if ( leftAddr > rightAddr ) { - return false; - } - else { - // if they have same address, one might be the end of a section and the other the start of the next section - const void* leftSection = left->getSectionRecord(); - const void* rightSection = right->getSectionRecord(); - if ( leftSection != rightSection ) { - return ( leftSection < rightSection ); - } - // if they have same address and section, one might be an alias - bool leftAlias = left->isAlias(); - bool rightAlias = right->isAlias(); - if ( leftAlias && rightAlias ) { - // sort multiple aliases for same address first by scope - ObjectFile::Atom::Scope leftScope = left->getScope(); - ObjectFile::Atom::Scope rightScope = right->getScope(); - if ( leftScope != rightScope ) { - return ( leftScope < rightScope ); - } - // sort multiple aliases for same address then by name - return ( strcmp(left->getName(), right->getName()) < 0 ); - } - else if ( leftAlias ) { - return true; - } - else if ( rightAlias ) { - return false; - } - // one might be a section start or end label - switch ( left->getContentType() ) { - case ObjectFile::Atom::kSectionStart: - return true; - case ObjectFile::Atom::kSectionEnd: - return false; - default: - break; - } - switch ( right->getContentType() ) { - case ObjectFile::Atom::kSectionStart: - return false; - case ObjectFile::Atom::kSectionEnd: - return true; - default: - break; - } - // they could be tentative defintions - switch ( left->getDefinitionKind() ) { - case ObjectFile::Atom::kTentativeDefinition: - // sort tentative definitions by name - return ( strcmp(left->getName(), right->getName()) < 0 ); - case ObjectFile::Atom::kAbsoluteSymbol: - // sort absolute symbols with same address by name - return ( strcmp(left->getName(), right->getName()) < 0 ); - default: - // hack for rdar://problem/5102873 - if ( !left->isZeroFill() || !right->isZeroFill() ) - warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath()); - break; - } - } - return false; - } -}; - - -// -// A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry -// pointing to it. A C function or global variable is represented by one of these atoms. -// -// -template -class SymbolAtom : public BaseAtom -{ -public: - virtual ObjectFile::Reader* getFile() const { return &fOwner; } - virtual bool getTranslationUnitSource(const char** dir, const char** name) const - { return fOwner.getTranslationUnitSource(dir, name); } - virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; } - virtual const char* getDisplayName() const { return getName(); } - virtual ObjectFile::Atom::Scope getScope() const { return fScope; } - virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0) - ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; } - virtual ObjectFile::Atom::ContentType getContentType() const { return fType; } - virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; } - virtual bool dontDeadStrip() const; - virtual bool isZeroFill() const; - virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); } - virtual uint64_t getSize() const { return fSize; } - virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } - virtual bool mustRemainInSection() const { return true; } - virtual const char* getSectionName() const; - virtual Segment& getSegment() const { return *fSegment; } - virtual ObjectFile::Atom& getFollowOnAtom() const; - virtual std::vector* getLineInfo() const { return (std::vector*)&fLineInfo; } - virtual ObjectFile::Alignment getAlignment() const { return fAlignment; } - virtual void copyRawContent(uint8_t buffer[]) const; - virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } - virtual void setSize(uint64_t size); - virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } - virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } - virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); } - virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; } - virtual uint64_t getObjectAddress() const { return fAddress; } - virtual const void* getSectionRecord() const { return (const void*)fSection; } - virtual unsigned int getSectionIndex() const { return 1 + (fSection - fOwner.fSectionsStart); } - virtual uint8_t getLSDAReferenceKind() const; - virtual uint8_t getPersonalityReferenceKind() const; - virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress); - -protected: - typedef typename A::P P; - typedef typename A::P::E E; - typedef typename A::P::uint_t pint_t; - typedef typename A::ReferenceKinds Kinds; - typedef typename std::vector*> ReferenceVector; - typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser - typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser - friend class Reader; - - SymbolAtom(Reader&, const macho_nlist

*, const macho_section

*); - virtual ~SymbolAtom() {} - - Reader& fOwner; - const macho_nlist

* fSymbol; - pint_t fAddress; - pint_t fSize; - const macho_section

* fSection; - Segment* fSegment; - ReferenceVector fReferences; - std::vector fLineInfo; - ObjectFile::Atom::Scope fScope; - SymbolTableInclusion fSymbolTableInclusion; - ObjectFile::Atom::ContentType fType; - ObjectFile::Alignment fAlignment; -}; - - -template -SymbolAtom::SymbolAtom(Reader& owner, const macho_nlist

* symbol, const macho_section

* section) - : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fType(ObjectFile::Atom::kUnclassifiedType), fAlignment(0) -{ - fSingleUnwindInfo[0].startOffset = 0; - fSingleUnwindInfo[0].unwindInfo = 0; - uint8_t type = symbol->n_type(); - if ( (type & N_EXT) == 0 ) - fScope = ObjectFile::Atom::scopeTranslationUnit; - else if ( (type & N_PEXT) != 0 ) - fScope = ObjectFile::Atom::scopeLinkageUnit; - else - fScope = ObjectFile::Atom::scopeGlobal; - if ( (type & N_TYPE) == N_SECT ) { - // real definition - fSegment = new Segment(fSection); - fAddress = fSymbol->n_value(); - pint_t sectionStartAddr = section->addr(); - pint_t sectionEndAddr = section->addr()+section->size(); - if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) { - throwf("malformed .o file, symbol %s with address 0x%0llX is not with section %d (%s,%s) address range of 0x%0llX to 0x%0llX", - this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(), - (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) ); - } - } - else { - warning("unknown symbol type: %d", type); - } - - //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress); - // support for .o files built with old ld64 - if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) { - const char* name = this->getName(); - const int nameLen = strlen(name); - if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) { - // switch symbol to point at name that does not have trailing $stub - char correctName[nameLen]; - strncpy(correctName, name, nameLen-5); - correctName[nameLen-5] = '\0'; - const macho_nlist

* symbolsStart = fOwner.fSymbols; - const macho_nlist

* symbolsEnd = &symbolsStart[fOwner.fSymbolCount]; - for(const macho_nlist

* s = symbolsStart; s < symbolsEnd; ++s) { - if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) { - fSymbol = s; - break; - } - } - } - } - // support for labeled stubs - switch ( section->flags() & SECTION_TYPE ) { - case S_SYMBOL_STUBS: - setSize(section->reserved2()); - break; - case S_LAZY_SYMBOL_POINTERS: - case S_NON_LAZY_SYMBOL_POINTERS: - setSize(sizeof(pint_t)); - break; - case S_4BYTE_LITERALS: - setSize(4); - break; - case S_8BYTE_LITERALS: - setSize(8); - break; - case S_16BYTE_LITERALS: - setSize(16); - break; - case S_CSTRING_LITERALS: - setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1); - fType = ObjectFile::Atom::kCStringType; - break; - case S_REGULAR: - case S_ZEROFILL: - case S_COALESCED: - // size calculate later after next atom is found - break; - } - - // compute alignment - fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align())); - - // compute whether this atom needs to be in symbol table - if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) { - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip; - } - else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) { - // labels beginning with a lowercase ell are automatically removed in final linked images - // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable) - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn; - } - else { - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; - } - - // work around malformed icc generated .o files - // if section starts with a symbol and that symbol address does not match section alignment, then force it to - if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) ) - fAlignment.modulus = 0; -} - - -template -bool SymbolAtom::dontDeadStrip() const -{ - // the symbol can have a no-dead-strip bit - if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 ) - return true; - // or the section can have a no-dead-strip bit - return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP ); -} - - -template -const char* SymbolAtom::getSectionName() const -{ - if ( fOwner.fOptions.fForFinalLinkedImage ) { - if ( strcmp(fSection->sectname(), "__textcoal_nt") == 0 ) - return "__text"; - else if ( strcmp(fSection->sectname(), "__const_coal") == 0 ) - return "__const"; - else if ( strcmp(fSection->sectname(), "__datacoal_nt") == 0 ) - return "__data"; - else if ( fOwner.fOptions.fAutoOrderInitializers && (strcmp(fSection->sectname(), "__StaticInit") == 0) ) - return "__text"; - else { - switch ( fSection->flags() & SECTION_TYPE ) { - case S_4BYTE_LITERALS: - case S_8BYTE_LITERALS: - case S_16BYTE_LITERALS: - return "__const"; - } - } - } - - if ( strlen(fSection->sectname()) > 15 ) { - static char temp[18]; - strncpy(temp, fSection->sectname(), 16); - temp[17] = '\0'; - return temp; - } - return fSection->sectname(); -} - -template -ObjectFile::Atom& SymbolAtom::getFollowOnAtom() const -{ - for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) { - Reference* ref = *it; - if ( ref->getKind() == A::kFollowOn ) - return ref->getTarget(); - } - return *((ObjectFile::Atom*)NULL); -} - -template -bool SymbolAtom::isZeroFill() const -{ - return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill ); -} - - -class Beyond -{ -public: - Beyond(uint64_t offset) : fOffset(offset) {} - bool operator()(ObjectFile::Reference* ref) const { - return ( ref->getFixUpOffset() >= fOffset ); - } -private: - uint64_t fOffset; -}; - - -template -void SymbolAtom::setSize(uint64_t size) -{ - // when resizing, any references beyond the new size are tossed - if ( (fSize != 0) && (fReferences.size() > 0) ) - fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end()); - // set new size - fSize = size; -} - -template -void SymbolAtom::copyRawContent(uint8_t buffer[]) const -{ - // copy base bytes - if ( isZeroFill() ) - bzero(buffer, fSize); - else { - uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; - memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize); - } -} - - - - -// -// A SymbolAliasAtom represents an alternate name for a SymbolAtom -// -// -template -class SymbolAliasAtom : public BaseAtom -{ -public: - virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); } - virtual bool getTranslationUnitSource(const char** dir, const char** name) const - { return fAliasOf.getTranslationUnitSource(dir, name); } - virtual const char* getName() const { return fName; } - virtual const char* getDisplayName() const { return fName; } - virtual ObjectFile::Atom::Scope getScope() const { return fScope; } - virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); } - virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); } - virtual bool dontDeadStrip() const { return fDontDeadStrip; } - virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); } - virtual bool isThumb() const { return fAliasOf.isThumb(); } - virtual uint64_t getSize() const { return 0; } - virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } - virtual bool mustRemainInSection() const { return true; } - virtual const char* getSectionName() const { return fAliasOf.getSectionName(); } - virtual Segment& getSegment() const { return (Segment&)fAliasOf.getSegment(); } - virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; } - virtual std::vector* getLineInfo() const { return NULL; } - virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); } - virtual void copyRawContent(uint8_t buffer[]) const {} - virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } - virtual void setSize(uint64_t size) { } - virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } - virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } - virtual void addLineInfo(const ObjectFile::LineInfo& info) { } - virtual const ObjectFile::ReaderOptions& getOptions() const { return fAliasOf.getOptions(); } - virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); } - virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); } - virtual unsigned int getSectionIndex() const { return fAliasOf.getSectionIndex(); } - virtual bool isAlias() const { return true; } - -protected: - typedef typename A::P P; - typedef typename std::vector*> ReferenceVector; - typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser - typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser - friend class Reader; - - SymbolAliasAtom(const char* name, const macho_nlist

*, const BaseAtom& ); - virtual ~SymbolAliasAtom() {} - - const char* fName; - const BaseAtom& fAliasOf; - ObjectFile::Atom::Scope fScope; - bool fDontDeadStrip; - ReferenceVector fReferences; -}; - - -template -SymbolAliasAtom::SymbolAliasAtom(const char* name, const macho_nlist

* symbol, const BaseAtom& aliasOf) - : fName(name), fAliasOf(aliasOf) -{ - //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name); - if ( symbol != NULL ) { - uint8_t type = symbol->n_type(); - if ( (type & N_EXT) == 0 ) - fScope = ObjectFile::Atom::scopeTranslationUnit; - else if ( (type & N_PEXT) != 0 ) - fScope = ObjectFile::Atom::scopeLinkageUnit; - else - fScope = ObjectFile::Atom::scopeGlobal; - fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); - } - else { - // aliases defined on the command line are initially global scope - fScope = ObjectFile::Atom::scopeGlobal; - fDontDeadStrip = false; - } - // add follow-on reference to real atom - new Reference(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf)); -} - - -// -// A TentativeAtom represents a C "common" or "tentative" defintion of data. -// For instance, "int foo;" is neither a declaration or a definition and -// is represented by a TentativeAtom. -// -template -class TentativeAtom : public BaseAtom -{ -public: - virtual ObjectFile::Reader* getFile() const { return &fOwner; } - virtual bool getTranslationUnitSource(const char** dir, const char** name) const - { return fOwner.getTranslationUnitSource(dir, name); } - virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; } - virtual const char* getDisplayName() const { return getName(); } - virtual ObjectFile::Atom::Scope getScope() const { return fScope; } - virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; } - virtual bool isZeroFill() const { return fOwner.fOptions.fOptimizeZeroFill; } - virtual bool isThumb() const { return false; } - virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) - ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; } - virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); } - virtual uint64_t getSize() const { return fSymbol->n_value(); } - virtual std::vector& getReferences() const { return fgNoReferences; } - virtual bool mustRemainInSection() const { return true; } - virtual const char* getSectionName() const; - virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; } - virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; } - virtual std::vector* getLineInfo() const { return NULL; } - virtual ObjectFile::Alignment getAlignment() const; - virtual void copyRawContent(uint8_t buffer[]) const; - virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } - virtual void setSize(uint64_t size) { } - virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; } - virtual void sortReferences() { } - virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; } - virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; } - virtual uint64_t getObjectAddress() const { return ULLONG_MAX; } - virtual const void* getSectionRecord() const { return NULL; } - virtual unsigned int getSectionIndex() const { return 0; } - -protected: - typedef typename A::P P; - typedef typename A::P::E E; - typedef typename A::P::uint_t pint_t; - typedef typename A::ReferenceKinds Kinds; - friend class Reader; - - TentativeAtom(Reader&, const macho_nlist

*); - virtual ~TentativeAtom() {} - - Reader& fOwner; - const macho_nlist

* fSymbol; - ObjectFile::Atom::Scope fScope; - static std::vector fgNoReferences; -}; - -template -std::vector TentativeAtom::fgNoReferences; - -template -TentativeAtom::TentativeAtom(Reader& owner, const macho_nlist

* symbol) - : fOwner(owner), fSymbol(symbol) -{ - uint8_t type = symbol->n_type(); - if ( (type & N_EXT) == 0 ) - fScope = ObjectFile::Atom::scopeTranslationUnit; - else if ( (type & N_PEXT) != 0 ) - fScope = ObjectFile::Atom::scopeLinkageUnit; - else - fScope = ObjectFile::Atom::scopeGlobal; - if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) { - // tentative definition - } - else { - warning("unknown symbol type: %d", type); - } - //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName()); -} - - -template -ObjectFile::Alignment TentativeAtom::getAlignment() const -{ - uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc()); - if ( alignment == 0 ) { - // common symbols align to their size - // that is, a 4-byte common aligns to 4-bytes - // if this size is not a power of two, - // then round up to the next power of two - uint64_t size = this->getSize(); - alignment = 63 - (uint8_t)__builtin_clzll(size); - if ( size != (1ULL << alignment) ) - ++alignment; - } - // limit alignment of extremely large commons to 2^15 bytes (8-page) - if ( alignment < 12 ) - return ObjectFile::Alignment(alignment); - else - return ObjectFile::Alignment(12); -} - -template -const char* TentativeAtom::getSectionName() const -{ - if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal ) - return "__common"; - else - return "._tentdef"; -} - - -template -void TentativeAtom::copyRawContent(uint8_t buffer[]) const -{ - bzero(buffer, getSize()); -} - - -// -// An AnonymousAtom represents compiler generated data that has no name. -// For instance, a literal C-string or a 64-bit floating point constant -// is represented by an AnonymousAtom. -// -template -class AnonymousAtom : public BaseAtom -{ -public: - virtual ObjectFile::Reader* getFile() const { return &fOwner; } - virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; } - virtual const char* getName() const { return fSynthesizedName; } - virtual const char* getDisplayName() const; - virtual ObjectFile::Atom::Scope getScope() const; - virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; } - virtual ObjectFile::Atom::ContentType getContentType() const { return fType; } - virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; } - virtual bool dontDeadStrip() const { return fDontDeadStrip; } - virtual bool isZeroFill() const; - virtual bool isThumb() const { return false; } - virtual uint64_t getSize() const { return fSize; } - virtual std::vector& getReferences() const { return (std::vector&)(fReferences); } - virtual bool mustRemainInSection() const { return true; } - virtual const char* getSectionName() const; - virtual Segment& getSegment() const { return *fSegment; } - virtual ObjectFile::Atom& getFollowOnAtom() const; - virtual std::vector* getLineInfo() const { return NULL; } - virtual ObjectFile::Alignment getAlignment() const; - virtual void copyRawContent(uint8_t buffer[]) const; - virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } - virtual void setSize(uint64_t size) { fSize = size; } - virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference*)ref); } - virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); } - virtual void addLineInfo(const ObjectFile::LineInfo& info); - virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; } - virtual uint64_t getObjectAddress() const { return fAddress; } - virtual const void* getSectionRecord() const { return (const void*)fSection; } - virtual unsigned int getSectionIndex() const { return fSectionIndex; } - BaseAtom* redirectTo() { return fRedirect; } - bool isWeakImportStub() { return fWeakImportStub; } - void resolveName(); - virtual uint8_t getLSDAReferenceKind() const; - virtual uint8_t getPersonalityReferenceKind() const; - virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress); - -protected: - typedef typename A::P P; - typedef typename A::P::E E; - typedef typename A::P::uint_t pint_t; - typedef typename A::ReferenceKinds Kinds; - typedef typename std::vector*> ReferenceVector; - typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser - typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser - friend class Reader; - - AnonymousAtom(Reader&, const macho_section

*, pint_t addr, pint_t size); - virtual ~AnonymousAtom() {} - static bool cstringsHaveLabels(); - - Reader& fOwner; - const char* fSynthesizedName; - const char* fDisplayName; - const macho_section

* fSection; - pint_t fAddress; - pint_t fSize; - Segment* fSegment; - ReferenceVector fReferences; - BaseAtom* fRedirect; - bool fDontDeadStrip; - bool fWeakImportStub; - ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion; - ObjectFile::Atom::Scope fScope; - ObjectFile::Atom::DefinitionKind fKind; - ObjectFile::Atom::ContentType fType; - unsigned int fSectionIndex; -}; - -template -AnonymousAtom::AnonymousAtom(Reader& owner, const macho_section

* section, pint_t addr, pint_t size) - : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size), - fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn), - fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition), - fType(ObjectFile::Atom::kUnclassifiedType), fSectionIndex(1 + (section - owner.fSectionsStart)) -{ - fSegment = new Segment(fSection); - fRedirect = this; - uint8_t type = fSection->flags() & SECTION_TYPE; - //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath()); - switch ( type ) { - case S_ZEROFILL: - { - asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr); - } - break; - case S_COALESCED: - case S_REGULAR: - if ( section == owner.fehFrameSection ) { - if ( fSize == 1 ) { - // is CIE - fSize = 0; - fDontDeadStrip = false; - if ( fOwner.fOptions.fForFinalLinkedImage ) - fSynthesizedName = "CIE"; - else - fSynthesizedName = "EH_frame1"; - } - else { - // is FDE - fSynthesizedName = ".eh_PENDING"; - fDontDeadStrip = false; - owner.fAtomsPendingAName.push_back(this); - } - fType = ObjectFile::Atom::kCFIType; - // FDEs and CIEs don't need to be in symbol table of final linked images - if ( !fOwner.fOptions.fNoEHLabels ) - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; - } - else if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) { - // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only - fSynthesizedName = ".objc_class_name_PENDING"; - owner.fAtomsPendingAName.push_back(this); - owner.fSectionsWithAtomsPendingAName.insert(fSection); - if ( fOwner.fOptions.fForFinalLinkedImage ) - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; - else - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute; - fScope = ObjectFile::Atom::scopeGlobal; - } - else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) { - // handle .o files created by old ld64 -r that are missing cstring section type - const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr(); - asprintf((char**)&fSynthesizedName, "cstring=%s", str); - } - else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) { - fSynthesizedName = "cfstring-pointer-name-PENDING"; - fScope = ObjectFile::Atom::scopeLinkageUnit; - owner.fAtomsPendingAName.push_back(this); - owner.fSectionsWithAtomsPendingAName.insert(fSection); - fDontDeadStrip = false; - fKind = ObjectFile::Atom::kWeakDefinition; - } - else if ( (fSection->flags() & S_ATTR_SOME_INSTRUCTIONS) != 0 ) { - fDontDeadStrip = false; - asprintf((char**)&fSynthesizedName, "anon-func-0x%X", addr); - } - else if ( strncmp(fSection->sectname(), "__gcc_except_tab",16) == 0 ) { - fType = ObjectFile::Atom::kLSDAType; - fDontDeadStrip = false; - fSynthesizedName = ".lsda_PENDING"; - owner.fAtomsPendingAName.push_back(this); - if ( !fOwner.fOptions.fNoEHLabels ) - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; - } - else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) { - fSynthesizedName = "objc-class-pointer-name-PENDING"; - fScope = ObjectFile::Atom::scopeLinkageUnit; - owner.fAtomsPendingAName.push_back(this); - owner.fSectionsWithAtomsPendingAName.insert(fSection); - fKind = ObjectFile::Atom::kWeakDefinition; - } - else if ( section == owner.fUTF16Section ) { - if ( fOwner.fOptions.fForFinalLinkedImage ) { - fDontDeadStrip = false; - fScope = ObjectFile::Atom::scopeLinkageUnit; - fKind = ObjectFile::Atom::kWeakDefinition; - char* name = new char[16+5*size]; - strcpy(name, "utf16-string="); - char* s = &name[13]; - const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr()); - unsigned int wordCount = size/2; - bool needSeperator = false; - for(unsigned int i=0; i < wordCount; ++i) { - if ( needSeperator ) - strcpy(s++, "."); - sprintf(s, "%04X", E::get32(words[i])); - s += 4; - needSeperator = true; - } - fSynthesizedName = name; - } - else { - asprintf((char**)&fSynthesizedName, "lutf16-0x%X", addr); - } - } - break; - case S_CSTRING_LITERALS: - { - const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr(); - if ( (strcmp(fSection->sectname(), "__cstring") == 0) && (strcmp(section->segname(), "__TEXT") == 0) ) - asprintf((char**)&fSynthesizedName, "cstring=%s", str); - else - asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str); - fScope = ObjectFile::Atom::scopeLinkageUnit; - fKind = ObjectFile::Atom::kWeakDefinition; - fType = ObjectFile::Atom::kCStringType; - fDontDeadStrip = false; - if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() ) - fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn; - } - break; - case S_4BYTE_LITERALS: - { - uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); - asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value); - fScope = ObjectFile::Atom::scopeLinkageUnit; - fKind = ObjectFile::Atom::kWeakDefinition; - fDontDeadStrip = false; - } - break; - case S_8BYTE_LITERALS: - { - uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); - asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value); - fScope = ObjectFile::Atom::scopeLinkageUnit; - fKind = ObjectFile::Atom::kWeakDefinition; - fDontDeadStrip = false; - } - break; - case S_16BYTE_LITERALS: - { - uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); - uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr())); - asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2); - fScope = ObjectFile::Atom::scopeLinkageUnit; - fKind = ObjectFile::Atom::kWeakDefinition; - fDontDeadStrip = false; - } - break; - case S_LITERAL_POINTERS: - { - //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr())); - //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr(); - //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str); - fSynthesizedName = "literal-pointer-name-PENDING"; - fScope = ObjectFile::Atom::scopeLinkageUnit; - fKind = ObjectFile::Atom::kWeakDefinition; - fDontDeadStrip = false; - owner.fAtomsPendingAName.push_back(this); - owner.fSectionsWithAtomsPendingAName.insert(fSection); - } - break; - case S_MOD_INIT_FUNC_POINTERS: - asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t)); - break; - case S_MOD_TERM_FUNC_POINTERS: - asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t)); - break; - case S_SYMBOL_STUBS: - { - uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2(); - index += fSection->reserved1(); - uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]); - const macho_nlist

* sym = &fOwner.fSymbols[symbolIndex]; - uint32_t strOffset = sym->n_strx(); - // want name to not have $stub suffix, this is what automatic stub generation expects - fSynthesizedName = &fOwner.fStrings[strOffset]; - // check for weak import - fWeakImportStub = fOwner.isWeakImportSymbol(sym); - // sometimes the compiler gets confused and generates a stub to a static function - // if so, we should redirect any call to the stub to be calls to the real static function atom - if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) { - BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName); - if ( staticAtom != NULL ) - fRedirect = staticAtom; - } - fKind = ObjectFile::Atom::kWeakDefinition; - // might be a spurious stub for a static function, make stub static too - if ( (sym->n_type() & N_EXT) == 0 ) - fScope = ObjectFile::Atom::scopeTranslationUnit; - else - fScope = ObjectFile::Atom::scopeLinkageUnit; - } - break; - case S_LAZY_SYMBOL_POINTERS: - case S_NON_LAZY_SYMBOL_POINTERS: - { - // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when - // generating the new compressed LINKEDIT format - if ( (type == S_NON_LAZY_SYMBOL_POINTERS) && fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) { - macho_section

* dummySection = new macho_section

(*fSection); - dummySection->set_segname("__DATA"); - dummySection->set_sectname("__nl_symbol_ptr"); - fSection = dummySection; - fSegment = new Segment(fSection); - } - - fDontDeadStrip = false; - fScope = ObjectFile::Atom::scopeLinkageUnit; - uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t); - index += fSection->reserved1(); - uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]); - if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) { - // Silly codegen with non-lazy pointer to a local symbol - uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; - pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset))); - // All atoms not created yet, so we need to scan symbol table - const macho_nlist

* closestSym = NULL; - const macho_nlist

* end = &fOwner.fSymbols[fOwner.fSymbolCount]; - for (const macho_nlist

* sym = fOwner.fSymbols; sym < end; ++sym) { - if ( ((sym->n_type() & N_TYPE) == N_SECT) - && ((sym->n_type() & N_STAB) == 0) ) { - if ( sym->n_value() == nonLazyPtrValue ) { - const char* name = &fOwner.fStrings[sym->n_strx()]; - char* str = new char[strlen(name)+16]; - strcpy(str, name); - strcat(str, "$non_lazy_ptr"); - fSynthesizedName = str; - // add direct reference to target later, because its atom may not be constructed yet - fOwner.fLocalNonLazys.push_back(this); - fScope = ObjectFile::Atom::scopeTranslationUnit; - fType = ObjectFile::Atom::kNonLazyPointer; - return; - } - else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) { - closestSym = sym; - } - } - } - // add direct reference to target later, because its atom may not be constructed yet - if ( closestSym != NULL ) { - const char* name = &fOwner.fStrings[closestSym->n_strx()]; - char* str; - asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value()); - fSynthesizedName = str; - } - else { - fSynthesizedName = "$interior$non_lazy_ptr"; - } - fScope = ObjectFile::Atom::scopeTranslationUnit; - fOwner.fLocalNonLazys.push_back(this); - fType = ObjectFile::Atom::kNonLazyPointer; - return; - } - const macho_nlist

* targetSymbol = &fOwner.fSymbols[symbolIndex]; - const char* name = &fOwner.fStrings[targetSymbol->n_strx()]; - char* str = new char[strlen(name)+16]; - strcpy(str, name); - if ( type == S_LAZY_SYMBOL_POINTERS ) { - strcat(str, "$lazy_ptr"); - fType = ObjectFile::Atom::kLazyPointer; - } - else { - strcat(str, "$non_lazy_ptr"); - fType = ObjectFile::Atom::kNonLazyPointer; - } - fSynthesizedName = str; - - if ( type == S_NON_LAZY_SYMBOL_POINTERS ) - fKind = ObjectFile::Atom::kWeakDefinition; - - if ( (targetSymbol->n_type() & N_EXT) == 0 ) { - // target is translation unit scoped, so add direct reference to target - //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value()); - new Reference(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value())); - } - else { - if ( fOwner.isWeakImportSymbol(targetSymbol) ) - new Reference(A::kPointerWeakImport, AtomAndOffset(this), name, 0); - else - new Reference(A::kPointer, AtomAndOffset(this), name, 0); - } - } - break; - default: - throwf("section type %d not supported with address=0x%08llX", type, (uint64_t)addr); - } - //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName()); -} - -// x86_64 uses L labels on cstrings to allow relocs with addends -template <> bool AnonymousAtom::cstringsHaveLabels() { return true; } -template bool AnonymousAtom::cstringsHaveLabels() { return false; } - -template -void AnonymousAtom::addLineInfo(const ObjectFile::LineInfo& info) -{ - // don't warn if line table has entries for stubs - if ( (fSection->flags() & SECTION_TYPE) != S_SYMBOL_STUBS ) - warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); -} - -template -void AnonymousAtom::resolveName() -{ - if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) { - std::vector& references = this->getReferences(); - // references are not yet sorted, so scan the vector - for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { - if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) { - const char* superStr = (*rit)->getTargetName(); - if ( strncmp(superStr, "cstring", 7) == 0 ) { - const char* superClassName; - asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]); - new Reference(A::kNoFixUp, AtomAndOffset(this), superClassName, 0); - } - break; - } - } - for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { - if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) { - const char* classStr = (*rit)->getTargetName(); - if ( strncmp(classStr, "cstring", 7) == 0 ) { - asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]); - } - break; - } - } - } - else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) { - std::vector& references = this->getReferences(); - if ( references.size() < 1 ) - throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname()); - ObjectFile::Reference* ref = references[0]; - const char* str = ref->getTargetName(); - if ( strncmp(str, "cstring", 7) == 0 ) { - asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]); - } - } - else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) { - // references are not yet sorted, so scan the vector - std::vector& references = this->getReferences(); - for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { - if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) { - const char* superStr = (*rit)->getTargetName(); - if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) { - asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]); - } - else if ( (superStr != NULL) && (strncmp(superStr, "utf16-string=", 13) == 0) ) { - asprintf((char**)&fSynthesizedName, "cfstring-utf16=%s", &superStr[13]); - } - else { - // compiled with -fwritable-strings or a non-ASCII string - fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable - fScope = ObjectFile::Atom::scopeTranslationUnit; - fSynthesizedName = "cfstring-not-coalesable"; - if ( (*rit)->getTargetOffset() != 0 ) - warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner.getPath()); - } - break; - } - } - } - else if ( fSection == fOwner.fehFrameSection ) { - // give name to FDE - ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromFDEAddress(fAddress); - if ( funcAtom != NULL ) - asprintf((char**)&fSynthesizedName, "%s.eh", funcAtom->getDisplayName()); - } - else if ( fOwner.fLSDAAtoms.count(this) != 0) { - // give name to LSDA - ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromLSDAAddress(fAddress); - if ( funcAtom != NULL ) - asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName()); - } - else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) { - std::vector& references = this->getReferences(); - if ( references.size() != 1 ) - throwf("__objc_classrefs element missing reloc (count=%ld) for target class in %s", references.size(), fOwner.getPath()); - const char* targetName = references[0]->getTargetName(); - if ( strncmp(targetName, "_OBJC_CLASS_$_", 14) == 0 ) - asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", &targetName[14]); - else - asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", targetName); - } -} - - -template -const char* AnonymousAtom::getDisplayName() const -{ - if ( fSynthesizedName != NULL ) - return fSynthesizedName; - - if ( fDisplayName != NULL ) - return fDisplayName; - - if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) { - uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; - asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset); - } - else { - asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() ); - } - return fDisplayName; -} - - -template -ObjectFile::Atom::Scope AnonymousAtom::getScope() const -{ - return fScope; -} - - -template -bool AnonymousAtom::isZeroFill() const -{ - return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill ); -} - - -template -const char* AnonymousAtom::getSectionName() const -{ - if ( fOwner.fOptions.fForFinalLinkedImage ) { - switch ( fSection->flags() & SECTION_TYPE ) { - case S_4BYTE_LITERALS: - case S_8BYTE_LITERALS: - case S_16BYTE_LITERALS: - return "__const"; - } - } - - if ( strlen(fSection->sectname()) > 15 ) { - static char temp[18]; - strncpy(temp, fSection->sectname(), 16); - temp[17] = '\0'; - return temp; - } - return fSection->sectname(); -} - -template -ObjectFile::Alignment AnonymousAtom::getAlignment() const -{ - // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment - if ( fType == ObjectFile::Atom::kCFIType ) - return ObjectFile::Alignment(0); - - switch ( fSection->flags() & SECTION_TYPE ) { - case S_4BYTE_LITERALS: - return ObjectFile::Alignment(2); - case S_8BYTE_LITERALS: - return ObjectFile::Alignment(3); - case S_16BYTE_LITERALS: - return ObjectFile::Alignment(4); - case S_NON_LAZY_SYMBOL_POINTERS: - return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t))); - case S_CSTRING_LITERALS: - if ( ! fOwner.fOptions.fForFinalLinkedImage ) - return ObjectFile::Alignment(fSection->align()); - default: - return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align())); - } -} - - -template -ObjectFile::Atom& AnonymousAtom::getFollowOnAtom() const -{ - for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) { - Reference* ref = *it; - if ( ref->getKind() == A::kFollowOn ) - return ref->getTarget(); - } - return *((ObjectFile::Atom*)NULL); -} - -template -void AnonymousAtom::copyRawContent(uint8_t buffer[]) const -{ - // copy base bytes - if ( isZeroFill() ) - bzero(buffer, fSize); - else { - uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress; - memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize); - } -} - -// -// An AbsoluteAtom represents an N_ABS symbol which can only be created in -// assembly language and usable by static executables such as the kernel/ -// -template -class AbsoluteAtom : public BaseAtom -{ -public: - virtual ObjectFile::Reader* getFile() const { return &fOwner; } - virtual bool getTranslationUnitSource(const char** dir, const char** name) const - { return fOwner.getTranslationUnitSource(dir, name); } - virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; } - virtual const char* getDisplayName() const { return getName(); } - virtual ObjectFile::Atom::Scope getScope() const { return fScope; } - virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; } - virtual bool isZeroFill() const { return false; } - virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); } - virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; } - virtual bool dontDeadStrip() const { return false; } - virtual uint64_t getSize() const { return 0; } - virtual std::vector& getReferences() const { return fgNoReferences; } - virtual bool mustRemainInSection() const { return true; } - virtual const char* getSectionName() const { return "._absolute"; } - virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; } - virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; } - virtual std::vector* getLineInfo() const { return NULL; } - virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } - virtual void copyRawContent(uint8_t buffer[]) const { } - virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; } - virtual void setSize(uint64_t size) { } - virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; } - virtual void sortReferences() { } - virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; } - virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; } - virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); } - virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ } - virtual const void* getSectionRecord() const { return NULL; } - virtual unsigned int getSectionIndex() const { return 0; } - -protected: - typedef typename A::P P; - typedef typename A::P::E E; - typedef typename A::P::uint_t pint_t; - typedef typename A::ReferenceKinds Kinds; - friend class Reader; - - AbsoluteAtom(Reader&, const macho_nlist

*); - virtual ~AbsoluteAtom() {} - - Reader& fOwner; - const macho_nlist

* fSymbol; - ObjectFile::Atom::Scope fScope; - static std::vector fgNoReferences; -}; - -template -std::vector AbsoluteAtom::fgNoReferences; - -template -AbsoluteAtom::AbsoluteAtom(Reader& owner, const macho_nlist

* symbol) - : fOwner(owner), fSymbol(symbol) -{ - // store absolute adress in fSectionOffset - fSectionOffset = symbol->n_value(); - // compute scope - uint8_t type = symbol->n_type(); - if ( (type & N_EXT) == 0 ) - fScope = ObjectFile::Atom::scopeTranslationUnit; - else if ( (type & N_PEXT) != 0 ) - fScope = ObjectFile::Atom::scopeLinkageUnit; - else - fScope = ObjectFile::Atom::scopeGlobal; - //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName()); -} - - -// -// An SectionBoundaryAtom represent the start or end of a section -// -template -class SectionBoundaryAtom : public BaseAtom -{ -public: - virtual ObjectFile::Reader* getFile() const { return &fOwner; } - virtual bool getTranslationUnitSource(const char** dir, const char** name) const - { return fOwner.getTranslationUnitSource(dir, name); } - virtual const char* getName() const { return fSymbolName; } - virtual const char* getDisplayName() const { return fDisplayName; } - virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } - virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition; } - virtual ObjectFile::Atom::ContentType getContentType() const { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; } - virtual bool isZeroFill() const { return fZeroFill; } - virtual bool isThumb() const { return false; } - virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; } - virtual bool dontDeadStrip() const { return false; } - virtual uint64_t getSize() const { return 0; } - virtual std::vector& getReferences() const { return fgNoReferences; } - virtual bool mustRemainInSection() const { return true; } - virtual const char* getSectionName() const { return fSectionName; } - virtual ObjectFile::Segment& getSegment() const { return *fSegment; } - virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; } - virtual std::vector* getLineInfo() const { return NULL; } - virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } - virtual void copyRawContent(uint8_t buffer[]) const { } - virtual void setScope(ObjectFile::Atom::Scope newScope) { } - virtual void setSize(uint64_t size) { } - virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; } - virtual void sortReferences() { } - virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; } - virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; } - virtual uint64_t getObjectAddress() const { return 0; } - virtual const void* getSectionRecord() const { return NULL; } - virtual unsigned int getSectionIndex() const { return 0; } - -protected: - typedef typename A::P P; - typedef typename A::P::E E; - typedef typename A::P::uint_t pint_t; - typedef typename A::ReferenceKinds Kinds; - friend class Reader; - - - class Segment : public ObjectFile::Segment - { - public: - Segment(const char* name, bool r, bool w, bool x): - fName(name), fReadable(r), fWritable(w), fExecutable(x) {} - - virtual const char* getName() const { return fName; } - virtual bool isContentReadable() const { return fReadable; } - virtual bool isContentWritable() const { return fWritable; } - virtual bool isContentExecutable() const { return fExecutable; } - private: - const char* fName; - bool fReadable; - bool fWritable; - bool fExecutable; - }; - - SectionBoundaryAtom(Reader&, bool start, const char* symbolName, const char* segSectName); - virtual ~SectionBoundaryAtom() {} - - Reader& fOwner; - class Segment* fSegment; - const char* fSymbolName; - const char* fSectionName; - const char* fDisplayName; - bool fStart; - bool fZeroFill; - static std::vector fgNoReferences; -}; - -template -std::vector SectionBoundaryAtom::fgNoReferences; - -// examples: -// section$start$__DATA$__my -// section$end$__DATA$__my -template -SectionBoundaryAtom::SectionBoundaryAtom(Reader& owner, bool start, const char* symbolName, const char* segSectName) - : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start), fZeroFill(false) -{ - const char* segSectDividor = strrchr(segSectName, '$'); - if ( segSectDividor == NULL ) - throwf("malformed section reference name: %s", symbolName); - fSectionName = segSectDividor + 1; - int segNameLen = segSectDividor - segSectName; - if ( segNameLen > 16 ) - throwf("malformed section reference name: %s", symbolName); - char segName[18]; - strlcpy(segName, segSectName, segNameLen+1); - if ( strcmp(segName, "__TEXT") == 0 ) - fSegment = new Segment("__TEXT", true, false, true); - else if ( strcmp(segName, "__DATA") == 0 ) { - fSegment = new Segment("__DATA", true, true, false); - if ( (strcmp(fSectionName, "__bss") == 0) || (strcmp(fSectionName, "__common") == 0) ) - fZeroFill = true; - } - else - fSegment = new Segment(strdup(segName), true, true, false); - - asprintf((char**)&fDisplayName, "%s of section '%s' in segment '%s'", (start ? "start" : "end"), fSectionName, segName); -} - - - -/// -/// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing -/// dwarf CFI information in an object file. -/// -template -class ObjectFileAddressSpace -{ -public: - ObjectFileAddressSpace(Reader& reader); - - typedef typename A::P::uint_t pint_t; - typedef typename A::P P; - typedef typename A::P::uint_t sint_t; - - uint8_t get8(pint_t addr); - uint16_t get16(pint_t addr); - uint32_t get32(pint_t addr); - uint64_t get64(pint_t addr); - pint_t getP(pint_t addr); - uint64_t getULEB128(pint_t& addr, pint_t end); - int64_t getSLEB128(pint_t& addr, pint_t end); - pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding); -private: - const void* mappedAddress(pint_t addr, pint_t* relocTarget=NULL); - pint_t relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount); - void buildRelocatedMap(const macho_section

* sect, std::map& map); - - Reader& fReader; - const uint8_t* fMappingStart; - const macho_section

* fSectionsStart; - const macho_section

* fSectionsEnd; - std::map fEHFrameOffsetToTargetMap; -}; - - -template -ObjectFileAddressSpace::ObjectFileAddressSpace(Reader& reader) - : fReader(reader), fMappingStart(NULL), fSectionsStart(NULL), fSectionsEnd(NULL) -{ -} - - - -template -const void* ObjectFileAddressSpace::mappedAddress(pint_t addr, pint_t* relocTarget) -{ - if ( fMappingStart == NULL ) { - // delay initialization until now when fReader.fSegment is set up - fMappingStart = (uint8_t*)fReader.fHeader; - fSectionsStart = (macho_section

*)((char*)fReader.fSegment + sizeof(macho_segment_command

)); - fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()]; - // find __eh_frame section and build map of relocations for performance - buildRelocatedMap(fReader.fehFrameSection, fEHFrameOffsetToTargetMap); - } - // special case lookups in __eh_frame section to be fast - const macho_section

* ehSect = fReader.fehFrameSection; - if ( (ehSect->addr() <= addr) && (addr < (ehSect->addr()+ehSect->size())) ) { - pint_t offsetOfAddrInSection = addr - ehSect->addr(); - if ( relocTarget != NULL ) { - std::map::iterator pos = fEHFrameOffsetToTargetMap.find(offsetOfAddrInSection); - if ( pos != fEHFrameOffsetToTargetMap.end() ) - *relocTarget = pos->second; - else - *relocTarget = 0; - } - return fMappingStart + ehSect->offset() + offsetOfAddrInSection; - } - else { - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) { - pint_t offsetOfAddrInSection = addr - sect->addr(); - if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) { - const uint32_t indirectTableOffset = sect->reserved1(); - const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t); - const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]); - // return pointer to symbol name which this non-lazy-pointer will point to - if ( relocTarget != NULL ) - *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()]; - } - else { - if ( relocTarget != NULL ) - *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc()); - } - return fMappingStart + sect->offset() + offsetOfAddrInSection; - } - } - throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr); - } -} - - - - -template -uint8_t ObjectFileAddressSpace::get8(pint_t logicalAddr) -{ - return *((uint8_t*)mappedAddress(logicalAddr)); -} - -template -uint16_t ObjectFileAddressSpace::get16(pint_t logicalAddr) -{ - return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr))); -} - -template -uint32_t ObjectFileAddressSpace::get32(pint_t logicalAddr) -{ - pint_t relocTarget; - return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget; -} - -template -uint64_t ObjectFileAddressSpace::get64(pint_t logicalAddr) -{ - pint_t relocTarget; - return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget; -} - -template -typename A::P::uint_t ObjectFileAddressSpace::getP(pint_t logicalAddr) -{ - pint_t relocTarget; - return P::getP(*((pint_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget; -} - -template -uint64_t ObjectFileAddressSpace::getULEB128(pint_t& logicalAddr, pint_t end) -{ - uintptr_t size = (end - logicalAddr); - libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr); - libunwind::LocalAddressSpace::pint_t sladdr = laddr; - uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size); - logicalAddr += (laddr-sladdr); - return result; -} - -template -int64_t ObjectFileAddressSpace::getSLEB128(pint_t& logicalAddr, pint_t end) -{ - uintptr_t size = (end - logicalAddr); - libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr); - libunwind::LocalAddressSpace::pint_t sladdr = laddr; - int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size); - logicalAddr += (laddr-sladdr); - return result; -} - - - - - - -template -class Reader : public ObjectFile::Reader -{ -public: - static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0); - static const char* fileKind(const uint8_t* fileContent); - Reader(const uint8_t* fileContent, const char* path, time_t modTime, - const ObjectFile::ReaderOptions& options, uint32_t ordinalBase); - virtual ~Reader() {} - - virtual const char* getPath() { return fPath; } - virtual time_t getModificationTime() { return fModTime; } - virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; } - virtual std::vector& getAtoms() { return (std::vector&)(fAtoms); } - virtual std::vector* getJustInTimeAtomsFor(const char* name) { return NULL; } - virtual std::vector* getStabs() { return &fStabs; } - virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; } - virtual uint32_t updateCpuConstraint(uint32_t current); - virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); } - virtual bool objcReplacementClasses(){ return fReplacementClasses; } - virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; } - - bool getTranslationUnitSource(const char** dir, const char** name) const; - -private: - typedef typename A::P P; - typedef typename A::P::E E; - typedef typename A::P::uint_t pint_t; - //typedef typename std::vector*> AtomVector; - //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser - typedef typename A::ReferenceKinds Kinds; - typedef typename libunwind::CFI_Parser >::FDE_Atom_Info FDE_Atom_Info; - typedef typename libunwind::CFI_Parser >::CIE_Atom_Info CIE_Atom_Info; - typedef class ObjectFileAddressSpace OAS; - friend class ObjectFileAddressSpace; - friend class AnonymousAtom; - friend class TentativeAtom; - friend class AbsoluteAtom; - friend class SectionBoundaryAtom; - friend class SymbolAtom; - typedef std::map AddrToAtomMap; - - void addReferencesForSection(const macho_section

* sect); - bool addRelocReference(const macho_section

* sect, const macho_relocation_info

* reloc); - bool addRelocReference_powerpc(const macho_section

* sect, const macho_relocation_info

* reloc); - const char* getDwarfString(uint64_t form, const uint8_t* p); - bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list); - static bool isWeakImportSymbol(const macho_nlist

* sym); - static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64); - static const char* assureFullPath(const char* path); - AtomAndOffset findAtomAndOffset(pint_t addr); - AtomAndOffset findAtomAndOffsetForSection(pint_t addr, unsigned int sectionIndex); - AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr); - Reference* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr); - Reference* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr); - Reference* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr); - Reference* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr); - Reference* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset); - BaseAtom* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section

* ehSect); - Reference* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist

* toSymbol, pint_t toOffset); - void validSectionType(uint8_t type); - void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName); - void setCpuConstraint(uint32_t cpusubtype); - const macho_section

* getSectionForAddress(pint_t); - ObjectFile::Atom* getFunctionAtomFromFDEAddress(pint_t); - ObjectFile::Atom* getFunctionAtomFromLSDAAddress(pint_t); - void addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target); - void addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding); - bool isSectDiffReloc(uint8_t r_type); - - - BaseAtom* findAtomByName(const char*); - - const char* fPath; - time_t fModTime; - uint32_t fOrdinalBase; - const ObjectFile::ReaderOptions& fOptions; - const macho_header

* fHeader; - const char* fStrings; - const macho_nlist

* fSymbols; - uint32_t fSymbolCount; - const macho_segment_command

* fSegment; - const uint32_t* fIndirectTable; - std::vector fAtoms; - AddrToAtomMap fAddrToAtom; - AddrToAtomMap fAddrToAbsoluteAtom; - std::vector*> fLocalNonLazys; - std::vector*> fAtomsPendingAName; - std::set*> fSectionsWithAtomsPendingAName; - std::vector fDtraceProviderInfo; - ObjectFile::Reader::DebugInfoKind fDebugInfo; - bool fHasUUID; - const macho_section

* fehFrameSection; - const macho_section

* fUTF16Section; - std::set fLSDAAtoms; - const macho_section

* fDwarfDebugInfoSect; - const macho_section

* fDwarfDebugAbbrevSect; - const macho_section

* fDwarfDebugLineSect; - const macho_section

* fDwarfDebugStringSect; - const char* fDwarfTranslationUnitDir; - const char* fDwarfTranslationUnitFile; - std::map fDwarfIndexToFile; - std::vector fStabs; - std::vector fFDEInfos; - std::vector fCIEInfos; - bool fAppleObjc; - bool fHasDTraceProbes; - bool fHaveIndirectSymbols; - bool fReplacementClasses; - bool fHasLongBranchStubs; - ObjectFile::Reader::ObjcConstraint fObjConstraint; - uint32_t fCpuConstraint; - const macho_section

* fSectionsStart; - const macho_section

* fSectionsEnd; - OAS fObjectAddressSpace; -}; - -template -Reader::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase) - : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header

*)fileContent), - fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL), - fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), fUTF16Section(NULL), - fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL), - fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false), - fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false), - fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny), - fSectionsStart(NULL), fSectionsEnd(NULL), fObjectAddressSpace(*this) -{ - // sanity check - if ( ! validFile(fileContent, false, 0) ) - throw "not a valid mach-o object file"; - - Reference::fgForFinalLinkedImage = options.fForFinalLinkedImage; - - // write out path for -t or -whatsloaded option - if ( options.fLogObjectFiles || options.fLogAllFiles ) - printf("%s\n", path); - - // cache intersting pointers - const macho_header

* header = (const macho_header

*)fileContent; - this->setCpuConstraint(header->cpusubtype()); - const uint32_t cmd_count = header->ncmds(); - const macho_load_command

* const cmds = (macho_load_command

*)((char*)header + sizeof(macho_header

)); - const macho_load_command

* const cmdsEnd = (macho_load_command

*)((char*)header + sizeof(macho_header

) + header->sizeofcmds()); - const macho_load_command

* cmd = cmds; - uint32_t undefinedStartIndex = 0; - uint32_t undefinedEndIndex = 0; - for (uint32_t i = 0; i < cmd_count; ++i) { - switch (cmd->cmd()) { - case LC_SYMTAB: - { - const macho_symtab_command

* symtab = (macho_symtab_command

*)cmd; - fSymbolCount = symtab->nsyms(); - fSymbols = (const macho_nlist

*)((char*)header + symtab->symoff()); - fStrings = (char*)header + symtab->stroff(); - if ( undefinedEndIndex == 0 ) { - undefinedStartIndex = 0; - undefinedEndIndex = symtab->nsyms(); - } - } - break; - case LC_DYSYMTAB: - { - const macho_dysymtab_command

* dsymtab = (struct macho_dysymtab_command

*)cmd; - fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff()); - undefinedStartIndex = dsymtab->iundefsym(); - undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym(); - } - break; - case LC_UUID: - fHasUUID = true; - break; - - default: - if ( cmd->cmd() == macho_segment_command

::CMD ) { - fSegment = (macho_segment_command

*)cmd; - } - break; - } - cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); - if ( cmd > cmdsEnd ) - throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path); - } - - // if there are no load commands, then this file has no content, so no atoms - if ( header->ncmds() < 1 ) - return; - - fSectionsStart = (macho_section

*)((char*)fSegment + sizeof(macho_segment_command

)); - fSectionsEnd = &fSectionsStart[fSegment->nsects()]; - - // inital guess for number of atoms - fAtoms.reserve(fSymbolCount); - - // if there is an __eh_frame section, decode it into chunks to get atoms in that - // section as well as division points for functions in __text - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) { - fehFrameSection = sect; - const char* msg = libunwind::CFI_Parser >::getCFIs(fObjectAddressSpace, sect->addr(), - sect->size(), fFDEInfos, fCIEInfos); - if ( msg != NULL ) { - throwf("malformed __eh_frame section: %s", msg); - } - else { - //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size()); - // add anonymous atoms for each CIE - for (typename std::vector::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) { - AnonymousAtom* cieAtom = new AnonymousAtom(*this, sect, it->cieAddress, 1); - fAtoms.push_back(cieAtom); - fAddrToAtom[it->cieAddress] = cieAtom; - } - // add anonymous atoms for each FDE and LSDA - for (typename std::vector::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) { - //fprintf(stderr, "fdeAddress=0x%08llX, lsdaAddr=0x%08llX, funcAddr=0x%08llX\n", (uint64_t)it->fdeAddress, (uint64_t)it->lsda.address, (uint64_t)it->function.address); - AnonymousAtom* fdeAtom = new AnonymousAtom(*this, sect, it->fdeAddress, 0); - fAtoms.push_back(fdeAtom); - fAddrToAtom[it->fdeAddress] = fdeAtom; - if ( it->lsda.address != 0 ) { - AnonymousAtom* lsdaAtom = new AnonymousAtom(*this, getSectionForAddress(it->lsda.address), it->lsda.address, 0); - fAtoms.push_back(lsdaAtom); - fAddrToAtom[it->lsda.address] = lsdaAtom; - fLSDAAtoms.insert(lsdaAtom); - } - } - } - } - else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) && (sect->size() != 0) ) { - // if there is a __ustring section parse it into atoms - fUTF16Section = sect; - // first find all cleave points - const uint16_t* words = (uint16_t*)((char*)(fHeader) + fUTF16Section->offset()); - unsigned int wordCount = fUTF16Section->size()/2; - std::vector utf16Addreses; - bool inString = false; - for (unsigned int i=0; i < wordCount; ++i) { - if ( inString ) { - if ( words[i] == 0x0000 ) { - inString = false; - } - } - else { - if ( words[i] == 0x0000 ) { - // skip over zero padding - } - else { - inString = true; - utf16Addreses.push_back(fUTF16Section->addr() + i*2); - } - } - } - utf16Addreses.push_back(fUTF16Section->addr() + sect->size()); - // build map of symbols - std::map* > symbolMap; - for (int i=fSymbolCount-1; i >= 0 ; --i) { - const macho_nlist

& sym = fSymbols[i]; - if ( (sym.n_type() & N_STAB) == 0 ) { - uint8_t type = (sym.n_type() & N_TYPE); - if ( type == N_SECT ) { - if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) { - // rdar://problem/7429384 don't coalesce UTF16 strings unless label starts with ___utf16_string - if ( strncmp(&fStrings[sym.n_strx()], "___utf16_string", 15) != 0 ) { - symbolMap[sym.n_value()] = &sym; - // if this symbol is a string of just 0x0000, it may not be in utf16Addreses - if ( words[(sym.n_value() - sect->addr())/2] == 0x0000 ) { - for(typename std::vector::iterator sit=utf16Addreses.begin(); sit != utf16Addreses.end(); ++sit) { - if ( *sit == sym.n_value() ) { - // already in utf16Addreses - break; - } - if ( *sit > sym.n_value() ) { - // need to insert - utf16Addreses.insert(sit, sym.n_value()); - break; - } - } - } - } - } - } - } - } - // make atom for each string - for(int i=utf16Addreses.size()-2; i >=0 ; --i) { - pint_t size = utf16Addreses[i+1] - utf16Addreses[i]; - typename std::map* >::iterator pos = symbolMap.find(utf16Addreses[i]); - if ( pos == symbolMap.end() ) { - AnonymousAtom* strAtom = new AnonymousAtom(*this, fUTF16Section, utf16Addreses[i], size); - fAtoms.push_back(strAtom); - fAddrToAtom[utf16Addreses[i]] = strAtom; - } - else { - SymbolAtom* newAtom = new SymbolAtom(*this, pos->second, fUTF16Section); - fAtoms.push_back(newAtom); - fAddrToAtom[utf16Addreses[i]] = newAtom; - newAtom->setSize(size); - } - } - } - } - - - // add all atoms that have entries in symbol table - BaseAtom* sectionEndAtoms[fSegment->nsects()]; - for (unsigned int i=0; i < fSegment->nsects(); ++i) - sectionEndAtoms[i] = NULL; - for (int i=fSymbolCount-1; i >= 0 ; --i) { - // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name - const macho_nlist

& sym = fSymbols[i]; - if ( (sym.n_type() & N_STAB) == 0 ) { - uint8_t type = (sym.n_type() & N_TYPE); - if ( type == N_SECT ) { - const macho_section

* section = &fSectionsStart[sym.n_sect()-1]; - const pint_t sectionStartAddr = section->addr(); - const pint_t sectionEndAddr = sectionStartAddr + section->size(); - bool suppress = false; - // ignore atoms in debugger sections - if ( (section->flags() & S_ATTR_DEBUG) == 0 ) { - if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) { - // ignore dtrace probe labels - fHasDTraceProbes = true; - } - else if ( fStrings[sym.n_strx()] == 'L' ) { - // ignore L labels, - } - else if ( section == fehFrameSection ) { - // ignore labels in __eh_frame section - } - else if ( section == fUTF16Section ) { - // ignore labels in __ustring section - } - else { - // ignore labels for atoms in other sections - switch ( section->flags() & SECTION_TYPE ) { - case S_REGULAR: - if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 ) - suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS - case S_ZEROFILL: - case S_COALESCED: - case S_4BYTE_LITERALS: - case S_8BYTE_LITERALS: - case S_16BYTE_LITERALS: - case S_CSTRING_LITERALS: - { - BaseAtom* newAtom; - typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value()); - if ( (pos != fAddrToAtom.end()) && (pos->second->getSectionRecord() == section) ) { - if ( fLSDAAtoms.count(pos->second) != 0 ) { - // already have LSDA atom from for this address, ignore compiler's label - suppress = true; - break; - } - else { - // another label to an existing address in the same section, make this an alias - newAtom = new SymbolAliasAtom(&fStrings[sym.n_strx()], &sym, *pos->second); - } - } - else { - if ( sym.n_value() == sectionEndAddr ) { - // Symbol address is at end of section. This can interfere - // with a symbol at the start of the next section, so don't - // add to fAddrToAtom. But do track in sectionEndAtoms so we - // still make aliases if there are duplicates. - if ( sectionEndAtoms[sym.n_sect()-1] == NULL ) { - newAtom = new SymbolAtom(*this, &sym, section); - sectionEndAtoms[sym.n_sect()-1] = newAtom; - // if this is a zero length section, so add to fAddrToAtom - if ( sym.n_value() == sectionStartAddr ) - fAddrToAtom[newAtom->getObjectAddress()] = newAtom; - } - else { - newAtom = new SymbolAliasAtom(&fStrings[sym.n_strx()], &sym, *sectionEndAtoms[sym.n_sect()-1]); - } - } - else { - // make SymbolAtom atom for this address - newAtom = new SymbolAtom(*this, &sym, section); - fAddrToAtom[newAtom->getObjectAddress()] = newAtom; - } - } - if ( ! suppress ) - fAtoms.push_back(newAtom); - } - break; - case S_SYMBOL_STUBS: - case S_LAZY_SYMBOL_POINTERS: - case S_NON_LAZY_SYMBOL_POINTERS: - // ignore symboled stubs produces by old ld64 - break; - default: - warning("symbol %s found in unsupported section in %s", - &fStrings[sym.n_strx()], this->getPath()); - } - } - } - } - else if ( (type == N_UNDF) && (sym.n_value() != 0) ) { - fAtoms.push_back(new TentativeAtom(*this, &sym)); - } - else if ( (type == N_UNDF) && (sym.n_value() == 0) ) { - const char* symName = &fStrings[sym.n_strx()]; - if ( strncmp(symName, "section$start$", 14) == 0) - fAtoms.push_back(new SectionBoundaryAtom(*this, true, symName, &symName[14])); - else if ( strncmp(symName, "section$end$", 12) == 0) - fAtoms.push_back(new SectionBoundaryAtom(*this, false, symName, &symName[12])); - } - else if ( type == N_ABS ) { - const char* symName = &fStrings[sym.n_strx()]; - if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) { - // ignore .objc_class_name_* symbols - fAppleObjc = true; - } - else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) { - // ignore empty *.eh symbols - } - else { - BaseAtom* abAtom = new AbsoluteAtom(*this, &sym); - fAtoms.push_back(abAtom); - fAddrToAbsoluteAtom[sym.n_value()] = abAtom; - } - } - else if ( type == N_INDR ) { - fHaveIndirectSymbols = true; - } - } - } - - // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names - if ( fehFrameSection != NULL ) { - for (typename std::vector::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) { - // add if not already an atom at that address - if ( fAddrToAtom.find(it->function.address) == fAddrToAtom.end() ) { - AnonymousAtom* funcAtom = new AnonymousAtom(*this, getSectionForAddress(it->function.address), it->function.address, 0); - fAtoms.push_back(funcAtom); - fAddrToAtom[it->function.address] = funcAtom; - // even though we've made a new atom, be conservative and make sure they lay out together - if ( canScatterAtoms() ) { - AtomAndOffset prev = findAtomAndOffset(it->function.address-1); - if ( prev.atom != NULL ) { - if ( ((BaseAtom*)(prev.atom))->getSectionRecord() == funcAtom->getSectionRecord() ) - new Reference(A::kFollowOn, prev, AtomAndOffset(funcAtom)); - } - } - } - } - } - - - // add all fixed size anonymous atoms from special sections - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - pint_t atomSize = 0; - uint8_t type (sect->flags() & SECTION_TYPE); - validSectionType(type); - bool suppress = false; - switch ( type ) { - case S_SYMBOL_STUBS: - suppress = true; - atomSize = sect->reserved2(); - break; - case S_LAZY_SYMBOL_POINTERS: - suppress = true; - atomSize = sizeof(pint_t); - break; - case S_NON_LAZY_SYMBOL_POINTERS: - case S_LITERAL_POINTERS: - case S_MOD_INIT_FUNC_POINTERS: - case S_MOD_TERM_FUNC_POINTERS: - atomSize = sizeof(pint_t); - break; - case S_INTERPOSING: - atomSize = sizeof(pint_t)*2; - break; - case S_4BYTE_LITERALS: - atomSize = 4; - break; - case S_8BYTE_LITERALS: - atomSize = 8; - break; - case S_16BYTE_LITERALS: - atomSize = 16; - break; - case S_REGULAR: - // special case ObjC classes to synthesize .objc_class_name_* symbols - if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) { - // gcc sometimes over aligns class structure - uint32_t align = 1 << sect->align(); - atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align); - } - // get objc Garbage Collection info - else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0)) - || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) { - // struct objc_image_info { - // uint32_t version; // initially 0 - // uint32_t flags; - // }; - // #define OBJC_IMAGE_SUPPORTS_GC 2 - // #define OBJC_IMAGE_GC_ONLY 4 - // - const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset()); - if ( (sect->size() >= 8) && (contents[0] == 0) ) { - uint32_t flags = E::get32(contents[1]); - if ( (flags & 4) == 4 ) - fObjConstraint = ObjectFile::Reader::kObjcGC; - else if ( (flags & 2) == 2 ) - fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC; - else - fObjConstraint = ObjectFile::Reader::kObjcRetainRelease; - if ( (flags & 1) == 1 ) - fReplacementClasses = true; - // don't make atom for this section - atomSize = sect->size(); - suppress = true; - } - else { - warning("can't parse __OBJC/__image_info section in %s", fPath); - } - } - // special case constant NS/CFString literals and make an atom out of each one - else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) { - atomSize = 4 * sizeof(pint_t); - } - // special case class reference sections - else if ( (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0) ) { - atomSize = sizeof(pint_t);; - } - break; - } - if ( atomSize != 0 ) { - for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) { - pint_t atomAddr = sect->addr() + sectOffset; - // add if not already an atom at that address - if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) { - AnonymousAtom* newAtom = new AnonymousAtom(*this, sect, atomAddr, atomSize); - if ( !suppress ) - fAtoms.push_back(newAtom); - fAddrToAtom[atomAddr] = newAtom->redirectTo(); - } - } - } - } - - // add all c-string anonymous atoms - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) { - uint32_t stringLen; - pint_t stringAddr; - BaseAtom* mostAlignedEmptyString = NULL; - uint32_t mostAlignedEmptyStringTrailingZeros = 0; - std::vector > emptyStrings; - for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) { - stringAddr = sect->addr() + sectOffset; - stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1; - // add if not already a non-zero length atom at that address - typename AddrToAtomMap::iterator pos = fAddrToAtom.find(stringAddr); - if ( (pos == fAddrToAtom.end()) || (pos->second->getSize() == 0) ) { - BaseAtom* newAtom = new AnonymousAtom(*this, sect, stringAddr, stringLen); - if ( stringLen == 1 ) { - // because of padding it may look like there are lots of empty strings, keep track of all - emptyStrings.push_back(std::make_pair(stringAddr, newAtom)); - // record empty string with greatest alignment requirement - uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr); - if ( (mostAlignedEmptyString == NULL) - || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) { - mostAlignedEmptyString = newAtom; - mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros; - } - } - else { - fAtoms.push_back(newAtom); - fAddrToAtom[stringAddr] = newAtom; - } - } - } - // map all uses of empty strings to the most aligned one - if ( mostAlignedEmptyString != NULL ) { - // make most aligned atom a real atom - fAtoms.push_back(mostAlignedEmptyString); - // map all other empty atoms to this one - for (typename std::vector >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) { - fAddrToAtom[it->first] = mostAlignedEmptyString; - } - } - } - } - - // sort all atoms so far by address and section - std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter()); - - //fprintf(stderr, "sorted atoms:\n"); - //for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) - // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName()); - - // create atoms to cover any non-debug ranges not handled above - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - pint_t sectionStartAddr = sect->addr(); - pint_t sectionEndAddr = sect->addr() + sect->size(); - // don't set follow-on atoms in __eh_frame section - const bool setFollowOnAtom = !canScatterAtoms() && (sect != fehFrameSection); - if ( sect->size() != 0 ) { - // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change - if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) { - fDebugInfo = kDebugInfoDwarf; - if ( strcmp(sect->sectname(), "__debug_info") == 0 ) - fDwarfDebugInfoSect = sect; - else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 ) - fDwarfDebugAbbrevSect = sect; - else if ( strcmp(sect->sectname(), "__debug_line") == 0 ) - fDwarfDebugLineSect = sect; - else if ( strcmp(sect->sectname(), "__debug_str") == 0 ) - fDwarfDebugStringSect = sect; - } - else { - if ( strcmp(sect->segname(), "__DWARFA") == 0 ) { - throw "object file contains old DWARF debug info - rebuild with newer compiler"; - } - uint8_t type (sect->flags() & SECTION_TYPE); - switch ( type ) { - case S_REGULAR: - case S_ZEROFILL: - case S_COALESCED: - // if there is not an atom already at the start of this section, add an anonymous one - pint_t previousAtomAddr = 0; - BaseAtom* previousAtom = NULL; - if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) { - BaseAtom* newAtom = new AnonymousAtom(*this, sect, sect->addr(), 0); - fAddrToAtom[sect->addr()] = newAtom; - fAtoms.push_back(newAtom); - previousAtomAddr = sectionStartAddr; - previousAtom = newAtom; - std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter()); - } - // calculate size of all atoms in this section and add follow-on references - for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { - BaseAtom* atom = (BaseAtom*)(*it); - pint_t atomAddr = atom->getObjectAddress(); - if ( atom->getSectionRecord() == sect ) { - //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName()); - if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) { - previousAtom->setSize(atomAddr - previousAtomAddr); - if ( setFollowOnAtom && (atom != previousAtom) ) - new Reference(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom)); - } - previousAtomAddr = atomAddr; - previousAtom = atom; - } - } - if ( previousAtom != NULL ) { - // set last atom in section - previousAtom->setSize(sectionEndAddr - previousAtomAddr); - } - break; - } - } - } - } - - // check for object file that defines no objc classes, but uses objc classes - // check for dtrace provider info - for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) { - const macho_nlist

& sym = fSymbols[i]; - if ( (sym.n_type() & N_STAB) == 0 ) { - if ( (sym.n_type() & N_TYPE) == N_UNDF ) { - const char* undefinedName = &fStrings[sym.n_strx()]; - if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) { - fAppleObjc = true; - } - else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) { - if ( strchr(undefinedName, '$') != NULL ) { - if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) { - // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$* - // is extra provider info - fDtraceProviderInfo.push_back(undefinedName); - } - } - } - } - } - } - - // add relocation based references to sections that have atoms with pending names - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( fSectionsWithAtomsPendingAName.count(sect) != 0 ) - addReferencesForSection(sect); - } - - // update any anonymous atoms that need references built in order to name themselves - for (typename std::vector*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) { - (*it)->resolveName(); - } - - // add relocation based references to other sections - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( fSectionsWithAtomsPendingAName.count(sect) == 0 ) - addReferencesForSection(sect); - } - - // add objective-c references - if ( fAppleObjc ) { - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) { - for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) { - AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset); - ObjectFile::Reference* classRef = ao.atom->getReferences()[0]; - if ( classRef->getFixUpOffset() == 0 ) { - const char* classStr = classRef->getTargetName(); - if ( strncmp(classStr, "cstring=", 8) == 0 ) { - const char* className; - asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]); - new Reference(A::kNoFixUp, ao, className, 0); - } - } - } - } - } - } - - // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed - for (typename std::vector*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) { - AnonymousAtom* localNonLazy = *it; - uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress; - pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset))); - makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue); - } - - - // add personality references to CIEs - for (typename std::vector::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) { - if ( it->personality.offsetInFDE != 0 ) - addCiePersonalityReference(fAddrToAtom[it->cieAddress], it->personality.offsetInFDE, it->personality.encodingOfAddress); - } - - // add all references for FDEs, including implicit group references - for (typename std::vector::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) { - AtomAndOffset funcAO = this->findAtomAndOffset(it->function.address); - if ( funcAO.offset != 0 ) - warning("FDE does not point to start of function %s\n", funcAO.atom->getDisplayName()); - AtomAndOffset fdeAO = this->findAtomAndOffset(it->fdeAddress); - if ( fdeAO.offset != 0 ) - warning("FDE does start its own atom %s\n", funcAO.atom->getDisplayName()); - AtomAndOffset cieAO = this->findAtomAndOffset(it->cie.address); - if ( cieAO.offset != 0 ) - warning("CIE does start its own atom %s\n", cieAO.atom->getDisplayName()); - AtomAndOffset lsdaAO; - if ( it->lsda.address != 0 ) { - lsdaAO = this->findAtomAndOffset(it->lsda.address); - if ( lsdaAO.offset != 0 ) - warning("LSDA does start its own atom %s\n", lsdaAO.atom->getDisplayName()); - } - - // add reference from FDE to CIE - AtomAndOffset cieInfdeAO = AtomAndOffset(fdeAO.atom, it->cie.offsetInFDE); - new Reference(A::kPointerDiff32, cieInfdeAO, cieAO, cieInfdeAO); - - // add reference from FDE to function - addFdeReference(it->function.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->function.offsetInFDE), funcAO); - - // add reference from FDE to LSDA - if ( it->lsda.address != 0 ) { - addFdeReference(it->lsda.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->lsda.offsetInFDE), lsdaAO); - } - - // FDE is in group lead by function atom - new Reference(A::kGroupSubordinate, funcAO, fdeAO); - - // LSDA is in group lead by function atom - if ( it->lsda.address != 0 ) { - new Reference(A::kGroupSubordinate, funcAO, lsdaAO); - // add back reference from LSDA to owning function - new Reference(A::kNoFixUp, lsdaAO, funcAO); - } - - // compute compact encoding for this FDE - if ( fOptions.fAddCompactUnwindEncoding ) { - ((BaseAtom*)(funcAO.atom))->setCompactUnwindEncoding(it->fdeAddress); - // add reference from function atom to personality function - // the only reference a CIE can have is the reference to the personality function - std::vector& cieRefs = cieAO.atom->getReferences(); - if ( cieRefs.size() == 1 ) { - new Reference((typename A::ReferenceKinds)((BaseAtom*)(funcAO.atom))->getPersonalityReferenceKind(), - funcAO, cieRefs[0]->getTargetName(), 0); - } - } - } - - // add command line aliases - for(std::vector::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) { - BaseAtom* target = this->findAtomByName(it->realName); - if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn ) - fAtoms.push_back(new SymbolAliasAtom(it->alias, NULL, *target)); - } - - // add dtrace probe locations - if ( fHasDTraceProbes ) { - for (uint32_t i=0; i < fSymbolCount; ++i) { - const macho_nlist

& sym = fSymbols[i]; - if ( (sym.n_type() & N_STAB) == 0 ) { - if ( (sym.n_type() & N_TYPE) == N_SECT ) { - const char* symbolName = &fStrings[sym.n_strx()]; - if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) { - //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName); - makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0); - } - } - } - } - } - - // turn indirect symbols into SymbolAliasAtom - if ( fHaveIndirectSymbols ) { - for (uint32_t i=0; i < fSymbolCount; ++i) { - const macho_nlist

& sym = fSymbols[i]; - if ( (sym.n_type() & N_STAB) == 0 ) { - if ( (sym.n_type() & N_TYPE) == N_INDR ) { - const char* aliasName = &fStrings[sym.n_strx()]; - const char* targetName = &fStrings[sym.n_value()]; - //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName); - BaseAtom* target = this->findAtomByName(targetName); - // only currently support N_INDR based aliases to something in the same .o file - if ( target != NULL ) { - fAtoms.push_back(new SymbolAliasAtom(aliasName, &sym, *target)); - //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName); - } - } - } - } - } - - //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) { - // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName()); - //} - - // add translation unit info from dwarf - uint64_t stmtList; - if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) { - // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those - if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) { - if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) { - // if can't parse dwarf, warn and give up - fDwarfTranslationUnitFile = NULL; - fDwarfTranslationUnitDir = NULL; - warning("can't parse dwarf compilation unit info in %s", this->getPath()); - fDebugInfo = kDebugInfoNone; - } - } - } - - // add line number info to atoms from dwarf - if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) { - // file with just data will have no __debug_line info - if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0) - && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) { - // validate stmt_list - if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) { - const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset(); - if ( debug_line != NULL ) { - struct line_reader_data* lines = line_open(&debug_line[stmtList], - fDwarfDebugLineSect->size() - stmtList, E::little_endian); - struct line_info result; - ObjectFile::Atom* curAtom = NULL; - uint32_t curAtomOffset = 0; - uint32_t curAtomAddress = 0; - uint32_t curAtomSize = 0; - if ( lines != NULL ) { - while ( line_next (lines, &result, line_stop_pc) ) { - //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n", - // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize); - // work around weird debug line table compiler generates if no functions in __text section - if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1)) - continue; - // for performance, see if in next pc is in current atom - if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) { - curAtomOffset = result.pc - curAtomAddress; - } - // or pc at end of current atom - else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) { - curAtomOffset = result.pc - curAtomAddress; - } - else { - // do slow look up of atom by address - AtomAndOffset ao = this->findAtomAndOffset(result.pc); - curAtom = ao.atom; - if ( curAtom == NULL ) - break; // file has line info but no functions - if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) { - // a one line function can be returned by line_next() as one entry with pc at end of blob - // look for alt atom starting at end of previous atom - uint32_t previousEnd = curAtomAddress+curAtomSize; - AtomAndOffset alt = this->findAtomAndOffset(previousEnd); - if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) { - curAtom = alt.atom; - curAtomOffset = alt.offset; - curAtomAddress = previousEnd - alt.offset; - curAtomSize = curAtom->getSize(); - } - else { - curAtomOffset = ao.offset; - curAtomAddress = result.pc - ao.offset; - curAtomSize = curAtom->getSize(); - } - } - else { - curAtomOffset = ao.offset; - curAtomAddress = result.pc - ao.offset; - curAtomSize = curAtom->getSize(); - } - } - const char* filename; - std::map::iterator pos = fDwarfIndexToFile.find(result.file); - if ( pos == fDwarfIndexToFile.end() ) { - filename = line_file(lines, result.file); - fDwarfIndexToFile[result.file] = filename; - } - else { - filename = pos->second; - } - ObjectFile::LineInfo info; - info.atomOffset = curAtomOffset; - info.fileName = filename; - info.lineNumber = result.line; - //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n", - // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence); - ((BaseAtom*)curAtom)->addLineInfo(info); - if ( result.end_of_sequence ) { - curAtom = NULL; - } - } - line_free(lines); - } - } - else { - warning("could not parse dwarf line number info in %s", this->getPath()); - } - } - } - } - - // if no dwarf, try processing stabs debugging info - if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) { - // scan symbol table for stabs entries - fStabs.reserve(fSymbolCount); // reduce re-allocations - BaseAtom* currentAtom = NULL; - pint_t currentAtomAddress = 0; - enum { start, inBeginEnd, inFun } state = start; - for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) { - const macho_nlist

* sym = &fSymbols[symbolIndex]; - bool useStab = true; - uint8_t type = sym->n_type(); - const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL; - if ( (type & N_STAB) != 0 ) { - fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs); - Stab stab; - stab.atom = NULL; - stab.type = type; - stab.other = sym->n_sect(); - stab.desc = sym->n_desc(); - stab.value = sym->n_value(); - stab.string = NULL; - switch (state) { - case start: - switch (type) { - case N_BNSYM: - // beginning of function block - state = inBeginEnd; - // fall into case to lookup atom by addresss - case N_LCSYM: - case N_STSYM: - currentAtomAddress = sym->n_value(); - currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom; - if ( currentAtom != NULL ) { - stab.atom = currentAtom; - stab.string = symString; - } - else { - fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s", - (uint64_t)sym->n_value(), path); - } - break; - case N_SO: - case N_OSO: - case N_OPT: - case N_LSYM: - case N_RSYM: - case N_PSYM: - // not associated with an atom, just copy - stab.string = symString; - break; - case N_GSYM: - { - // n_value field is NOT atom address ;-( - // need to find atom by name match - const char* colon = strchr(symString, ':'); - if ( colon != NULL ) { - // build underscore leading name - int nameLen = colon - symString; - char symName[nameLen+2]; - strlcpy(&symName[1], symString, nameLen+1); - symName[0] = '_'; - symName[nameLen+1] = '\0'; - currentAtom = findAtomByName(symName); - if ( currentAtom != NULL ) { - stab.atom = currentAtom; - stab.string = symString; - } - } - else { - // might be a debug-note without trailing :G() - currentAtom = findAtomByName(symString); - if ( currentAtom != NULL ) { - stab.atom = currentAtom; - stab.string = symString; - } - } - if ( stab.atom == NULL ) { - // ld_classic added bogus GSYM stabs for old style dtrace probes - if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) ) - warning("can't find atom for N_GSYM stabs %s in %s", symString, path); - useStab = false; - } - break; - } - case N_FUN: - // old style stabs without BNSYM - state = inFun; - currentAtomAddress = sym->n_value(); - currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom; - if ( currentAtom != NULL ) { - stab.atom = currentAtom; - stab.string = symString; - } - else { - warning("can't find atom for stabs FUN at %08llX in %s", - (uint64_t)currentAtomAddress, path); - } - break; - case N_SOL: - case N_SLINE: - stab.string = symString; - // old stabs - break; - case N_BINCL: - case N_EINCL: - case N_EXCL: - stab.string = symString; - // -gfull built .o file - break; - default: - warning("unknown stabs type 0x%X in %s", type, path); - } - break; - case inBeginEnd: - stab.atom = currentAtom; - switch (type) { - case N_ENSYM: - state = start; - currentAtom = NULL; - break; - case N_LCSYM: - case N_STSYM: - { - BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom; - if ( nestedAtom != NULL ) { - stab.atom = nestedAtom; - stab.string = symString; - } - else { - warning("can't find atom for stabs 0x%X at %08llX in %s", - type, (uint64_t)sym->n_value(), path); - } - break; - } - case N_LBRAC: - case N_RBRAC: - case N_SLINE: - // adjust value to be offset in atom - stab.value -= currentAtomAddress; - default: - stab.string = symString; - break; - } - break; - case inFun: - switch (type) { - case N_FUN: - if ( sym->n_sect() != 0 ) { - // found another start stab, must be really old stabs... - currentAtomAddress = sym->n_value(); - currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom; - if ( currentAtom != NULL ) { - stab.atom = currentAtom; - stab.string = symString; - } - else { - warning("can't find atom for stabs FUN at %08llX in %s", - (uint64_t)currentAtomAddress, path); - } - } - else { - // found ending stab, switch back to start state - stab.string = symString; - stab.atom = currentAtom; - state = start; - currentAtom = NULL; - } - break; - case N_LBRAC: - case N_RBRAC: - case N_SLINE: - // adjust value to be offset in atom - stab.value -= currentAtomAddress; - stab.atom = currentAtom; - break; - case N_SO: - stab.string = symString; - state = start; - break; - default: - stab.atom = currentAtom; - stab.string = symString; - break; - } - break; - } - // add to list of stabs for this .o file - if ( useStab ) - fStabs.push_back(stab); - } - } - } - -#if 0 - // special case precompiled header .o file (which has no content) to have one empty atom - if ( fAtoms.size() == 0 ) { - int pathLen = strlen(path); - if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) { - ObjectFile::Atom* phony = new AnonymousAtom(*this, (uint32_t)0); - //phony->fSynthesizedName = ".gch.o"; - fAtoms.push_back(phony); - } - } -#endif - - // sort all atoms by address - std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter()); - - // set ordinal and sort references in each atom - uint32_t index = fOrdinalBase; - for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { - BaseAtom* atom = (BaseAtom*)(*it); - atom->setOrdinal(index++); - atom->sortReferences(); - } - -} - -template -const macho_section* Reader::getSectionForAddress(pint_t addr) -{ - for (const macho_section

* sect=fSectionsStart; sect < fSectionsEnd; ++sect) { - if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) - return sect; - } - throwf("section not found for address 0x%08llX", (uint64_t)addr); -} - -template -ObjectFile::Atom* Reader::getFunctionAtomFromFDEAddress(pint_t addr) -{ - for (typename std::vector::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) { - if ( it->fdeAddress == addr ) { - return findAtomAndOffset(it->function.address).atom; - } - } - // CIEs won't be in fFDEInfos - return NULL; -} - -template -ObjectFile::Atom* Reader::getFunctionAtomFromLSDAAddress(pint_t addr) -{ - for (typename std::vector::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) { - if ( it->lsda.address == addr ) { - return findAtomAndOffset(it->function.address).atom; - } - } - return NULL; -} - - -template <> -void ObjectFileAddressSpace::buildRelocatedMap(const macho_section

* sect, std::map& map) -{ - // mach-o x86_64 is different, the content of a section with a relocation is the addend - const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fReader.fHeader) + sect->reloff()); - const macho_relocation_info

* relocsEnd = &relocs[sect->nreloc()]; - for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { - std::map::iterator pos; - switch ( reloc->r_type() ) { - case X86_64_RELOC_UNSIGNED: - pos = map.find(reloc->r_address()); - if ( pos != map.end() ) - pos->second += fReader.fSymbols[reloc->r_symbolnum()].n_value(); - else - map[reloc->r_address()] = fReader.fSymbols[reloc->r_symbolnum()].n_value(); - break; - case X86_64_RELOC_SUBTRACTOR: - map[reloc->r_address()] = -fReader.fSymbols[reloc->r_symbolnum()].n_value(); - break; - case X86_64_RELOC_GOT: - // there is no good address to return here. - // GOT slots are synthsized by the linker - // this is used for the reference to the personality function in CIEs - map[reloc->r_address()] = 0; - break; - default: - fprintf(stderr, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc->r_address()); - break; - } - } -} - -template -void ObjectFileAddressSpace::buildRelocatedMap(const macho_section

* sect, std::map& map) -{ - // in all architectures except x86_64, the section contents are already fixed up to point - // to content in the same object file. -} - -template <> -uint64_t ObjectFileAddressSpace::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount) -{ - // mach-o x86_64 is different, the content of a section with a relocation is the addend - uint64_t result = 0; - const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fReader.fHeader) + relocsOffset); - const macho_relocation_info

* relocsEnd = &relocs[relocsCount]; - for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { - //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address()); - if ( reloc->r_address() == sectOffset ) { - switch ( reloc->r_type() ) { - case X86_64_RELOC_UNSIGNED: - result += fReader.fSymbols[reloc->r_symbolnum()].n_value(); - break; - case X86_64_RELOC_SUBTRACTOR: - result -= fReader.fSymbols[reloc->r_symbolnum()].n_value(); - break; - case X86_64_RELOC_GOT: - // there is no good address to return here. - // GOT slots are synthsized by the linker - // this is used for the reference to the personality function in CIEs - result = 0; - break; - default: - fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset, reloc->r_type(), reloc->r_symbolnum()); - break; - } - } - } - //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result); - return result; -} - -template -typename A::P::uint_t ObjectFileAddressSpace::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount) -{ - // in all architectures except x86_64, the section contents are already fixed up to point - // to content in the same object file. - return 0; -} - - - -// FSF exception handling Pointer-Encoding constants -// Used in CFI augmentation by gcc compiler -enum { - DW_EH_PE_ptr = 0x00, - DW_EH_PE_uleb128 = 0x01, - DW_EH_PE_udata2 = 0x02, - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_udata8 = 0x04, - DW_EH_PE_signed = 0x08, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0A, - DW_EH_PE_sdata4 = 0x0B, - DW_EH_PE_sdata8 = 0x0C, - DW_EH_PE_absptr = 0x00, - DW_EH_PE_pcrel = 0x10, - DW_EH_PE_textrel = 0x20, - DW_EH_PE_datarel = 0x30, - DW_EH_PE_funcrel = 0x40, - DW_EH_PE_aligned = 0x50, - DW_EH_PE_indirect = 0x80, - DW_EH_PE_omit = 0xFF -}; - -template <> -void Reader::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding) -{ - if ( encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4) ) - throw "unexpected personality encoding in CIE"; - - // walk relocs looking for reloc in this CIE - uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr(); - const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fHeader) + fehFrameSection->reloff()); - const macho_relocation_info

* relocsEnd = &relocs[fehFrameSection->nreloc()]; - for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { - if ( reloc->r_address() == sectOffset ) { - switch ( reloc->r_type() ) { - case X86_64_RELOC_GOT: - if ( !reloc->r_extern() ) - throw "GOT reloc not extern for personality function"; - new Reference(x86_64::kPCRel32GOT, AtomAndOffset(cieAtom, offsetInCIE), &fStrings[fSymbols[reloc->r_symbolnum()].n_strx()], 4); - return; - default: - throw "expected GOT reloc for personality function"; - } - } - } - throw "personality function not found for CIE"; -} - -template <> -bool Reader::isSectDiffReloc(uint8_t r_type) -{ - switch ( r_type ) { - case PPC_RELOC_LOCAL_SECTDIFF: - case PPC_RELOC_SECTDIFF: - return true; - } - return false; -} - -template <> -bool Reader::isSectDiffReloc(uint8_t r_type) -{ - switch ( r_type ) { - case PPC_RELOC_LOCAL_SECTDIFF: - case PPC_RELOC_SECTDIFF: - return true; - } - return false; -} - -template <> -bool Reader::isSectDiffReloc(uint8_t r_type) -{ - switch ( r_type ) { - case GENERIC_RELOC_LOCAL_SECTDIFF: - case GENERIC_RELOC_SECTDIFF: - return true; - } - return false; -} - -template <> -bool Reader::isSectDiffReloc(uint8_t r_type) -{ - switch ( r_type ) { - case ARM_RELOC_LOCAL_SECTDIFF: - case ARM_RELOC_SECTDIFF: - return true; - } - return false; -} - -template -void Reader::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding) -{ - if ( (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4)) && (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel)) ) - throw "unexpected personality encoding in CIE"; - - // walk relocs looking for personality reloc in this CIE - uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr(); - const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fHeader) + fehFrameSection->reloff()); - const macho_relocation_info

* relocsEnd = &relocs[fehFrameSection->nreloc()]; - for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - // ignore - } - else { - const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - if ( sreloc->r_address() == sectOffset ) { - if ( isSectDiffReloc(sreloc->r_type()) ) { - // r_value is address of non-lazy-pointer to personality function - new Reference(A::kPointerDiff32, AtomAndOffset(cieAtom, offsetInCIE), AtomAndOffset(cieAtom, offsetInCIE), - findAtomAndOffset(sreloc->r_value())); - return; - } - } - } - } - throw "can't find relocation for personality in CIE"; -} - -template -void Reader::addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target) -{ - if ( (encoding & 0xF0) != DW_EH_PE_pcrel ) - throw "unsupported encoding in FDE"; - Kinds kind = A::kNoFixUp; - switch ( encoding & 0xF ) { - case DW_EH_PE_ptr: - kind = A::kPointerDiff; - break; - case DW_EH_PE_sdata4: - kind = A::kPointerDiff32; - break; - default: - throw "unsupported encoding in FDE"; - } - new Reference(kind, inFDE, inFDE, target); -} - -template -typename A::P::uint_t ObjectFileAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding) -{ - pint_t startAddr = addr; - pint_t p = addr; - pint_t result; - - // first get value - switch (encoding & 0x0F) { - case DW_EH_PE_ptr: - result = getP(addr); - p += sizeof(pint_t); - addr = (pint_t)p; - break; - case DW_EH_PE_uleb128: - result = getULEB128(addr, end); - break; - case DW_EH_PE_udata2: - result = get16(addr); - p += 2; - addr = (pint_t)p; - break; - case DW_EH_PE_udata4: - result = get32(addr); - p += 4; - addr = (pint_t)p; - break; - case DW_EH_PE_udata8: - result = get64(addr); - p += 8; - addr = (pint_t)p; - break; - case DW_EH_PE_sleb128: - result = getSLEB128(addr, end); - break; - case DW_EH_PE_sdata2: - result = (int16_t)get16(addr); - p += 2; - addr = (pint_t)p; - break; - case DW_EH_PE_sdata4: - result = (int32_t)get32(addr); - p += 4; - addr = (pint_t)p; - break; - case DW_EH_PE_sdata8: - result = get64(addr); - p += 8; - addr = (pint_t)p; - break; - default: - throwf("ObjectFileAddressSpace::getEncodedP() encoding 0x%08X not supported", encoding); - } - - // then add relative offset - switch ( encoding & 0x70 ) { - case DW_EH_PE_absptr: - // do nothing - break; - case DW_EH_PE_pcrel: - // pc-rel sdata4 should return zero if content is zero - if ( (result != 0) || ((encoding & DW_EH_PE_indirect) != 0) ) - result += startAddr; - break; - case DW_EH_PE_textrel: - throw "DW_EH_PE_textrel pointer encoding not supported"; - break; - case DW_EH_PE_datarel: - throw "DW_EH_PE_datarel pointer encoding not supported"; - break; - case DW_EH_PE_funcrel: - throw "DW_EH_PE_funcrel pointer encoding not supported"; - break; - case DW_EH_PE_aligned: - throw "DW_EH_PE_aligned pointer encoding not supported"; - break; - default: - throwf("ObjectFileAddressSpace::getEncodedP() encoding 0x%08X not supported", encoding); - break; - } - - if ( encoding & DW_EH_PE_indirect ) - result = getP(result); - - return result; -} - -template <> -uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - pint_t lsda; - pint_t personality; - char warningBuffer[1024]; - uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); - if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) { - //if ( fOwner.fOptions.fForDyld ) - // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); - //else - if ( fOwner.fOptions.fWarnCompactUnwind ) - warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer); - } - return result; -} - -template <> -uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - pint_t lsda; - pint_t personality; - char warningBuffer[1024]; - uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86_64>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); - if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) { - //if ( fOwner.fOptions.fForDyld ) - // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); - //else - if ( fOwner.fOptions.fWarnCompactUnwind ) - warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer); - } - return result; -} - -template <> -uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - // compact encoding not supported for ppc - return 0; -} - -template <> -uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - // compact encoding not supported for ppc64 - return 0; -} - -template <> -uint32_t SymbolAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - // compact encoding not supported for arm - return 0; -} - - -template -uint8_t SymbolAtom::getLSDAReferenceKind() const -{ - return A::kGroupSubordinate; -} - -template <> -uint8_t SymbolAtom::getPersonalityReferenceKind() const -{ - return x86_64::kGOTNoFixUp; -} - -template <> -uint8_t SymbolAtom::getPersonalityReferenceKind() const -{ - return x86::kNoFixUp; -} - -template -uint8_t SymbolAtom::getPersonalityReferenceKind() const -{ - // only used with architectures that support compact unwinding - return 0; -} - - -template <> -uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - pint_t lsda; - pint_t personality; - char warningBuffer[1024]; - uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); - if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) { - //if ( fOwner.fOptions.fForDyld ) - // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); - //else - if ( fOwner.fOptions.fWarnCompactUnwind ) - warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath()); - } - return result; -} - -template <> -uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - pint_t lsda; - pint_t personality; - char warningBuffer[1024]; - uint32_t result = libunwind::DwarfInstructions, libunwind::Registers_x86_64>::createCompactEncodingFromFDE( - fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer); - if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) { - //if ( fOwner.fOptions.fForDyld ) - // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName()); - //else - if ( fOwner.fOptions.fWarnCompactUnwind ) - warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath()); - } - return result; -} - -template <> -uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - // compact encoding not supported for ppc - return 0; -} - -template <> -uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - // compact encoding not supported for ppc64 - return 0; -} - -template <> -uint32_t AnonymousAtom::getCompactUnwindEncoding(uint64_t ehAtomAddress) -{ - // compact encoding not supported for arm - return 0; -} - - -template -uint8_t AnonymousAtom::getLSDAReferenceKind() const -{ - return A::kGroupSubordinate; -} - -template <> -uint8_t AnonymousAtom::getPersonalityReferenceKind() const -{ - return x86_64::kGOTNoFixUp; -} - -template <> -uint8_t AnonymousAtom::getPersonalityReferenceKind() const -{ - return x86::kNoFixUp; -} - -template -uint8_t AnonymousAtom::getPersonalityReferenceKind() const -{ - // only used with architectures that support compact unwinding - return 0; -} - - - - - - - -template <> -void Reader::setCpuConstraint(uint32_t cpusubtype) -{ - switch (cpusubtype) { - case CPU_SUBTYPE_POWERPC_ALL: - case CPU_SUBTYPE_POWERPC_750: - case CPU_SUBTYPE_POWERPC_7400: - case CPU_SUBTYPE_POWERPC_7450: - case CPU_SUBTYPE_POWERPC_970: - fCpuConstraint = cpusubtype; - break; - default: - warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath); - fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL; - break; - } -} - -template <> -void Reader::setCpuConstraint(uint32_t cpusubtype) -{ - switch (cpusubtype) { - case CPU_SUBTYPE_ARM_ALL: - case CPU_SUBTYPE_ARM_V4T: - case CPU_SUBTYPE_ARM_V5TEJ: - case CPU_SUBTYPE_ARM_V6: - case CPU_SUBTYPE_ARM_XSCALE: - case CPU_SUBTYPE_ARM_V7: - fCpuConstraint = cpusubtype; - break; - default: - warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath); - fCpuConstraint = CPU_SUBTYPE_ARM_ALL; - break; - } -} - -template -void Reader::setCpuConstraint(uint32_t cpusubtype) -{ - // no cpu sub types for this architecture -} - -template <> -uint32_t Reader::updateCpuConstraint(uint32_t previous) -{ - switch ( previous ) { - case CPU_SUBTYPE_POWERPC_ALL: - return fCpuConstraint; - break; - case CPU_SUBTYPE_POWERPC_750: - if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 || - fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 || - fCpuConstraint == CPU_SUBTYPE_POWERPC_970 ) - return fCpuConstraint; - break; - case CPU_SUBTYPE_POWERPC_7400: - case CPU_SUBTYPE_POWERPC_7450: - if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 ) - return fCpuConstraint; - break; - case CPU_SUBTYPE_POWERPC_970: - // G5 can run everything - break; - default: - throw "Unhandled PPC cpu subtype!"; - break; - } - return previous; -} - - - -template <> -uint32_t Reader::updateCpuConstraint(uint32_t previous) -{ - switch (previous) { - case CPU_SUBTYPE_ARM_ALL: - return fCpuConstraint; - break; - case CPU_SUBTYPE_ARM_V5TEJ: - // v6, v7, and xscale are more constrained than previous file (v5), so use it - if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6) - || (fCpuConstraint == CPU_SUBTYPE_ARM_V7) - || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) ) - return fCpuConstraint; - break; - case CPU_SUBTYPE_ARM_V4T: - // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it - if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7) - || (fCpuConstraint == CPU_SUBTYPE_ARM_V6) - || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ) - || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) ) - return fCpuConstraint; - break; - case CPU_SUBTYPE_ARM_V6: - // v6 can run everything except xscale and v7 - if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE ) - throw "can't mix xscale and v6 code"; - if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 ) - return fCpuConstraint; - break; - case CPU_SUBTYPE_ARM_XSCALE: - // xscale can run everything except v6 and v7 - if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 ) - throw "can't mix xscale and v6 code"; - if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 ) - throw "can't mix xscale and v7 code"; - break; - case CPU_SUBTYPE_ARM_V7: - // v7 can run everything except xscale - if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE ) - throw "can't mix xscale and v7 code"; - break; - default: - throw "Unhandled ARM cpu subtype!"; - } - return previous; -} - -template -uint32_t Reader::updateCpuConstraint(uint32_t current) -{ - // no cpu sub types for this architecture - return current; -} - -template -void Reader::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName) -{ - // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with - // a matching provider name, add a by-name kDtraceTypeReference at probe site - const char* dollar = strchr(providerName, '$'); - if ( dollar != NULL ) { - int providerNameLen = dollar-providerName+1; - for ( std::vector::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) { - const char* typeDollar = strchr(*it, '$'); - if ( typeDollar != NULL ) { - if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) { - makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0); - } - } - } - } -} - - -template <> -void Reader::validSectionType(uint8_t type) -{ - switch ( type ) { - case S_SYMBOL_STUBS: - throw "symbol_stub sections not valid in x86_64 object files"; - case S_LAZY_SYMBOL_POINTERS: - throw "lazy pointer sections not valid in x86_64 object files"; - case S_NON_LAZY_SYMBOL_POINTERS: - throw "non lazy pointer sections not valid in x86_64 object files"; - } -} - -template -void Reader::validSectionType(uint8_t type) -{ -} - -template -bool Reader::getTranslationUnitSource(const char** dir, const char** name) const -{ - if ( fDebugInfo == kDebugInfoDwarf ) { - *dir = fDwarfTranslationUnitDir; - *name = fDwarfTranslationUnitFile; - return (fDwarfTranslationUnitFile != NULL); - } - return false; -} - -template -BaseAtom* Reader::findAtomByName(const char* name) -{ - // first search the more important atoms - for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) { - const char* atomName = it->second->getName(); - if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) { - return it->second; - } - } - // try all atoms, because this might have been a tentative definition - for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { - BaseAtom* atom = (BaseAtom*)(*it); - const char* atomName = atom->getName(); - if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) { - return atom; - } - } - return NULL; -} - -template -Reference* Reader::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr) -{ - return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr)); -} - -template -Reference* Reader::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr) -{ - return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr)); -} - -template -Reference* Reader::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr) -{ - return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr)); -} - -template -Reference* Reader::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr) -{ - return new Reference(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr)); -} - -template -Reference* Reader::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset) -{ - return new Reference(kind, findAtomAndOffset(atAddr), toName, toOffset); -} - -template -BaseAtom* Reader::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section

* ehSect) -{ - // add a group subordinate reference from function atom to its eh frame atom - const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset(); - int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function - pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8; - ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom; - ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom; - new Reference(A::kGroupSubordinate, funcAtom, ehAtom); - return (BaseAtom*)funcAtom; -} - - -template <> -Reference* Reader::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset) -{ - // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references - // instead check scope of target - BaseAtom* target = findAtomByName(toName); - if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) - return new Reference(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset)); - else - return new Reference(kind, findAtomAndOffset(atAddr), toName, toOffset); -} - -template <> -Reference* Reader::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist

* toSymbol, pint_t toOffset) -{ - // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references - // instead check scope of target - const char* symbolName = &fStrings[toSymbol->n_strx()]; - if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) { - AtomAndOffset targetAO = findAtomAndOffsetForSection(toSymbol->n_value(), toSymbol->n_sect()); - targetAO.offset = toOffset; - return new Reference(kind, findAtomAndOffset(atAddr), targetAO); - } - else - return new Reference(kind, findAtomAndOffset(atAddr), symbolName, toOffset); -} - - -template <> -BaseAtom* Reader::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section

* ehSect) -{ - // add a group subordinate reference from function atom to its eh frame atom - // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target - uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function - const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fHeader) + ehSect->reloff()); - const macho_relocation_info

* relocsEnd = &relocs[ehSect->nreloc()]; - for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { - if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) { - pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value(); - ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom; - ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom; - new Reference(x86_64::kGroupSubordinate, funcAtom, ehAtom); - return (BaseAtom*)funcAtom; - } - } - warning("can't find matching function for eh symbol %s", ehName); - return NULL; -} - -template -AtomAndOffset Reader::findAtomAndOffsetForSection(pint_t addr, unsigned int expectedSectionIndex) -{ - AtomAndOffset ao = findAtomAndOffset(addr); - if ( ao.atom != NULL ) { - if ( ((BaseAtom*)(ao.atom))->getSectionIndex() == expectedSectionIndex ) - return ao; - } - // The atom found is not in the section expected. - // This probably means there was a label at the end of the section. - // Do a slow sequential lookup - for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); ++it) { - BaseAtom* atom = *it; - if ( atom->getSectionIndex() == expectedSectionIndex ) { - pint_t objAddr = atom->getObjectAddress(); - if ( (objAddr == addr) || ((objAddr < addr) && (objAddr+atom->getSize() > addr)) ) { - return AtomAndOffset(atom, addr-atom->getObjectAddress()); - } - } - } - // no atom found that matched section, fall back to one orginally found - return ao; -} - -template -AtomAndOffset Reader::findAtomAndOffset(pint_t addr) -{ - // STL has no built-in for "find largest key that is same or less than" - typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr); - // if no atoms up to this address return none found - if ( it == fAddrToAtom.begin() ) - return AtomAndOffset(NULL); - // otherwise upper_bound gets us next key, so we back up one - --it; - AtomAndOffset result; - result.atom = it->second; - result.offset = addr - it->first; - //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n", - // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize()); - return result; -} - -// "scattered" relocations enable you to offset into an atom past the end of it -// baseAddr is the address of the target atom, -// realAddr is the points into it -template -AtomAndOffset Reader::findAtomAndOffset(pint_t baseAddr, pint_t realAddr) -{ - typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr); - if ( it != fAddrToAtom.end() ) { - AtomAndOffset result; - result.atom = it->second; - result.offset = realAddr - it->first; - if ( result.atom->isThumb() ) - result.offset &= -2; - //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset); - return result; - } - // getting here means we have a scattered relocation to an address without a label - // so, find the atom that contains the baseAddr, and offset from that to the readAddr - AtomAndOffset result = findAtomAndOffset(baseAddr); - result.offset += (realAddr-baseAddr); - return result; -} - - -/* Skip over a LEB128 value (signed or unsigned). */ -static void -skip_leb128 (const uint8_t ** offset, const uint8_t * end) -{ - while (*offset != end && **offset >= 0x80) - (*offset)++; - if (*offset != end) - (*offset)++; -} - -/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow - or error. On overflow, skip past the rest of the uleb128. */ -static uint64_t -read_uleb128 (const uint8_t ** offset, const uint8_t * end) -{ - uint64_t result = 0; - int bit = 0; - - do { - uint64_t b; - - if (*offset == end) - return (uint64_t) -1; - - b = **offset & 0x7f; - - if (bit >= 64 || b << bit >> bit != b) - result = (uint64_t) -1; - else - result |= b << bit, bit += 7; - } while (*(*offset)++ >= 0x80); - return result; -} - - -/* Skip over a DWARF attribute of form FORM. */ -template -bool Reader::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, - uint8_t addr_size, bool dwarf64) -{ - int64_t sz=0; - - switch (form) - { - case DW_FORM_addr: - sz = addr_size; - break; - - case DW_FORM_block2: - if (end - *offset < 2) - return false; - sz = 2 + A::P::E::get16(*(uint16_t*)offset); - break; - - case DW_FORM_block4: - if (end - *offset < 4) - return false; - sz = 2 + A::P::E::get32(*(uint32_t*)offset); - break; - - case DW_FORM_data2: - case DW_FORM_ref2: - sz = 2; - break; - - case DW_FORM_data4: - case DW_FORM_ref4: - sz = 4; - break; - - case DW_FORM_data8: - case DW_FORM_ref8: - sz = 8; - break; - - case DW_FORM_string: - while (*offset != end && **offset) - ++*offset; - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - sz = 1; - break; - - case DW_FORM_block: - sz = read_uleb128 (offset, end); - break; - - case DW_FORM_block1: - if (*offset == end) - return false; - sz = 1 + **offset; - break; - - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - skip_leb128 (offset, end); - return true; - - case DW_FORM_strp: - case DW_FORM_ref_addr: - sz = 4; - break; - - default: - return false; - } - if (end - *offset < sz) - return false; - *offset += sz; - return true; -} - -template -const char* Reader::getDwarfString(uint64_t form, const uint8_t* p) -{ - if ( form == DW_FORM_string ) - return (const char*)p; - else if ( form == DW_FORM_strp ) { - uint32_t offset = E::get32(*((uint32_t*)p)); - const char* dwarfStrings = (char*)(fHeader) + fDwarfDebugStringSect->offset(); - if ( offset > fDwarfDebugStringSect->size() ) { - warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->getPath()); - return NULL; - } - return &dwarfStrings[offset]; - } - warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->getPath()); - return NULL; -} - - -// Look at the compilation unit DIE and determine -// its NAME, compilation directory (in COMP_DIR) and its -// line number information offset (in STMT_LIST). NAME and COMP_DIR -// may be NULL (especially COMP_DIR) if they are not in the .o file; -// STMT_LIST will be (uint64_t) -1. -// -// At present this assumes that there's only one compilation unit DIE. -// -template -bool Reader::read_comp_unit(const char ** name, const char ** comp_dir, - uint64_t *stmt_list) -{ - const uint8_t * debug_info; - const uint8_t * debug_abbrev; - const uint8_t * di; - const uint8_t * da; - const uint8_t * end; - const uint8_t * enda; - uint64_t sz; - uint16_t vers; - uint64_t abbrev_base; - uint64_t abbrev; - uint8_t address_size; - bool dwarf64; - - *name = NULL; - *comp_dir = NULL; - *stmt_list = (uint64_t) -1; - - if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) ) - return false; - - debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset(); - debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset(); - di = debug_info; - - if (fDwarfDebugInfoSect->size() < 12) - /* Too small to be a real debug_info section. */ - return false; - sz = A::P::E::get32(*(uint32_t*)di); - di += 4; - dwarf64 = sz == 0xffffffff; - if (dwarf64) - sz = A::P::E::get64(*(uint64_t*)di), di += 8; - else if (sz > 0xffffff00) - /* Unknown dwarf format. */ - return false; - - /* Verify claimed size. */ - if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11)) - return false; - - vers = A::P::E::get16(*(uint16_t*)di); - if (vers < 2 || vers > 3) - /* DWARF version wrong for this code. - Chances are we could continue anyway, but we don't know for sure. */ - return false; - di += 2; - - /* Find the debug_abbrev section. */ - abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di); - di += dwarf64 ? 8 : 4; - - if (abbrev_base > fDwarfDebugAbbrevSect->size()) - return false; - da = debug_abbrev + abbrev_base; - enda = debug_abbrev + fDwarfDebugAbbrevSect->size(); - - address_size = *di++; - - /* Find the abbrev number we're looking for. */ - end = di + sz; - abbrev = read_uleb128 (&di, end); - if (abbrev == (uint64_t) -1) - return false; - - /* Skip through the debug_abbrev section looking for that abbrev. */ - for (;;) - { - uint64_t this_abbrev = read_uleb128 (&da, enda); - uint64_t attr; - - if (this_abbrev == abbrev) - /* This is almost always taken. */ - break; - skip_leb128 (&da, enda); /* Skip the tag. */ - if (da == enda) - return false; - da++; /* Skip the DW_CHILDREN_* value. */ - - do { - attr = read_uleb128 (&da, enda); - skip_leb128 (&da, enda); - } while (attr != 0 && attr != (uint64_t) -1); - if (attr != 0) - return false; - } - - /* Check that the abbrev is one for a DW_TAG_compile_unit. */ - if (read_uleb128 (&da, enda) != DW_TAG_compile_unit) - return false; - if (da == enda) - return false; - da++; /* Skip the DW_CHILDREN_* value. */ - - /* Now, go through the DIE looking for DW_AT_name, - DW_AT_comp_dir, and DW_AT_stmt_list. */ - for (;;) - { - uint64_t attr = read_uleb128 (&da, enda); - uint64_t form = read_uleb128 (&da, enda); - - if (attr == (uint64_t) -1) - return false; - else if (attr == 0) - return true; - - if (form == DW_FORM_indirect) - form = read_uleb128 (&di, end); - - if (attr == DW_AT_name) - *name = getDwarfString(form, di); - else if (attr == DW_AT_comp_dir) - *comp_dir = getDwarfString(form, di); - else if (attr == DW_AT_stmt_list && form == DW_FORM_data4) - *stmt_list = A::P::E::get32(*(uint32_t*)di); - else if (attr == DW_AT_stmt_list && form == DW_FORM_data8) - *stmt_list = A::P::E::get64(*(uint64_t*)di); - if (! skip_form (&di, end, form, address_size, dwarf64)) - return false; - } -} - -template -const char* Reader::assureFullPath(const char* path) -{ - if ( path[0] == '/' ) - return path; - char cwdbuff[MAXPATHLEN]; - if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) { - char* result; - asprintf(&result, "%s/%s", cwdbuff, path); - if ( result != NULL ) - return result; - } - return path; -} - - -// -// -// To implement architecture xxx, you must write template specializations for the following six methods: -// Reader::validFile() -// Reader::addRelocReference() -// Reference::getDescription() -// -// - - -template <> -bool Reader::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} - -template <> -bool Reader::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC_64 ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} - -template <> -bool Reader::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return false; - if ( header->cputype() != CPU_TYPE_I386 ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} - -template <> -bool Reader::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC_64 ) - return false; - if ( header->cputype() != CPU_TYPE_X86_64 ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} - -template <> -bool Reader::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return false; - if ( header->cputype() != CPU_TYPE_ARM ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - if ( subtypeMustMatch && ((cpu_subtype_t)header->cpusubtype() != subtype) ) - return false; - return true; -} - - -template <> -const char* Reader::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return NULL; - switch ( header->cpusubtype() ) { - case CPU_SUBTYPE_POWERPC_750: - return "ppc750"; - case CPU_SUBTYPE_POWERPC_7400: - return "ppc7400"; - case CPU_SUBTYPE_POWERPC_7450: - return "ppc7450"; - case CPU_SUBTYPE_POWERPC_970: - return "ppc970"; - case CPU_SUBTYPE_POWERPC_ALL: - return "ppc"; - } - return "ppc???"; -} - -template <> -const char* Reader::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return NULL; - return "ppc64"; -} - -template <> -const char* Reader::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_I386 ) - return NULL; - return "i386"; -} - -template <> -const char* Reader::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_X86_64 ) - return NULL; - return "x86_64"; -} - -template <> -const char* Reader::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_ARM ) - return NULL; - switch ( header->cpusubtype() ) { - case CPU_SUBTYPE_ARM_V4T: - return "armv4t"; - case CPU_SUBTYPE_ARM_V5TEJ: - return "armv5"; - case CPU_SUBTYPE_ARM_V6: - return "armv6"; - case CPU_SUBTYPE_ARM_V7: - return "armv7"; - } - return "arm???"; -} - - -template -bool Reader::isWeakImportSymbol(const macho_nlist

* sym) -{ - return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) ); -} - -template <> -bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) -{ - return addRelocReference_powerpc(sect, reloc); -} - -template <> -bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) -{ - return addRelocReference_powerpc(sect, reloc); -} - - -// -// ppc and ppc64 both use the same relocations, so process them in one common routine -// -template -bool Reader::addRelocReference_powerpc(const macho_section* sect, - const macho_relocation_info* reloc) -{ - uint32_t srcAddr; - uint32_t dstAddr; - uint32_t* fixUpPtr; - int32_t displacement = 0; - uint32_t instruction = 0; - uint32_t offsetInTarget; - int16_t lowBits; - bool result = false; - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - const macho_relocation_info

* nextReloc = &reloc[1]; - const char* targetName = NULL; - bool weakImport = false; - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); - if ( reloc->r_type() != PPC_RELOC_PAIR ) - instruction = BigEndian::get32(*fixUpPtr); - srcAddr = sect->addr() + reloc->r_address(); - if ( reloc->r_extern() ) { - const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - targetName = &fStrings[targetSymbol->n_strx()]; - weakImport = this->isWeakImportSymbol(targetSymbol); - } - switch ( reloc->r_type() ) { - case PPC_RELOC_BR24: - { - if ( (instruction & 0x4C000000) == 0x48000000 ) { - displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - } - else { - printf("bad instruction for BR24 reloc"); - } - if ( reloc->r_extern() ) { - offsetInTarget = srcAddr + displacement; - if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { - makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { - makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else if ( weakImport ) - makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget); - else - makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = srcAddr + displacement; - // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol - ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom; - targetName = atom->getName(); - if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { - makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { - makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) - && ((AnonymousAtom*)atom)->isWeakImportStub() ) - makeReference(A::kBranch24WeakImport, srcAddr, dstAddr); - else - makeReference(A::kBranch24, srcAddr, dstAddr); - } - } - break; - case PPC_RELOC_BR14: - { - displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - if ( reloc->r_extern() ) { - offsetInTarget = srcAddr + displacement; - makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = srcAddr + displacement; - makeReference(A::kBranch14, srcAddr, dstAddr); - } - } - break; - case PPC_RELOC_PAIR: - // skip, processed by a previous look ahead - break; - case PPC_RELOC_LO16: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - throw "PPC_RELOC_LO16 missing following pair"; - } - result = true; - lowBits = (instruction & 0xFFFF); - if ( reloc->r_extern() ) { - offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF); - makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF); - if ( reloc->r_symbolnum() == R_ABS ) { - // find absolute symbol that corresponds to pointerValue - typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0); - else - makeReference(A::kAbsLow16, srcAddr, dstAddr); - } - else { - makeReference(A::kAbsLow16, srcAddr, dstAddr); - } - } - } - break; - case PPC_RELOC_LO14: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - throw "PPC_RELOC_LO14 missing following pair"; - } - result = true; - lowBits = (instruction & 0xFFFC); - if ( reloc->r_extern() ) { - offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF); - makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF); - if ( reloc->r_symbolnum() == R_ABS ) { - // find absolute symbol that corresponds to pointerValue - typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0); - else - makeReference(A::kAbsLow14, srcAddr, dstAddr); - } - else { - makeReference(A::kAbsLow14, srcAddr, dstAddr); - } - } - } - break; - case PPC_RELOC_HI16: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - throw "PPC_RELOC_HI16 missing following pair"; - } - result = true; - if ( reloc->r_extern() ) { - offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); - makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); - if ( reloc->r_symbolnum() == R_ABS ) { - // find absolute symbol that corresponds to pointerValue - typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0); - else - makeReference(A::kAbsHigh16, srcAddr, dstAddr); - } - else { - makeReference(A::kAbsHigh16, srcAddr, dstAddr); - } - } - } - break; - case PPC_RELOC_HA16: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - throw "PPC_RELOC_HA16 missing following pair"; - } - result = true; - lowBits = (nextReloc->r_address() & 0x0000FFFF); - if ( reloc->r_extern() ) { - offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - if ( reloc->r_symbolnum() == R_ABS ) { - // find absolute symbol that corresponds to pointerValue - typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0); - else - makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr); - } - else { - makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr); - } - } - } - break; - case PPC_RELOC_VANILLA: - { - pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr)); - if ( reloc->r_extern() ) { - if ( weakImport ) - makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue); - else - makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue); - } - else { - new Reference(A::kPointer, findAtomAndOffset(srcAddr), findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum())); - } - } - break; - case PPC_RELOC_JBSR: - // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - throw "PPC_RELOC_JBSR missing following pair"; - } - if ( !fHasLongBranchStubs ) - warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath); - fHasLongBranchStubs = true; - result = true; - if ( reloc->r_extern() ) { - throw "PPC_RELOC_JBSR should not be using an external relocation"; - } - makeReference(A::kBranch24, srcAddr, nextReloc->r_address()); - if ( (instruction & 0x4C000000) == 0x48000000 ) { - displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - } - else { - fprintf(stderr, "bad instruction for BR24 reloc"); - } - break; - default: - warning("unknown relocation type %d", reloc->r_type()); - } - } - else { - const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - uint32_t betterDstAddr; - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); - const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; - const macho_relocation_info

* nextReloc = &reloc[1]; - // file format allows pair to be scattered or not - bool nextRelocIsPair = false; - uint32_t nextRelocAddress = 0; - uint32_t nextRelocValue = 0; - if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { - if ( nextReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextReloc->r_address(); - result = true; - } - } - else { - if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextSReloc->r_address(); - nextRelocValue = nextSReloc->r_value(); - result = true; - } - } - switch (sreloc->r_type()) { - case PPC_RELOC_VANILLA: - { - betterDstAddr = P::getP(*(pint_t*)fixUpPtr); - //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr); - // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) - makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr); - } - break; - case PPC_RELOC_BR14: - { - instruction = BigEndian::get32(*fixUpPtr); - displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - betterDstAddr = srcAddr+displacement; - //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement); - makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr); - } - break; - case PPC_RELOC_BR24: - { - instruction = BigEndian::get32(*fixUpPtr); - if ( (instruction & 0x4C000000) == 0x48000000 ) { - displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - betterDstAddr = srcAddr+displacement; - makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr); - } - } - break; - case PPC_RELOC_LO16_SECTDIFF: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_LO16_SECTDIFF missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (instruction & 0xFFFF); - displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF); - makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr); - } - break; - case PPC_RELOC_LO14_SECTDIFF: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_LO14_SECTDIFF missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (instruction & 0xFFFC); - displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF); - makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr); - } - break; - case PPC_RELOC_HA16_SECTDIFF: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_HA16_SECTDIFF missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (nextRelocAddress & 0x0000FFFF); - displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr); - } - break; - case PPC_RELOC_LO14: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_LO14 missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (instruction & 0xFFFC); - betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF); - makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr); - } - break; - case PPC_RELOC_LO16: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_LO16 missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (instruction & 0xFFFF); - betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF); - makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr); - } - break; - case PPC_RELOC_HA16: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_HA16 missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (nextRelocAddress & 0xFFFF); - betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits; - makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr); - } - break; - case PPC_RELOC_HI16: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_HI16 missing following pair"; - } - instruction = BigEndian::get32(*fixUpPtr); - lowBits = (nextRelocAddress & 0xFFFF); - betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF); - makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr); - } - break; - case PPC_RELOC_SECTDIFF: - case PPC_RELOC_LOCAL_SECTDIFF: - { - if ( ! nextRelocIsPair ) { - throw "PPC_RELOC_SECTDIFF missing following pair"; - } - Kinds kind = A::kPointerDiff32;; - uint32_t contentAddr = 0; - switch ( sreloc->r_length() ) { - case 0: - throw "bad diff relocations r_length (0) for ppc architecture"; - case 1: - kind = A::kPointerDiff16; - contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr)); - break; - case 2: - kind = A::kPointerDiff32; - contentAddr = BigEndian::get32(*fixUpPtr); - break; - case 3: - kind = A::kPointerDiff64; - contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr)); - break; - } - AtomAndOffset srcao = findAtomAndOffset(srcAddr); - AtomAndOffset fromao = findAtomAndOffset(nextRelocValue); - AtomAndOffset toao = findAtomAndOffset(dstAddr); - // check for addend encoded in the section content - //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n", - // dstAddr, nextRelocValue, contentAddr); - if ( (dstAddr - nextRelocValue) != contentAddr ) { - if ( toao.atom == srcao.atom ) - toao.offset += (contentAddr + nextRelocValue) - dstAddr; - else if ( fromao.atom == srcao.atom ) - toao.offset += (contentAddr + nextRelocValue) - dstAddr; - else - fromao.offset += (dstAddr - contentAddr) - nextRelocValue; - } - //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n", - // srcao.atom->getDisplayName(), srcao.offset, - // fromao.atom->getDisplayName(), fromao.offset, - // toao.atom->getDisplayName(), toao.offset); - new Reference(kind, srcao, fromao, toao); - } - break; - case PPC_RELOC_PAIR: - break; - case PPC_RELOC_HI16_SECTDIFF: - warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF"); - break; - default: - warning("unknown scattered relocation type %d", sreloc->r_type()); - } - } - return result; -} - - -template <> -bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) -{ - uint32_t srcAddr; - uint32_t dstAddr; - uint32_t* fixUpPtr; - bool result = false; - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - srcAddr = sect->addr() + reloc->r_address(); - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); - switch ( reloc->r_type() ) { - case GENERIC_RELOC_VANILLA: - { - x86::ReferenceKinds kind = x86::kPointer; - uint32_t pointerValue = E::get32(*fixUpPtr); - if ( reloc->r_pcrel() ) { - switch( reloc->r_length() ) { - case 0: - kind = x86::kPCRel8; - pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t); - break; - case 1: - kind = x86::kPCRel16; - pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t); - break; - case 2: - kind = x86::kPCRel32; - pointerValue += srcAddr + sizeof(uint32_t); - break; - case 3: - throw "bad pc-rel vanilla relocation length"; - } - } - else if ( strcmp(sect->segname(), "__TEXT") == 0 ) { - kind = x86::kAbsolute32; - if ( reloc->r_length() != 2 ) - throw "bad vanilla relocation length"; - } - else { - kind = x86::kPointer; - if ( reloc->r_length() != 2 ) - throw "bad vanilla relocation length"; - } - if ( reloc->r_extern() ) { - const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - if ( this->isWeakImportSymbol(targetSymbol) ) { - if ( reloc->r_pcrel() ) - kind = x86::kPCRel32WeakImport; - else - kind = x86::kPointerWeakImport; - } - const char* targetName = &fStrings[targetSymbol->n_strx()]; - if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { - makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { - makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else - makeByNameReference(kind, srcAddr, targetName, pointerValue); - } - else { - AtomAndOffset targetAO = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()); - const char* targetName = targetAO.atom->getName(); - if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { - makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { - makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol - else if ( reloc->r_pcrel() && (targetAO.atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) - && ((AnonymousAtom*)targetAO.atom)->isWeakImportStub() ) - new Reference(x86::kPCRel32WeakImport, findAtomAndOffset(srcAddr), targetAO); - else if ( reloc->r_symbolnum() != R_ABS ) - new Reference(kind, findAtomAndOffset(srcAddr), targetAO); - else { - // find absolute symbol that corresponds to pointerValue - AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(kind, srcAddr, pos->second->getName(), 0); - else - throwf("R_ABS reloc but no absolute symbol at target address"); - } - } - } - break; - default: - warning("unknown relocation type %d", reloc->r_type()); - } - } - else { - const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); - const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; - const macho_relocation_info

* nextReloc = &reloc[1]; - pint_t betterDstAddr; - // file format allows pair to be scattered or not - bool nextRelocIsPair = false; - uint32_t nextRelocAddress = 0; - uint32_t nextRelocValue = 0; - if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { - if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextReloc->r_address(); - result = true; - } - } - else { - if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextSReloc->r_address(); - nextRelocValue = nextSReloc->r_value(); - } - } - switch (sreloc->r_type()) { - case GENERIC_RELOC_VANILLA: - betterDstAddr = LittleEndian::get32(*fixUpPtr); - //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr); - // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) - if ( sreloc->r_pcrel() ) { - switch ( sreloc->r_length() ) { - case 2: - betterDstAddr += srcAddr + 4; - makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr); - break; - case 1: - betterDstAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)) + srcAddr + 2; - makeReferenceWithToBase(x86::kPCRel16, srcAddr, betterDstAddr, dstAddr); - break; - case 0: - betterDstAddr = *((uint8_t*)fixUpPtr) + srcAddr + 1; - makeReferenceWithToBase(x86::kPCRel8, srcAddr, betterDstAddr, dstAddr); - break; - case 3: - throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc"); - break; - } - } - else { - if ( sreloc->r_length() != 2 ) - throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length()); - if ( strcmp(sect->segname(), "__TEXT") == 0 ) - makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr); - else - makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr); - } - break; - case GENERIC_RELOC_SECTDIFF: - case GENERIC_RELOC_LOCAL_SECTDIFF: - { - if ( !nextRelocIsPair ) { - throw "GENERIC_RELOC_SECTDIFF missing following pair"; - } - x86::ReferenceKinds kind = x86::kPointerDiff; - uint32_t contentAddr = 0; - switch ( sreloc->r_length() ) { - case 0: - case 3: - throw "bad length for GENERIC_RELOC_SECTDIFF"; - case 1: - kind = x86::kPointerDiff16; - contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)); - break; - case 2: - kind = x86::kPointerDiff; - contentAddr = LittleEndian::get32(*fixUpPtr); - break; - } - AtomAndOffset srcao = findAtomAndOffset(srcAddr); - AtomAndOffset fromao = findAtomAndOffset(nextRelocValue); - AtomAndOffset toao = findAtomAndOffset(dstAddr); - // check for addend encoded in the section content - //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n", - // dstAddr, nextRelocValue, contentAddr); - if ( (dstAddr - nextRelocValue) != contentAddr ) { - if ( toao.atom == srcao.atom ) - toao.offset += (contentAddr + nextRelocValue) - dstAddr; - else if ( fromao.atom == srcao.atom ) - toao.offset += (contentAddr + nextRelocValue) - dstAddr; - else - fromao.offset += (dstAddr - contentAddr) - nextRelocValue; - } - //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n", - // srcao.atom->getDisplayName(), srcao.offset, - // fromao.atom->getDisplayName(), fromao.offset, - // toao.atom->getDisplayName(), toao.offset); - new Reference(kind, srcao, fromao, toao); - } - break; - case GENERIC_RELOC_PAIR: - // do nothing, already used via a look ahead - break; - default: - warning("unknown scattered relocation type %d", sreloc->r_type()); - } - } - return result; -} - -template <> -bool Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) -{ - uint64_t srcAddr; - uint64_t dstAddr = 0; - uint64_t addend; - uint32_t* fixUpPtr; - x86_64::ReferenceKinds kind = x86_64::kNoFixUp; - bool result = false; - const macho_nlist

* targetSymbol = NULL; - const char* targetName = NULL; - srcAddr = sect->addr() + reloc->r_address(); - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); - //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address()); - if ( reloc->r_extern() ) { - targetSymbol = &fSymbols[reloc->r_symbolnum()]; - targetName = &fStrings[targetSymbol->n_strx()]; - } - switch ( reloc->r_type() ) { - case X86_64_RELOC_UNSIGNED: - if ( reloc->r_pcrel() ) - throw "pcrel and X86_64_RELOC_UNSIGNED not supported"; - switch ( reloc->r_length() ) { - case 0: - case 1: - throw "length < 2 and X86_64_RELOC_UNSIGNED not supported"; - case 2: - kind = x86_64::kPointer32; - break; - case 3: - if ( reloc->r_extern() && isWeakImportSymbol(targetSymbol) ) - kind = x86_64::kPointerWeakImport; - else - kind = x86_64::kPointer; - break; - } - dstAddr = E::get64(*((uint64_t*)fixUpPtr)); - if ( reloc->r_extern() ) { - makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr); - } - else { - makeReference(kind, srcAddr, dstAddr); - // verify that dstAddr is in the section being targeted - int sectNum = reloc->r_symbolnum(); - const macho_section

* const sectionsStart = (macho_section

*)((char*)fSegment + sizeof(macho_segment_command

)); - const macho_section

* const targetSection = §ionsStart[sectNum-1]; - if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) { - throwf("local relocation for address 0x%08llX in section %s does not target section %s", - srcAddr, sect->sectname(), targetSection->sectname()); - } - } - break; - case X86_64_RELOC_SIGNED: - case X86_64_RELOC_SIGNED_1: - case X86_64_RELOC_SIGNED_2: - case X86_64_RELOC_SIGNED_4: - if ( ! reloc->r_pcrel() ) - throw "not pcrel and X86_64_RELOC_SIGNED* not supported"; - if ( reloc->r_length() != 2 ) - throw "length != 2 and X86_64_RELOC_SIGNED* not supported"; - addend = (int64_t)((int32_t)(E::get32(*fixUpPtr))); - if ( reloc->r_extern() ) { - switch ( reloc->r_type() ) { - case X86_64_RELOC_SIGNED: - kind = x86_64::kPCRel32; - // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created - if ( addend == (uint64_t)(-1) ) { - addend = 0; - kind = x86_64::kPCRel32_1; - } - else if ( addend == (uint64_t)(-2) ) { - addend = 0; - kind = x86_64::kPCRel32_2; - } - else if ( addend == (uint64_t)(-4) ) { - addend = 0; - kind = x86_64::kPCRel32_4; - } - break; - // end support for old .o files before X86_64_RELOC_SIGNED_1 was created - case X86_64_RELOC_SIGNED_1: - kind = x86_64::kPCRel32_1; - addend += 1; - break; - case X86_64_RELOC_SIGNED_2: - kind = x86_64::kPCRel32_2; - addend += 2; - break; - case X86_64_RELOC_SIGNED_4: - kind = x86_64::kPCRel32_4; - addend += 4; - break; - } - makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend); - } - else { - uint64_t ripRelativeOffset = addend; - switch ( reloc->r_type() ) { - case X86_64_RELOC_SIGNED: - dstAddr = srcAddr + 4 + ripRelativeOffset; - kind = x86_64::kPCRel32; - break; - case X86_64_RELOC_SIGNED_1: - dstAddr = srcAddr + 5 + ripRelativeOffset; - kind = x86_64::kPCRel32_1; - break; - case X86_64_RELOC_SIGNED_2: - dstAddr = srcAddr + 6 + ripRelativeOffset; - kind = x86_64::kPCRel32_2; - break; - case X86_64_RELOC_SIGNED_4: - dstAddr = srcAddr + 8 + ripRelativeOffset; - kind = x86_64::kPCRel32_4; - break; - } - makeReference(kind, srcAddr, dstAddr); - // verify that dstAddr is in the section being targeted - int sectNum = reloc->r_symbolnum(); - const macho_section

* const sectionsStart = (macho_section

*)((char*)fSegment + sizeof(macho_segment_command

)); - const macho_section

* const targetSection = §ionsStart[sectNum-1]; - if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) { - throwf("local relocation for address 0x%08llX in section %s does not target section %s", - srcAddr, sect->sectname(), targetSection->sectname()); - } - } - break; - case X86_64_RELOC_BRANCH: - if ( ! reloc->r_pcrel() ) - throw "not pcrel and X86_64_RELOC_BRANCH not supported"; - if ( reloc->r_length() == 2 ) { - dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr))); - if ( reloc->r_extern() ) { - if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { - makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { - makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( isWeakImportSymbol(targetSymbol) ) - makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr); - else - makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr); - } - else { - makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr); - } - } - else if ( reloc->r_length() == 0 ) { - dstAddr = *((int8_t*)fixUpPtr); - if ( reloc->r_extern() ) { - makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr); - } - else { - makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr); - } - } - else { - throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());; - } - break; - case X86_64_RELOC_GOT: - if ( ! reloc->r_extern() ) - throw "not extern and X86_64_RELOC_GOT not supported"; - if ( ! reloc->r_pcrel() ) - throw "not pcrel and X86_64_RELOC_GOT not supported"; - if ( reloc->r_length() != 2 ) - throw "length != 2 and X86_64_RELOC_GOT not supported"; - addend = (int64_t)((int32_t)(E::get32(*fixUpPtr))); - if ( isWeakImportSymbol(targetSymbol) ) - makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend); - else - makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend); - break; - case X86_64_RELOC_GOT_LOAD: - if ( ! reloc->r_extern() ) - throw "not extern and X86_64_RELOC_GOT_LOAD not supported"; - if ( ! reloc->r_pcrel() ) - throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported"; - if ( reloc->r_length() != 2 ) - throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported"; - addend = (int64_t)((int32_t)(E::get32(*fixUpPtr))); - if ( isWeakImportSymbol(targetSymbol) ) - makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend); - else - makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend); - break; - case X86_64_RELOC_SUBTRACTOR: - { - if ( reloc->r_pcrel() ) - throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative"; - if ( reloc->r_length() < 2 ) - throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3"; - if ( !reloc->r_extern() ) - throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1"; - const macho_relocation_info* nextReloc = &reloc[1]; - if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED ) - throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED"; - result = true; - if ( nextReloc->r_pcrel() ) - throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative"; - if ( nextReloc->r_length() != reloc->r_length() ) - throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length"; - Reference* ref; - bool negativeAddend; - if ( reloc->r_length() == 2 ) { - kind = x86_64::kPointerDiff32; - dstAddr = E::get32(*fixUpPtr); // addend is in content - negativeAddend = ((dstAddr & 0x80000000) != 0); - } - else { - kind = x86_64::kPointerDiff; - dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content - negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0); - } - AtomAndOffset inAtomAndOffset = this->findAtomAndOffset(srcAddr); - ObjectFile::Atom* inAtom = inAtomAndOffset.atom; - // create reference with "to" target - if ( nextReloc->r_extern() ) { - const macho_nlist

* targetSymbol = &fSymbols[nextReloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0); - // if "to" is in this atom, change by-name to a direct reference - if ( strcmp(targetName, inAtom->getName()) == 0 ) - ref->setTarget(*inAtom, 0); - } - else { - ref = makeReference(kind, srcAddr, dstAddr); - } - // add in "from" target - if ( reloc->r_extern() ) { - const macho_nlist

* targetFromSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()]; - if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) { - // from target is translation unit scoped, so use a direct reference - ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom)); - } - else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) { - // if "from" is in this atom, change by-name to a direct reference - ref->setFromTarget(*inAtom); - } - else { - // some non-static other atom - ref->setFromTargetName(fromTargetName); - } - } - else { - throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0"; - } - // addend goes in from side iff negative - if ( negativeAddend ) - ref->setFromTargetOffset(-dstAddr); - else - ref->setToTargetOffset(dstAddr); - break; - } - default: - warning("unknown relocation type %d", reloc->r_type()); - } - return result; -} - - -/// Reader::addRelocReference - -/// turns arm relocation entries into references. Returns true if the next -/// relocation should be skipped, false otherwise. -template <> -bool Reader::addRelocReference(const macho_section* sect, - const macho_relocation_info* reloc) -{ - uint32_t * fixUpPtr; - int32_t displacement; - uint32_t instruction = 0; - bool result = false; - uint32_t srcAddr; - uint32_t dstAddr; - uint32_t pointerValue; - arm::ReferenceKinds kind = arm::kNoFixUp; - - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - // non-scattered relocation - const char* targetName = NULL; - bool weakImport = false; - - srcAddr = sect->addr() + reloc->r_address(); - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); - if ( reloc->r_type() != ARM_RELOC_PAIR ) - instruction = LittleEndian::get32(*fixUpPtr); - - if ( reloc->r_extern() ) { - const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - targetName = &fStrings[targetSymbol->n_strx()]; - weakImport = this->isWeakImportSymbol(targetSymbol); - } - - switch ( reloc->r_type() ) { - case ARM_RELOC_BR24: - // Sign-extend displacement - displacement = (instruction & 0x00FFFFFF) << 2; - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - // The pc added will be +8 from the pc - displacement += 8; - // If this is BLX add H << 1 - if ((instruction & 0xFE000000) == 0xFA000000) - displacement += ((instruction & 0x01000000) >> 23); - - if ( reloc->r_extern() ) { - uint32_t offsetInTarget = srcAddr + displacement; - if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { - makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { - makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else if ( weakImport ) - makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget); - else - makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget); - } - else { - dstAddr = srcAddr + displacement; - ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom; - // check for dtrace probes and weak_import stubs - const char* targetName = atom->getName(); - if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { - makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { - makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) - && ((AnonymousAtom*)atom)->isWeakImportStub() ) - makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr); - else if ( reloc->r_symbolnum() != R_ABS ) - makeReference(arm::kBranch24, srcAddr, dstAddr); - else { - // find absolute symbol that corresponds to pointerValue - AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0); - else - throwf("R_ABS reloc but no absolute symbol at target address"); - } - } - break; - - case ARM_THUMB_RELOC_BR22: - // thumb2 added two more bits to displacement, complicating the displacement decoding - { - uint32_t s = (instruction >> 10) & 0x1; - uint32_t j1 = (instruction >> 29) & 0x1; - uint32_t j2 = (instruction >> 27) & 0x1; - uint32_t imm10 = instruction & 0x3FF; - uint32_t imm11 = (instruction >> 16) & 0x7FF; - uint32_t i1 = (j1 == s); - uint32_t i2 = (j2 == s); - uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); - int32_t sdis = dis; - if ( s ) - sdis |= 0xFE000000; - displacement = sdis; - } - // The pc added will be +4 from the pc - displacement += 4; - // If the instruction was blx, force the low 2 bits to be clear - dstAddr = srcAddr + displacement; - if ((instruction & 0xF8000000) == 0xE8000000) - dstAddr &= 0xFFFFFFFC; - - if ( reloc->r_extern() ) { - uint32_t offsetInTarget = dstAddr; - if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) { - makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) { - makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else if ( weakImport ) - makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget); - else - makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget); - } - else { - ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom; - // check for dtrace probes and weak_import stubs - const char* targetName = atom->getName(); - if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) { - makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[16]); - } - else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) { - makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0); - addDtraceExtraInfos(srcAddr, &targetName[20]); - } - else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) - && ((AnonymousAtom*)atom)->isWeakImportStub() ) - makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr); - else if ( reloc->r_symbolnum() != R_ABS ) - makeReference(arm::kThumbBranch22, srcAddr, dstAddr); - else { - // find absolute symbol that corresponds to pointerValue - AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr); - if ( pos != fAddrToAbsoluteAtom.end() ) - makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0); - else - throwf("R_ABS reloc but no absolute symbol at target address"); - } - } - break; - - case ARM_RELOC_VANILLA: - if ( reloc->r_length() != 2 ) - throw "bad length for ARM_RELOC_VANILLA"; - - pointerValue = instruction; - kind = arm::kPointer; - if ( strcmp(sect->segname(), "__TEXT") == 0 ) - kind = arm::kReadOnlyPointer; - if ( weakImport ) - kind = arm::kPointerWeakImport; - if ( reloc->r_extern() ) { - const macho_nlist

* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - if ( (targetSymbol->n_desc() & N_ARM_THUMB_DEF) && (pointerValue == 1) ) - pointerValue = 0; - makeByNameReference(kind, srcAddr, targetName, pointerValue); - } - else { - AtomAndOffset at = findAtomAndOffset(srcAddr); - AtomAndOffset to = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()); - if ( to.atom->isThumb() ) - to.offset &= -2; - new Reference(kind, at, to); - } - break; - - case ARM_THUMB_32BIT_BRANCH: - // ignore old unnecessary relocs - break; - - default: - warning("unexpected relocation type %u", reloc->r_type()); - break; - } - } - else { - const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; - int32_t addend; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - uint32_t betterDstAddr; - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); - instruction = LittleEndian::get32(*fixUpPtr); - - // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF} - // relocation types, and it is an error to see one otherwise. - bool nextRelocIsPair = false; - uint32_t nextRelocAddress = 0; - uint32_t nextRelocValue = 0; - if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextSReloc->r_address(); - nextRelocValue = nextSReloc->r_value(); - result = true; - } - - switch (sreloc->r_type()) { - case ARM_RELOC_VANILLA: - if ( sreloc->r_length() != 2 ) - throw "bad length for ARM_RELOC_VANILLA"; - - //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr); - betterDstAddr = LittleEndian::get32(*fixUpPtr); - kind = arm::kPointer; - if ( strcmp(sect->segname(), "__TEXT") == 0 ) - kind = arm::kReadOnlyPointer; - // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) - makeReferenceWithToBase(kind, srcAddr, betterDstAddr, dstAddr); - break; - - case ARM_RELOC_BR24: - // Sign-extend displacement - displacement = (instruction & 0x00FFFFFF) << 2; - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - // The pc added will be +8 from the pc - displacement += 8; - // If this is BLX add H << 1 - if ((instruction & 0xFE000000) == 0xFA000000) - displacement += ((instruction & 0x01000000) >> 23); - betterDstAddr = srcAddr+displacement; - makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr); - break; - - case ARM_THUMB_RELOC_BR22: - // thumb2 added two more bits to displacement, complicating the displacement decoding - { - uint32_t s = (instruction >> 10) & 0x1; - uint32_t j1 = (instruction >> 29) & 0x1; - uint32_t j2 = (instruction >> 27) & 0x1; - uint32_t imm10 = instruction & 0x3FF; - uint32_t imm11 = (instruction >> 16) & 0x7FF; - uint32_t i1 = (j1 == s); - uint32_t i2 = (j2 == s); - uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); - int32_t sdis = dis; - if ( s ) - sdis |= 0xFE000000; - displacement = sdis; - } - // The pc added will be +4 from the pc - displacement += 4; - betterDstAddr = srcAddr+displacement; - // If the instruction was blx, force the low 2 bits to be clear - if ((instruction & 0xF8000000) == 0xE8000000) - betterDstAddr &= 0xFFFFFFFC; - makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr); - break; - - case ARM_RELOC_SECTDIFF: - case ARM_RELOC_LOCAL_SECTDIFF: - if ( !nextRelocIsPair ) { - throw "ARM_RELOC_SECTDIFF missing following pair"; - } - if ( sreloc->r_length() != 2 ) - throw "bad length for ARM_RELOC_SECTDIFF"; - { - AtomAndOffset srcao = findAtomAndOffset(srcAddr); - AtomAndOffset fromao = findAtomAndOffset(nextRelocValue); - AtomAndOffset toao = findAtomAndOffset(dstAddr); - // check for addend encoded in the section content - pointerValue = LittleEndian::get32(*fixUpPtr); - addend = pointerValue - (dstAddr - nextRelocValue); - if ( toao.atom->isThumb() && (addend & 1) ) - addend &= -2; // remove thumb bit - if ( (dstAddr - nextRelocValue) != pointerValue ) { - if ( fromao.atom == srcao.atom ) { - if ( ((const macho_section

*)(((BaseAtom*)(srcao.atom))->getSectionRecord()))->flags() & S_ATTR_PURE_INSTRUCTIONS ) { - int pcBaseOffset = srcao.atom->isThumb() ? 4 : 8; - if ( addend == -pcBaseOffset ) { - fromao.offset -= addend; - } - else { - toao.offset += addend; - } - } - else { - toao.offset += addend; - } - } - else if ( toao.atom == srcao.atom ) - toao.offset += addend; - else - fromao.offset -= addend; - } - new Reference(arm::kPointerDiff, srcao, fromao, toao); - } - break; - - default: - warning("unexpected srelocation type %u", sreloc->r_type()); - break; - } - } - return result; -} - -template -void Reader::addReferencesForSection(const macho_section

* sect) -{ - // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change - if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) { - switch ( sect->flags() & SECTION_TYPE ) { - case S_SYMBOL_STUBS: - case S_LAZY_SYMBOL_POINTERS: - // we ignore compiler generated stubs, so ignore those relocs too - break; - default: - // ignore all relocations in __eh_frame section - if ( sect == fehFrameSection ) - return; - const macho_relocation_info

* relocs = (macho_relocation_info

*)((char*)(fHeader) + sect->reloff()); - const uint32_t relocCount = sect->nreloc(); - //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname()); - for (uint32_t r = 0; r < relocCount; ++r) { - try { - if ( addRelocReference(sect, &relocs[r]) ) - ++r; // skip next - } - catch (const char* msg) { - throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg); - } - } - } - } -} - - -template <> -const char* Reference::getDescription() const -{ - static char temp[2048]; - switch( fKind ) { - case x86::kNoFixUp: - sprintf(temp, "reference to "); - break; - case x86::kFollowOn: - sprintf(temp, "followed by "); - break; - case x86::kGroupSubordinate: - sprintf(temp, "group subordinate "); - break; - case x86::kPointerWeakImport: - sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc); - break; - case x86::kPointer: - sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc); - break; - case x86::kPointerDiff: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - break; - case x86::kPointerDiff16: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - break; - case x86::kPCRel32WeakImport: - sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc); - break; - case x86::kPCRel32: - sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc); - break; - case x86::kPCRel16: - sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc); - break; - case x86::kPCRel8: - sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc); - break; - case x86::kAbsolute32: - sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc); - break; - case x86::kImageOffset32: - sprintf(temp, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc); - break; - case x86::kPointerDiff24: - sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)", - fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset, - this->getFromTargetDisplayName(), fFromTarget.offset ); - return temp; - break; - case x86::kSectionOffset24: - sprintf(temp, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc); - break; - case x86::kDtraceProbe: - sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); - break; - case x86::kDtraceProbeSite: - sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc); - break; - case x86::kDtraceIsEnabledSite: - sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc); - break; - case x86::kDtraceTypeReference: - sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc); - break; - } - // always quote by-name references - if ( fToTargetName != NULL ) { - strcat(temp, "\""); - strcat(temp, fToTargetName); - strcat(temp, "\""); - } - else if ( fToTarget.atom != NULL ) { - strcat(temp, fToTarget.atom->getDisplayName()); - } - else { - strcat(temp, "NULL target"); - } - if ( fToTarget.offset != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset); - - return temp; -} - - -template <> -const char* Reference::getDescription() const -{ - static char temp[2048]; - switch( fKind ) { - case ppc::kNoFixUp: - sprintf(temp, "reference to "); - break; - case ppc::kFollowOn: - sprintf(temp, "followed by "); - break; - case ppc::kGroupSubordinate: - sprintf(temp, "group subordinate "); - break; - case ppc::kPointerWeakImport: - sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc); - break; - case ppc::kPointer: - sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc); - break; - case ppc::kPointerDiff16: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case ppc::kPointerDiff32: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case ppc::kPointerDiff64: - throw "unsupported refrence kind"; - break; - case ppc::kBranch24WeakImport: - sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc); - break; - case ppc::kBranch24: - case ppc::kBranch14: - sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc); - break; - case ppc::kPICBaseLow16: - sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset); - break; - case ppc::kPICBaseLow14: - sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset); - break; - case ppc::kPICBaseHigh16: - sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset); - break; - case ppc::kAbsLow16: - sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc::kAbsLow14: - sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc::kAbsHigh16: - sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc::kAbsHigh16AddLow: - sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc::kDtraceProbe: - sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); - break; - case ppc::kDtraceProbeSite: - sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc); - break; - case ppc::kDtraceIsEnabledSite: - sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc); - break; - case ppc::kDtraceTypeReference: - sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc); - break; - } - // always quote by-name references - if ( fToTargetName != NULL ) { - strcat(temp, "\""); - strcat(temp, fToTargetName); - strcat(temp, "\""); - } - else if ( fToTarget.atom != NULL ) { - strcat(temp, fToTarget.atom->getDisplayName()); - } - else { - strcat(temp, "NULL target"); - } - if ( fToTarget.offset != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset); - - return temp; -} - -template <> -const char* Reference::getDescription() const -{ - static char temp[2048]; - switch( fKind ) { - case ppc64::kNoFixUp: - sprintf(temp, "reference to "); - break; - case ppc64::kFollowOn: - sprintf(temp, "followed by "); - break; - case ppc64::kGroupSubordinate: - sprintf(temp, "group subordinate "); - break; - case ppc64::kPointerWeakImport: - sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc); - break; - case ppc64::kPointer: - sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc); - break; - case ppc64::kPointerDiff64: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case ppc64::kPointerDiff32: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case ppc64::kPointerDiff16: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case ppc64::kBranch24WeakImport: - sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc); - break; - case ppc64::kBranch24: - case ppc64::kBranch14: - sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc); - break; - case ppc64::kPICBaseLow16: - sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset); - break; - case ppc64::kPICBaseLow14: - sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset); - break; - case ppc64::kPICBaseHigh16: - sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset); - break; - case ppc64::kAbsLow16: - sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc64::kAbsLow14: - sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc64::kAbsHigh16: - sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc64::kAbsHigh16AddLow: - sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc); - break; - case ppc64::kDtraceProbe: - sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc); - break; - case ppc64::kDtraceProbeSite: - sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc); - break; - case ppc64::kDtraceIsEnabledSite: - sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc); - break; - case ppc64::kDtraceTypeReference: - sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc); - break; - } - // always quote by-name references - if ( fToTargetName != NULL ) { - strcat(temp, "\""); - strcat(temp, fToTargetName); - strcat(temp, "\""); - } - else if ( fToTarget.atom != NULL ) { - strcat(temp, fToTarget.atom->getDisplayName()); - } - else { - strcat(temp, "NULL target"); - } - if ( fToTarget.offset != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset()); - - return temp; -} - - -template <> -const char* Reference::getDescription() const -{ - static char temp[2048]; - switch( fKind ) { - case x86_64::kNoFixUp: - sprintf(temp, "reference to "); - break; - case x86_64::kFollowOn: - sprintf(temp, "followed by "); - break; - case x86_64::kGroupSubordinate: - sprintf(temp, "group subordinate "); - break; - case x86_64::kPointerWeakImport: - sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc); - break; - case x86_64::kPointer: - sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc); - break; - case x86_64::kPointer32: - sprintf(temp, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc); - break; - case x86_64::kPointerDiff32: - case x86_64::kPointerDiff: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit"; - sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)", - fFixUpOffsetInSrc, size, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - break; - case x86_64::kPCRel32: - sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32_1: - sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32_2: - sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32_4: - sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc); - break; - case x86_64::kBranchPCRel32: - sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc); - break; - case x86_64::kBranchPCRel32WeakImport: - sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32GOT: - sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32GOTWeakImport: - sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32GOTLoad: - sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc); - break; - case x86_64::kPCRel32GOTLoadWeakImport: - sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc); - break; - case x86_64::kGOTNoFixUp: - sprintf(temp, "reference to GOT entry for "); - break; - case x86_64::kBranchPCRel8: - sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc); - break; - case x86_64::kPointerDiff24: - sprintf(temp, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)", - fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset, - this->getFromTargetDisplayName(), fFromTarget.offset ); - return temp; - case x86_64::kImageOffset32: - sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc); - break; - case x86_64::kSectionOffset24: - sprintf(temp, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc); - break; - case x86_64::kDtraceProbe: - sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc); - break; - case x86_64::kDtraceProbeSite: - sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc); - break; - case x86_64::kDtraceIsEnabledSite: - sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc); - break; - case x86_64::kDtraceTypeReference: - sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc); - break; - } - // always quote by-name references - if ( fToTargetName != NULL ) { - strcat(temp, "\""); - strcat(temp, fToTargetName); - strcat(temp, "\""); - } - else if ( fToTarget.atom != NULL ) { - strcat(temp, fToTarget.atom->getDisplayName()); - } - else { - strcat(temp, "NULL target"); - } - if ( fToTarget.offset != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset()); - - return temp; -} - - -template <> -const char* Reference::getDescription() const -{ - static char temp[2048]; - switch( fKind ) { - case arm::kNoFixUp: - sprintf(temp, "reference to "); - break; - case arm::kFollowOn: - sprintf(temp, "followed by "); - break; - case arm::kGroupSubordinate: - sprintf(temp, "group subordinate "); - break; - case arm::kPointer: - sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc); - break; - case arm::kPointerWeakImport: - sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc); - break; - case arm::kPointerDiff: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case arm::kPointerDiff12: - { - // by-name references have quoted names - const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : ""; - const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : ""; - sprintf(temp, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)", - fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset, - fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset ); - return temp; - } - case arm::kReadOnlyPointer: - sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc); - break; - case arm::kBranch24: - case arm::kThumbBranch22: - sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc); - break; - case arm::kBranch24WeakImport: - case arm::kThumbBranch22WeakImport: - sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc); - break; - case arm::kDtraceProbe: - sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc); - break; - case arm::kDtraceProbeSite: - sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc); - break; - case arm::kDtraceIsEnabledSite: - sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc); - break; - case arm::kDtraceTypeReference: - sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc); - break; - } - // always quote by-name references - if ( fToTargetName != NULL ) { - strcat(temp, "\""); - strcat(temp, fToTargetName); - strcat(temp, "\""); - } - else if ( fToTarget.atom != NULL ) { - strcat(temp, fToTarget.atom->getDisplayName()); - } - else { - strcat(temp, "NULL target"); - } - if ( fToTarget.offset != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset); - - return temp; -} - - -template <> -bool Reference::isBranch() const -{ - switch ( fKind ) { - case x86::kPCRel32: - case x86::kPCRel32WeakImport: - return true; - default: - return false; - } -} - -template <> -bool Reference::isBranch() const -{ - switch ( fKind ) { - case x86_64::kBranchPCRel32: - case x86_64::kBranchPCRel32WeakImport: - return true; - default: - return false; - } -} - -template <> -bool Reference::isBranch() const -{ - switch ( fKind ) { - case ppc::kBranch24: - case ppc::kBranch24WeakImport: - return true; - default: - return false; - } -} - -template <> -bool Reference::isBranch() const -{ - switch ( fKind ) { - case ppc64::kBranch24: - case ppc64::kBranch24WeakImport: - return true; - default: - return false; - } -} - -template <> -bool Reference::isBranch() const -{ - switch ( fKind ) { - case arm::kBranch24: - case arm::kBranch24WeakImport: - case arm::kThumbBranch22: - case arm::kThumbBranch22WeakImport: - return true; - default: - return false; - } -} - - - -}; // namespace relocatable -}; // namespace mach_o - -#endif // __OBJECT_FILE_MACH_O__