1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __OBJECT_FILE_MACH_O__
26 #define __OBJECT_FILE_MACH_O__
31 #include <sys/param.h>
37 #include "MachOFileAbstraction.hpp"
38 #include "Architectures.hpp"
39 #include "ObjectFile.h"
41 #include "debugline.h"
43 #include <libunwind/DwarfInstructions.hpp>
44 #include <libunwind/AddressSpace.hpp>
45 #include <libunwind/Registers.hpp>
49 // To implement architecture xxx, you must write template specializations for the following six methods:
50 // Reader<xxx>::validFile()
51 // Reader<xxx>::validSectionType()
52 // Reader<xxx>::addRelocReference()
53 // Reference<xxx>::getDescription()
59 extern __attribute__((noreturn)) void throwf(const char* format, ...);
60 extern void warning(const char* format, ...);
63 namespace relocatable {
70 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
72 return ( left->getFixUpOffset() < right->getFixUpOffset() );
78 template <typename A> class Reader;
82 AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
83 AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
84 ObjectFile::Atom* atom;
90 class Reference : public ObjectFile::Reference
93 typedef typename A::P P;
94 typedef typename A::P::uint_t pint_t;
95 typedef typename A::ReferenceKinds Kinds;
97 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
98 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
99 Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
101 virtual ~Reference() {}
104 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const;
105 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const;
106 virtual uint8_t getKind() const { return (uint8_t)fKind; }
107 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
108 virtual const char* getTargetName() const { return (fToTarget.atom != NULL) ? fToTarget.atom->getName() : fToTargetName; }
109 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
110 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
111 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
112 virtual const char* getFromTargetName() const { return (fFromTarget.atom != NULL) ? fFromTarget.atom->getName() : fFromTargetName; }
113 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = ⌖ fToTarget.offset = offset; }
114 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
115 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = ⌖ }
116 virtual void setFromTargetName(const char* name) { fFromTargetName = name; }
117 virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; }
118 virtual const char* getDescription() const;
119 virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; }
120 virtual bool isBranch() const;
121 virtual const char* getTargetDisplayName() const { return (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName; }
122 virtual const char* getFromTargetDisplayName() const { return (fFromTarget.atom != NULL) ? fFromTarget.atom->getDisplayName() : fFromTargetName; }
124 static bool fgForFinalLinkedImage;
127 pint_t fFixUpOffsetInSrc;
128 AtomAndOffset fToTarget;
129 AtomAndOffset fFromTarget;
130 const char* fToTargetName;
131 const char* fFromTargetName;
137 template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
139 template <typename A>
140 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
141 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
144 // make reference a by-name unless:
145 // - the reference type is only used with direct references
146 // - the target is translation unit scoped
147 // - the target kind is not regular (is weak or tentative)
148 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
149 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
150 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
151 && (toTarget.atom != at.atom) ) {
152 fToTargetName = toTarget.atom->getName();
153 //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());
154 fToTarget.atom = NULL;
156 ((class BaseAtom*)at.atom)->addReference(this);
157 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
160 template <typename A>
161 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
162 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
163 fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
165 // make reference a by-name where needed
166 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
167 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
168 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
169 && (toTarget.atom != at.atom) ) {
170 fToTargetName = toTarget.atom->getName();
171 fToTarget.atom = NULL;
173 ((class BaseAtom*)at.atom)->addReference(this);
174 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
175 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
178 template <typename A>
179 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
180 : fFixUpOffsetInSrc(at.offset),
181 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
183 fToTarget.offset = toOffset;
184 ((class BaseAtom*)at.atom)->addReference(this);
187 template <typename A>
188 ObjectFile::Reference::TargetBinding Reference<A>::getTargetBinding() const
190 if ( fgForFinalLinkedImage ) {
191 if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) )
192 return ObjectFile::Reference::kDontBind;
194 if ( fToTarget.atom == NULL )
195 return ObjectFile::Reference::kUnboundByName;
196 if ( fToTargetName == NULL )
197 return ObjectFile::Reference::kBoundDirectly;
199 return ObjectFile::Reference::kBoundByName;
202 template <typename A>
203 ObjectFile::Reference::TargetBinding Reference<A>::getFromTargetBinding() const
205 if ( fFromTarget.atom == NULL ) {
206 if ( fFromTargetName == NULL )
207 return ObjectFile::Reference::kDontBind;
209 return ObjectFile::Reference::kUnboundByName;
212 if ( fFromTargetName == NULL )
213 return ObjectFile::Reference::kBoundDirectly;
215 return ObjectFile::Reference::kBoundByName;
221 template <typename A>
222 class Segment : public ObjectFile::Segment
225 Segment(const macho_section<typename A::P>* sect);
226 virtual const char* getName() const { return fSection->segname(); }
227 virtual bool isContentReadable() const { return true; }
228 virtual bool isContentWritable() const { return fWritable; }
229 virtual bool isContentExecutable() const { return fExecutable; }
231 const macho_section<typename A::P>* fSection;
236 template <typename A>
237 Segment<A>::Segment(const macho_section<typename A::P>* sect)
238 : fSection(sect), fWritable(true), fExecutable(false)
240 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
244 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
251 class DataSegment : public ObjectFile::Segment
254 virtual const char* getName() const { return "__DATA"; }
255 virtual bool isContentReadable() const { return true; }
256 virtual bool isContentWritable() const { return true; }
257 virtual bool isContentExecutable() const { return false; }
259 static DataSegment fgSingleton;
262 DataSegment DataSegment::fgSingleton;
264 class LinkEditSegment : public ObjectFile::Segment
267 virtual const char* getName() const { return "__LINKEDIT"; }
268 virtual bool isContentReadable() const { return true; }
269 virtual bool isContentWritable() const { return false; }
270 virtual bool isContentExecutable() const { return false; }
272 static LinkEditSegment fgSingleton;
275 LinkEditSegment LinkEditSegment::fgSingleton;
277 class BaseAtom : public ObjectFile::Atom
280 BaseAtom() : fStabsStartIndex(0), fStabsCount(0), fHasCompactUnwindInfo(false) {}
282 virtual void setSize(uint64_t size) = 0;
283 virtual void addReference(ObjectFile::Reference* ref) = 0;
284 virtual void sortReferences() = 0;
285 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
286 virtual const ObjectFile::ReaderOptions& getOptions() const = 0;
287 virtual uint64_t getObjectAddress() const = 0;
288 virtual uint32_t getOrdinal() const { return fOrdinal; }
289 virtual void setOrdinal(uint32_t value) { fOrdinal = value; }
290 virtual const void* getSectionRecord() const = 0;
291 virtual unsigned int getSectionIndex() const = 0;
292 virtual bool isAlias() const { return false; }
293 virtual uint8_t getLSDAReferenceKind() const { return 0; }
294 virtual uint8_t getPersonalityReferenceKind() const { return 0; }
295 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress) { return 0; }
296 virtual ObjectFile::UnwindInfo::iterator beginUnwind() { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[0] : NULL; }
297 virtual ObjectFile::UnwindInfo::iterator endUnwind() { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[1] : NULL; }
298 virtual ObjectFile::Reference* getLSDA();
299 virtual Atom* getPersonalityPointer();
300 virtual void setCompactUnwindEncoding(uint64_t ehAtomAddress);
302 uint32_t fStabsStartIndex;
303 uint32_t fStabsCount;
305 ObjectFile::UnwindInfo fSingleUnwindInfo[1];
306 bool fHasCompactUnwindInfo;
310 ObjectFile::Reference* BaseAtom::getLSDA()
312 const uint8_t groupKind = this->getLSDAReferenceKind();
313 const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
314 for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
315 ObjectFile::Reference* ref = *it;
316 if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kLSDAType) ) {
323 ObjectFile::Atom* BaseAtom::getPersonalityPointer()
325 const uint8_t personalityKind = this->getPersonalityReferenceKind();
326 const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
327 for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
328 ObjectFile::Reference* ref = *it;
329 if ( ref->getKind() == personalityKind ) {
330 if ( strcmp(ref->getTarget().getSectionName(), "__nl_symbol_ptr") == 0 )
331 return &ref->getTarget();
332 if ( strcmp(ref->getTarget().getSectionName(), "__pointers") == 0 )
333 return &ref->getTarget();
340 void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress)
342 fSingleUnwindInfo[0].unwindInfo = this->getCompactUnwindEncoding(ehAtomAddress);
343 fHasCompactUnwindInfo = true;
350 bool operator()(const class BaseAtom* left, const class BaseAtom* right) {
353 uint64_t leftAddr = left->getObjectAddress();
354 uint64_t rightAddr = right->getObjectAddress();
355 if ( leftAddr < rightAddr ) {
358 else if ( leftAddr > rightAddr ) {
362 // if they have same address, one might be the end of a section and the other the start of the next section
363 const void* leftSection = left->getSectionRecord();
364 const void* rightSection = right->getSectionRecord();
365 if ( leftSection != rightSection ) {
366 return ( leftSection < rightSection );
368 // if they have same address and section, one might be an alias
369 bool leftAlias = left->isAlias();
370 bool rightAlias = right->isAlias();
371 if ( leftAlias && rightAlias ) {
372 // sort multiple aliases for same address first by scope
373 ObjectFile::Atom::Scope leftScope = left->getScope();
374 ObjectFile::Atom::Scope rightScope = right->getScope();
375 if ( leftScope != rightScope ) {
376 return ( leftScope < rightScope );
378 // sort multiple aliases for same address then by name
379 return ( strcmp(left->getName(), right->getName()) < 0 );
381 else if ( leftAlias ) {
384 else if ( rightAlias ) {
387 // one might be a section start or end label
388 switch ( left->getContentType() ) {
389 case ObjectFile::Atom::kSectionStart:
391 case ObjectFile::Atom::kSectionEnd:
396 switch ( right->getContentType() ) {
397 case ObjectFile::Atom::kSectionStart:
399 case ObjectFile::Atom::kSectionEnd:
404 // they could be tentative defintions
405 switch ( left->getDefinitionKind() ) {
406 case ObjectFile::Atom::kTentativeDefinition:
407 // sort tentative definitions by name
408 return ( strcmp(left->getName(), right->getName()) < 0 );
409 case ObjectFile::Atom::kAbsoluteSymbol:
410 // sort absolute symbols with same address by name
411 return ( strcmp(left->getName(), right->getName()) < 0 );
413 // hack for rdar://problem/5102873
414 if ( !left->isZeroFill() || !right->isZeroFill() )
415 warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath());
425 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
426 // pointing to it. A C function or global variable is represented by one of these atoms.
429 template <typename A>
430 class SymbolAtom : public BaseAtom
433 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
434 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
435 { return fOwner.getTranslationUnitSource(dir, name); }
436 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
437 virtual const char* getDisplayName() const { return getName(); }
438 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
439 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
440 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
441 virtual ObjectFile::Atom::ContentType getContentType() const { return fType; }
442 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
443 virtual bool dontDeadStrip() const;
444 virtual bool isZeroFill() const;
445 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
446 virtual uint64_t getSize() const { return fSize; }
447 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
448 virtual bool mustRemainInSection() const { return true; }
449 virtual const char* getSectionName() const;
450 virtual Segment<A>& getSegment() const { return *fSegment; }
451 virtual ObjectFile::Atom& getFollowOnAtom() const;
452 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
453 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
454 virtual void copyRawContent(uint8_t buffer[]) const;
455 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
456 virtual void setSize(uint64_t size);
457 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
458 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
459 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
460 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
461 virtual uint64_t getObjectAddress() const { return fAddress; }
462 virtual const void* getSectionRecord() const { return (const void*)fSection; }
463 virtual unsigned int getSectionIndex() const { return 1 + (fSection - fOwner.fSectionsStart); }
464 virtual uint8_t getLSDAReferenceKind() const;
465 virtual uint8_t getPersonalityReferenceKind() const;
466 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
469 typedef typename A::P P;
470 typedef typename A::P::E E;
471 typedef typename A::P::uint_t pint_t;
472 typedef typename A::ReferenceKinds Kinds;
473 typedef typename std::vector<Reference<A>*> ReferenceVector;
474 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
475 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
476 friend class Reader<A>;
478 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
479 virtual ~SymbolAtom() {}
482 const macho_nlist<P>* fSymbol;
485 const macho_section<P>* fSection;
486 Segment<A>* fSegment;
487 ReferenceVector fReferences;
488 std::vector<ObjectFile::LineInfo> fLineInfo;
489 ObjectFile::Atom::Scope fScope;
490 SymbolTableInclusion fSymbolTableInclusion;
491 ObjectFile::Atom::ContentType fType;
492 ObjectFile::Alignment fAlignment;
496 template <typename A>
497 SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
498 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fType(ObjectFile::Atom::kUnclassifiedType), fAlignment(0)
500 fSingleUnwindInfo[0].startOffset = 0;
501 fSingleUnwindInfo[0].unwindInfo = 0;
502 uint8_t type = symbol->n_type();
503 if ( (type & N_EXT) == 0 )
504 fScope = ObjectFile::Atom::scopeTranslationUnit;
505 else if ( (type & N_PEXT) != 0 )
506 fScope = ObjectFile::Atom::scopeLinkageUnit;
508 fScope = ObjectFile::Atom::scopeGlobal;
509 if ( (type & N_TYPE) == N_SECT ) {
511 fSegment = new Segment<A>(fSection);
512 fAddress = fSymbol->n_value();
513 pint_t sectionStartAddr = section->addr();
514 pint_t sectionEndAddr = section->addr()+section->size();
515 if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) {
516 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",
517 this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(),
518 (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) );
522 warning("unknown symbol type: %d", type);
525 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
526 // support for .o files built with old ld64
527 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
528 const char* name = this->getName();
529 const int nameLen = strlen(name);
530 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
531 // switch symbol to point at name that does not have trailing $stub
532 char correctName[nameLen];
533 strncpy(correctName, name, nameLen-5);
534 correctName[nameLen-5] = '\0';
535 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
536 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
537 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
538 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
545 // support for labeled stubs
546 switch ( section->flags() & SECTION_TYPE ) {
548 setSize(section->reserved2());
550 case S_LAZY_SYMBOL_POINTERS:
551 case S_NON_LAZY_SYMBOL_POINTERS:
552 setSize(sizeof(pint_t));
554 case S_4BYTE_LITERALS:
557 case S_8BYTE_LITERALS:
560 case S_16BYTE_LITERALS:
563 case S_CSTRING_LITERALS:
564 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
565 fType = ObjectFile::Atom::kCStringType;
570 // size calculate later after next atom is found
575 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
577 // compute whether this atom needs to be in symbol table
578 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
579 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
581 else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) {
582 // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
583 // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
584 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
587 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
590 // work around malformed icc generated .o files <rdar://problem/5349847>
591 // if section starts with a symbol and that symbol address does not match section alignment, then force it to
592 if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) )
593 fAlignment.modulus = 0;
596 template <typename A>
597 bool SymbolAtom<A>::dontDeadStrip() const
599 // the symbol can have a no-dead-strip bit
600 if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 )
602 // or the section can have a no-dead-strip bit
603 return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP );
607 template <typename A>
608 const char* SymbolAtom<A>::getSectionName() const
610 if ( fOwner.fOptions.fForFinalLinkedImage ) {
611 if ( strcmp(fSection->sectname(), "__textcoal_nt") == 0 )
613 else if ( strcmp(fSection->sectname(), "__const_coal") == 0 )
615 else if ( strcmp(fSection->sectname(), "__datacoal_nt") == 0 )
617 else if ( fOwner.fOptions.fAutoOrderInitializers && (strcmp(fSection->sectname(), "__StaticInit") == 0) )
620 switch ( fSection->flags() & SECTION_TYPE ) {
621 case S_4BYTE_LITERALS:
622 case S_8BYTE_LITERALS:
623 case S_16BYTE_LITERALS:
629 if ( strlen(fSection->sectname()) > 15 ) {
630 static char temp[18];
631 strncpy(temp, fSection->sectname(), 16);
635 return fSection->sectname();
638 template <typename A>
639 ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
641 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
642 Reference<A>* ref = *it;
643 if ( ref->getKind() == A::kFollowOn )
644 return ref->getTarget();
646 return *((ObjectFile::Atom*)NULL);
649 template <typename A>
650 bool SymbolAtom<A>::isZeroFill() const
652 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
659 Beyond(uint64_t offset) : fOffset(offset) {}
660 bool operator()(ObjectFile::Reference* ref) const {
661 return ( ref->getFixUpOffset() >= fOffset );
668 template <typename A>
669 void SymbolAtom<A>::setSize(uint64_t size)
671 // when resizing, any references beyond the new size are tossed
672 if ( (fSize != 0) && (fReferences.size() > 0) )
673 fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end());
678 template <typename A>
679 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
683 bzero(buffer, fSize);
685 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
686 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
694 // A SymbolAliasAtom represents an alternate name for a SymbolAtom
697 template <typename A>
698 class SymbolAliasAtom : public BaseAtom
701 virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); }
702 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
703 { return fAliasOf.getTranslationUnitSource(dir, name); }
704 virtual const char* getName() const { return fName; }
705 virtual const char* getDisplayName() const { return fName; }
706 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
707 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); }
708 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); }
709 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
710 virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); }
711 virtual bool isThumb() const { return fAliasOf.isThumb(); }
712 virtual uint64_t getSize() const { return 0; }
713 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
714 virtual bool mustRemainInSection() const { return true; }
715 virtual const char* getSectionName() const { return fAliasOf.getSectionName(); }
716 virtual Segment<A>& getSegment() const { return (Segment<A>&)fAliasOf.getSegment(); }
717 virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; }
718 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
719 virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); }
720 virtual void copyRawContent(uint8_t buffer[]) const {}
721 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
722 virtual void setSize(uint64_t size) { }
723 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
724 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
725 virtual void addLineInfo(const ObjectFile::LineInfo& info) { }
726 virtual const ObjectFile::ReaderOptions& getOptions() const { return fAliasOf.getOptions(); }
727 virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); }
728 virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); }
729 virtual unsigned int getSectionIndex() const { return fAliasOf.getSectionIndex(); }
730 virtual bool isAlias() const { return true; }
733 typedef typename A::P P;
734 typedef typename std::vector<Reference<A>*> ReferenceVector;
735 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
736 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
737 friend class Reader<A>;
739 SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
740 virtual ~SymbolAliasAtom() {}
743 const BaseAtom& fAliasOf;
744 ObjectFile::Atom::Scope fScope;
746 ReferenceVector fReferences;
750 template <typename A>
751 SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
752 : fName(name), fAliasOf(aliasOf)
754 //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
755 if ( symbol != NULL ) {
756 uint8_t type = symbol->n_type();
757 if ( (type & N_EXT) == 0 )
758 fScope = ObjectFile::Atom::scopeTranslationUnit;
759 else if ( (type & N_PEXT) != 0 )
760 fScope = ObjectFile::Atom::scopeLinkageUnit;
762 fScope = ObjectFile::Atom::scopeGlobal;
763 fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
766 // aliases defined on the command line are initially global scope
767 fScope = ObjectFile::Atom::scopeGlobal;
768 fDontDeadStrip = false;
770 // add follow-on reference to real atom
771 new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
776 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
777 // For instance, "int foo;" is neither a declaration or a definition and
778 // is represented by a TentativeAtom.
780 template <typename A>
781 class TentativeAtom : public BaseAtom
784 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
785 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
786 { return fOwner.getTranslationUnitSource(dir, name); }
787 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
788 virtual const char* getDisplayName() const { return getName(); }
789 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
790 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
791 virtual bool isZeroFill() const { return fOwner.fOptions.fOptimizeZeroFill; }
792 virtual bool isThumb() const { return false; }
793 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
794 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
795 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
796 virtual uint64_t getSize() const { return fSymbol->n_value(); }
797 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
798 virtual bool mustRemainInSection() const { return true; }
799 virtual const char* getSectionName() const;
800 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
801 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
802 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
803 virtual ObjectFile::Alignment getAlignment() const;
804 virtual void copyRawContent(uint8_t buffer[]) const;
805 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
806 virtual void setSize(uint64_t size) { }
807 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
808 virtual void sortReferences() { }
809 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
810 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
811 virtual uint64_t getObjectAddress() const { return ULLONG_MAX; }
812 virtual const void* getSectionRecord() const { return NULL; }
813 virtual unsigned int getSectionIndex() const { return 0; }
816 typedef typename A::P P;
817 typedef typename A::P::E E;
818 typedef typename A::P::uint_t pint_t;
819 typedef typename A::ReferenceKinds Kinds;
820 friend class Reader<A>;
822 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
823 virtual ~TentativeAtom() {}
826 const macho_nlist<P>* fSymbol;
827 ObjectFile::Atom::Scope fScope;
828 static std::vector<ObjectFile::Reference*> fgNoReferences;
831 template <typename A>
832 std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
834 template <typename A>
835 TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
836 : fOwner(owner), fSymbol(symbol)
838 uint8_t type = symbol->n_type();
839 if ( (type & N_EXT) == 0 )
840 fScope = ObjectFile::Atom::scopeTranslationUnit;
841 else if ( (type & N_PEXT) != 0 )
842 fScope = ObjectFile::Atom::scopeLinkageUnit;
844 fScope = ObjectFile::Atom::scopeGlobal;
845 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
846 // tentative definition
849 warning("unknown symbol type: %d", type);
851 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
855 template <typename A>
856 ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
858 uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc());
859 if ( alignment == 0 ) {
860 // common symbols align to their size
861 // that is, a 4-byte common aligns to 4-bytes
862 // if this size is not a power of two,
863 // then round up to the next power of two
864 uint64_t size = this->getSize();
865 alignment = 63 - (uint8_t)__builtin_clzll(size);
866 if ( size != (1ULL << alignment) )
869 // limit alignment of extremely large commons to 2^15 bytes (8-page)
870 if ( alignment < 12 )
871 return ObjectFile::Alignment(alignment);
873 return ObjectFile::Alignment(12);
876 template <typename A>
877 const char* TentativeAtom<A>::getSectionName() const
879 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
886 template <typename A>
887 void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
889 bzero(buffer, getSize());
894 // An AnonymousAtom represents compiler generated data that has no name.
895 // For instance, a literal C-string or a 64-bit floating point constant
896 // is represented by an AnonymousAtom.
898 template <typename A>
899 class AnonymousAtom : public BaseAtom
902 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
903 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
904 virtual const char* getName() const { return fSynthesizedName; }
905 virtual const char* getDisplayName() const;
906 virtual ObjectFile::Atom::Scope getScope() const;
907 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; }
908 virtual ObjectFile::Atom::ContentType getContentType() const { return fType; }
909 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
910 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
911 virtual bool isZeroFill() const;
912 virtual bool isThumb() const { return false; }
913 virtual uint64_t getSize() const { return fSize; }
914 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
915 virtual bool mustRemainInSection() const { return true; }
916 virtual const char* getSectionName() const;
917 virtual Segment<A>& getSegment() const { return *fSegment; }
918 virtual ObjectFile::Atom& getFollowOnAtom() const;
919 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
920 virtual ObjectFile::Alignment getAlignment() const;
921 virtual void copyRawContent(uint8_t buffer[]) const;
922 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
923 virtual void setSize(uint64_t size) { fSize = size; }
924 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
925 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
926 virtual void addLineInfo(const ObjectFile::LineInfo& info) { warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); }
927 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
928 virtual uint64_t getObjectAddress() const { return fAddress; }
929 virtual const void* getSectionRecord() const { return (const void*)fSection; }
930 virtual unsigned int getSectionIndex() const { return fSectionIndex; }
931 BaseAtom* redirectTo() { return fRedirect; }
932 bool isWeakImportStub() { return fWeakImportStub; }
934 virtual uint8_t getLSDAReferenceKind() const;
935 virtual uint8_t getPersonalityReferenceKind() const;
936 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
939 typedef typename A::P P;
940 typedef typename A::P::E E;
941 typedef typename A::P::uint_t pint_t;
942 typedef typename A::ReferenceKinds Kinds;
943 typedef typename std::vector<Reference<A>*> ReferenceVector;
944 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
945 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
946 friend class Reader<A>;
948 AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
949 virtual ~AnonymousAtom() {}
950 static bool cstringsHaveLabels();
953 const char* fSynthesizedName;
954 const char* fDisplayName;
955 const macho_section<P>* fSection;
958 Segment<A>* fSegment;
959 ReferenceVector fReferences;
962 bool fWeakImportStub;
963 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
964 ObjectFile::Atom::Scope fScope;
965 ObjectFile::Atom::DefinitionKind fKind;
966 ObjectFile::Atom::ContentType fType;
967 unsigned int fSectionIndex;
970 template <typename A>
971 AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
972 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
973 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
974 fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition),
975 fType(ObjectFile::Atom::kUnclassifiedType), fSectionIndex(1 + (section - owner.fSectionsStart))
977 fSegment = new Segment<A>(fSection);
979 uint8_t type = fSection->flags() & SECTION_TYPE;
980 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
984 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
989 if ( section == owner.fehFrameSection ) {
993 fDontDeadStrip = false;
994 if ( fOwner.fOptions.fForFinalLinkedImage )
995 fSynthesizedName = "CIE";
997 fSynthesizedName = "EH_frame1";
1001 fSynthesizedName = ".eh_PENDING";
1002 fDontDeadStrip = false;
1003 owner.fAtomsPendingAName.push_back(this);
1005 fType = ObjectFile::Atom::kCFIType;
1006 // FDEs and CIEs don't need to be in symbol table of final linked images <rdar://problem/4180168>
1007 if ( !fOwner.fOptions.fNoEHLabels )
1008 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1010 else if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
1011 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
1012 fSynthesizedName = ".objc_class_name_PENDING";
1013 owner.fAtomsPendingAName.push_back(this);
1014 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1015 if ( fOwner.fOptions.fForFinalLinkedImage )
1016 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1018 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
1019 fScope = ObjectFile::Atom::scopeGlobal;
1021 else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
1022 // handle .o files created by old ld64 -r that are missing cstring section type
1023 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
1024 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
1026 else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) {
1027 fSynthesizedName = "cfstring-pointer-name-PENDING";
1028 fScope = ObjectFile::Atom::scopeLinkageUnit;
1029 owner.fAtomsPendingAName.push_back(this);
1030 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1031 fDontDeadStrip = false;
1032 fKind = ObjectFile::Atom::kWeakDefinition;
1034 else if ( (fSection->flags() & S_ATTR_SOME_INSTRUCTIONS) != 0 ) {
1035 fDontDeadStrip = false;
1036 asprintf((char**)&fSynthesizedName, "anon-func-0x%X", addr);
1038 else if ( strncmp(fSection->sectname(), "__gcc_except_tab",16) == 0 ) {
1039 fType = ObjectFile::Atom::kLSDAType;
1040 fDontDeadStrip = false;
1041 fSynthesizedName = ".lsda_PENDING";
1042 owner.fAtomsPendingAName.push_back(this);
1043 if ( !fOwner.fOptions.fNoEHLabels )
1044 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1047 case S_CSTRING_LITERALS:
1049 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
1050 if ( strcmp(fSection->sectname(), "__cstring") == 0 )
1051 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
1053 asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str);
1054 fScope = ObjectFile::Atom::scopeLinkageUnit;
1055 fKind = ObjectFile::Atom::kWeakDefinition;
1056 fType = ObjectFile::Atom::kCStringType;
1057 fDontDeadStrip = false;
1058 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
1059 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1062 case S_4BYTE_LITERALS:
1064 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1065 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
1066 fScope = ObjectFile::Atom::scopeLinkageUnit;
1067 fKind = ObjectFile::Atom::kWeakDefinition;
1068 fDontDeadStrip = false;
1071 case S_8BYTE_LITERALS:
1073 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1074 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
1075 fScope = ObjectFile::Atom::scopeLinkageUnit;
1076 fKind = ObjectFile::Atom::kWeakDefinition;
1077 fDontDeadStrip = false;
1080 case S_16BYTE_LITERALS:
1082 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1083 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
1084 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
1085 fScope = ObjectFile::Atom::scopeLinkageUnit;
1086 fKind = ObjectFile::Atom::kWeakDefinition;
1087 fDontDeadStrip = false;
1090 case S_LITERAL_POINTERS:
1092 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1093 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
1094 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
1095 fSynthesizedName = "literal-pointer-name-PENDING";
1096 fScope = ObjectFile::Atom::scopeLinkageUnit;
1097 fKind = ObjectFile::Atom::kWeakDefinition;
1098 fDontDeadStrip = false;
1099 owner.fAtomsPendingAName.push_back(this);
1100 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1103 case S_MOD_INIT_FUNC_POINTERS:
1104 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1106 case S_MOD_TERM_FUNC_POINTERS:
1107 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1109 case S_SYMBOL_STUBS:
1111 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
1112 index += fSection->reserved1();
1113 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1114 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
1115 uint32_t strOffset = sym->n_strx();
1116 // want name to not have $stub suffix, this is what automatic stub generation expects
1117 fSynthesizedName = &fOwner.fStrings[strOffset];
1118 // check for weak import
1119 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
1120 // sometimes the compiler gets confused and generates a stub to a static function
1121 // if so, we should redirect any call to the stub to be calls to the real static function atom
1122 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
1123 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
1124 if ( staticAtom != NULL )
1125 fRedirect = staticAtom;
1127 fKind = ObjectFile::Atom::kWeakDefinition;
1128 // might be a spurious stub for a static function, make stub static too
1129 if ( (sym->n_type() & N_EXT) == 0 )
1130 fScope = ObjectFile::Atom::scopeTranslationUnit;
1132 fScope = ObjectFile::Atom::scopeLinkageUnit;
1135 case S_LAZY_SYMBOL_POINTERS:
1136 case S_NON_LAZY_SYMBOL_POINTERS:
1138 fDontDeadStrip = false;
1139 fScope = ObjectFile::Atom::scopeLinkageUnit;
1140 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
1141 index += fSection->reserved1();
1142 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1143 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1144 // Silly codegen with non-lazy pointer to a local symbol
1145 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1146 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
1147 // All atoms not created yet, so we need to scan symbol table
1148 const macho_nlist<P>* closestSym = NULL;
1149 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1150 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
1151 if ( ((sym->n_type() & N_TYPE) == N_SECT)
1152 && ((sym->n_type() & N_STAB) == 0) ) {
1153 if ( sym->n_value() == nonLazyPtrValue ) {
1154 const char* name = &fOwner.fStrings[sym->n_strx()];
1155 char* str = new char[strlen(name)+16];
1157 strcat(str, "$non_lazy_ptr");
1158 fSynthesizedName = str;
1159 // add direct reference to target later, because its atom may not be constructed yet
1160 fOwner.fLocalNonLazys.push_back(this);
1161 fScope = ObjectFile::Atom::scopeTranslationUnit;
1164 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1169 // add direct reference to target later, because its atom may not be constructed yet
1170 if ( closestSym != NULL ) {
1171 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1173 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1174 fSynthesizedName = str;
1177 fSynthesizedName = "$interior$non_lazy_ptr";
1179 fScope = ObjectFile::Atom::scopeTranslationUnit;
1180 fOwner.fLocalNonLazys.push_back(this);
1183 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1184 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1185 char* str = new char[strlen(name)+16];
1187 if ( type == S_LAZY_SYMBOL_POINTERS )
1188 strcat(str, "$lazy_ptr");
1190 strcat(str, "$non_lazy_ptr");
1191 fSynthesizedName = str;
1193 // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when
1194 // generating the new compressed LINKEDIT format
1195 if ( fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
1196 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1197 dummySection->set_segname("__DATA");
1198 dummySection->set_sectname("__nl_symbol_ptr");
1199 fSection = dummySection;
1200 fSegment = new Segment<A>(fSection);
1203 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1204 fKind = ObjectFile::Atom::kWeakDefinition;
1206 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1207 // target is translation unit scoped, so add direct reference to target
1208 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1209 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1212 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1213 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1215 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1220 throwf("section type %d not supported with address=0x%08X", type, addr);
1222 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1225 // x86_64 uses L labels on cstrings to allow relocs with addends
1226 template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1227 template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1230 template <typename A>
1231 void AnonymousAtom<A>::resolveName()
1233 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1234 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1235 // references are not yet sorted, so scan the vector
1236 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1237 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1238 const char* superStr = (*rit)->getTargetName();
1239 if ( strncmp(superStr, "cstring", 7) == 0 ) {
1240 const char* superClassName;
1241 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1242 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1247 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1248 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1249 const char* classStr = (*rit)->getTargetName();
1250 if ( strncmp(classStr, "cstring", 7) == 0 ) {
1251 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1257 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
1258 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1259 if ( references.size() < 1 )
1260 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1261 ObjectFile::Reference* ref = references[0];
1262 const char* str = ref->getTargetName();
1263 if ( strncmp(str, "cstring", 7) == 0 ) {
1264 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1267 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1268 // references are not yet sorted, so scan the vector
1269 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1270 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1271 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1272 const char* superStr = (*rit)->getTargetName();
1273 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1274 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1277 // compiled with -fwritable-strings or a non-ASCII string
1278 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1279 fScope = ObjectFile::Atom::scopeTranslationUnit;
1280 fSynthesizedName = "cfstring-not-coalesable";
1281 if ( (*rit)->getTargetOffset() != 0 )
1282 warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner.getPath());
1288 else if ( fSection == fOwner.fehFrameSection ) {
1290 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromFDEAddress(fAddress);
1291 if ( funcAtom != NULL )
1292 asprintf((char**)&fSynthesizedName, "%s.eh", funcAtom->getDisplayName());
1294 else if ( fOwner.fLSDAAtoms.count(this) != 0) {
1295 // give name to LSDA
1296 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromLSDAAddress(fAddress);
1297 if ( funcAtom != NULL )
1298 asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
1303 template <typename A>
1304 const char* AnonymousAtom<A>::getDisplayName() const
1306 if ( fSynthesizedName != NULL )
1307 return fSynthesizedName;
1309 if ( fDisplayName != NULL )
1310 return fDisplayName;
1312 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1313 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1314 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
1317 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
1319 return fDisplayName;
1323 template <typename A>
1324 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1330 template <typename A>
1331 bool AnonymousAtom<A>::isZeroFill() const
1333 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
1337 template <typename A>
1338 const char* AnonymousAtom<A>::getSectionName() const
1340 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1341 switch ( fSection->flags() & SECTION_TYPE ) {
1342 case S_4BYTE_LITERALS:
1343 case S_8BYTE_LITERALS:
1344 case S_16BYTE_LITERALS:
1349 if ( strlen(fSection->sectname()) > 15 ) {
1350 static char temp[18];
1351 strncpy(temp, fSection->sectname(), 16);
1355 return fSection->sectname();
1358 template <typename A>
1359 ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
1361 // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
1362 if ( fType == ObjectFile::Atom::kCFIType )
1363 return ObjectFile::Alignment(0);
1365 switch ( fSection->flags() & SECTION_TYPE ) {
1366 case S_4BYTE_LITERALS:
1367 return ObjectFile::Alignment(2);
1368 case S_8BYTE_LITERALS:
1369 return ObjectFile::Alignment(3);
1370 case S_16BYTE_LITERALS:
1371 return ObjectFile::Alignment(4);
1372 case S_NON_LAZY_SYMBOL_POINTERS:
1373 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
1374 case S_CSTRING_LITERALS:
1375 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1376 return ObjectFile::Alignment(fSection->align());
1378 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
1383 template <typename A>
1384 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1386 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1387 Reference<A>* ref = *it;
1388 if ( ref->getKind() == A::kFollowOn )
1389 return ref->getTarget();
1391 return *((ObjectFile::Atom*)NULL);
1394 template <typename A>
1395 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1399 bzero(buffer, fSize);
1401 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1402 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1407 // An AbsoluteAtom represents an N_ABS symbol which can only be created in
1408 // assembly language and usable by static executables such as the kernel/
1410 template <typename A>
1411 class AbsoluteAtom : public BaseAtom
1414 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1415 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1416 { return fOwner.getTranslationUnitSource(dir, name); }
1417 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1418 virtual const char* getDisplayName() const { return getName(); }
1419 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1420 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1421 virtual bool isZeroFill() const { return false; }
1422 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
1423 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1424 virtual bool dontDeadStrip() const { return false; }
1425 virtual uint64_t getSize() const { return 0; }
1426 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1427 virtual bool mustRemainInSection() const { return true; }
1428 virtual const char* getSectionName() const { return "._absolute"; }
1429 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1430 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1431 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1432 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1433 virtual void copyRawContent(uint8_t buffer[]) const { }
1434 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1435 virtual void setSize(uint64_t size) { }
1436 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1437 virtual void sortReferences() { }
1438 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1439 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1440 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1441 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1442 virtual const void* getSectionRecord() const { return NULL; }
1443 virtual unsigned int getSectionIndex() const { return 0; }
1446 typedef typename A::P P;
1447 typedef typename A::P::E E;
1448 typedef typename A::P::uint_t pint_t;
1449 typedef typename A::ReferenceKinds Kinds;
1450 friend class Reader<A>;
1452 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1453 virtual ~AbsoluteAtom() {}
1456 const macho_nlist<P>* fSymbol;
1457 ObjectFile::Atom::Scope fScope;
1458 static std::vector<ObjectFile::Reference*> fgNoReferences;
1461 template <typename A>
1462 std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1464 template <typename A>
1465 AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1466 : fOwner(owner), fSymbol(symbol)
1468 // store absolute adress in fSectionOffset
1469 fSectionOffset = symbol->n_value();
1471 uint8_t type = symbol->n_type();
1472 if ( (type & N_EXT) == 0 )
1473 fScope = ObjectFile::Atom::scopeTranslationUnit;
1474 else if ( (type & N_PEXT) != 0 )
1475 fScope = ObjectFile::Atom::scopeLinkageUnit;
1477 fScope = ObjectFile::Atom::scopeGlobal;
1478 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1483 // An SectionBoundaryAtom represent the start or end of a section
1485 template <typename A>
1486 class SectionBoundaryAtom : public BaseAtom
1489 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1490 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1491 { return fOwner.getTranslationUnitSource(dir, name); }
1492 virtual const char* getName() const { return fSymbolName; }
1493 virtual const char* getDisplayName() const { return fDisplayName; }
1494 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1495 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition; }
1496 virtual ObjectFile::Atom::ContentType getContentType() const { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
1497 virtual bool isZeroFill() const { return false; }
1498 virtual bool isThumb() const { return false; }
1499 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
1500 virtual bool dontDeadStrip() const { return false; }
1501 virtual uint64_t getSize() const { return 0; }
1502 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1503 virtual bool mustRemainInSection() const { return true; }
1504 virtual const char* getSectionName() const { return fSectionName; }
1505 virtual ObjectFile::Segment& getSegment() const { return *fSegment; }
1506 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1507 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1508 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1509 virtual void copyRawContent(uint8_t buffer[]) const { }
1510 virtual void setScope(ObjectFile::Atom::Scope newScope) { }
1511 virtual void setSize(uint64_t size) { }
1512 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1513 virtual void sortReferences() { }
1514 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1515 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1516 virtual uint64_t getObjectAddress() const { return 0; }
1517 virtual const void* getSectionRecord() const { return NULL; }
1518 virtual unsigned int getSectionIndex() const { return 0; }
1521 typedef typename A::P P;
1522 typedef typename A::P::E E;
1523 typedef typename A::P::uint_t pint_t;
1524 typedef typename A::ReferenceKinds Kinds;
1525 friend class Reader<A>;
1528 class Segment : public ObjectFile::Segment
1531 Segment(const char* name, bool r, bool w, bool x):
1532 fName(name), fReadable(r), fWritable(w), fExecutable(x) {}
1534 virtual const char* getName() const { return fName; }
1535 virtual bool isContentReadable() const { return fReadable; }
1536 virtual bool isContentWritable() const { return fWritable; }
1537 virtual bool isContentExecutable() const { return fExecutable; }
1545 SectionBoundaryAtom(Reader<A>&, bool start, const char* symbolName, const char* segSectName);
1546 virtual ~SectionBoundaryAtom() {}
1549 class Segment* fSegment;
1550 const char* fSymbolName;
1551 const char* fSectionName;
1552 const char* fDisplayName;
1554 static std::vector<ObjectFile::Reference*> fgNoReferences;
1557 template <typename A>
1558 std::vector<ObjectFile::Reference*> SectionBoundaryAtom<A>::fgNoReferences;
1561 // section$start$__DATA$__my
1562 // section$end$__DATA$__my
1563 template <typename A>
1564 SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
1565 : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start)
1567 const char* segSectDividor = strrchr(segSectName, '$');
1568 if ( segSectDividor == NULL )
1569 throwf("malformed section reference name: %s", symbolName);
1570 fSectionName = segSectDividor + 1;
1571 int segNameLen = segSectDividor - segSectName;
1572 if ( segNameLen > 16 )
1573 throwf("malformed section reference name: %s", symbolName);
1575 strlcpy(segName, segSectName, segNameLen+1);
1576 if ( strcmp(segName, "__TEXT") == 0 )
1577 fSegment = new Segment("__TEXT", true, false, true);
1578 else if ( strcmp(segName, "__DATA") == 0 )
1579 fSegment = new Segment("__DATA", true, true, false);
1581 fSegment = new Segment(strdup(segName), true, true, false);
1583 asprintf((char**)&fDisplayName, "%s of section '%s' in segment '%s'", (start ? "start" : "end"), fSectionName, segName);
1589 /// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
1590 /// dwarf CFI information in an object file.
1592 template <typename A>
1593 class ObjectFileAddressSpace
1596 ObjectFileAddressSpace(Reader<A>& reader);
1598 typedef typename A::P::uint_t pint_t;
1599 typedef typename A::P P;
1600 typedef typename A::P::uint_t sint_t;
1602 uint8_t get8(pint_t addr);
1603 uint16_t get16(pint_t addr);
1604 uint32_t get32(pint_t addr);
1605 uint64_t get64(pint_t addr);
1606 pint_t getP(pint_t addr);
1607 uint64_t getULEB128(pint_t& addr, pint_t end);
1608 int64_t getSLEB128(pint_t& addr, pint_t end);
1609 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
1611 const void* mappedAddress(pint_t addr, pint_t* relocTarget=NULL);
1612 pint_t relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount);
1615 const uint8_t* fMappingStart;
1616 const macho_section<P>* fSectionsStart;
1617 const macho_section<P>* fSectionsEnd;
1621 template <typename A>
1622 ObjectFileAddressSpace<A>::ObjectFileAddressSpace(Reader<A>& reader)
1623 : fReader(reader), fMappingStart(NULL), fSectionsStart(NULL), fSectionsEnd(NULL)
1629 template <typename A>
1630 const void* ObjectFileAddressSpace<A>::mappedAddress(pint_t addr, pint_t* relocTarget)
1632 if ( fMappingStart == NULL ) {
1633 // delay initialization until now when fReader.fSegment is set up
1634 fMappingStart = (uint8_t*)fReader.fHeader;
1635 fSectionsStart = (macho_section<P>*)((char*)fReader.fSegment + sizeof(macho_segment_command<P>));
1636 fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()];
1638 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
1639 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
1640 pint_t offsetOfAddrInSection = addr - sect->addr();
1641 if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
1642 const uint32_t indirectTableOffset = sect->reserved1();
1643 const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t);
1644 const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]);
1645 // return pointer to symbol name which this non-lazy-pointer will point to
1646 if ( relocTarget != NULL )
1647 *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()];
1650 if ( relocTarget != NULL )
1651 *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc());
1653 return fMappingStart + sect->offset() + offsetOfAddrInSection;
1656 throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr);
1662 template <typename A>
1663 uint8_t ObjectFileAddressSpace<A>::get8(pint_t logicalAddr)
1665 return *((uint8_t*)mappedAddress(logicalAddr));
1668 template <typename A>
1669 uint16_t ObjectFileAddressSpace<A>::get16(pint_t logicalAddr)
1671 return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr)));
1674 template <typename A>
1675 uint32_t ObjectFileAddressSpace<A>::get32(pint_t logicalAddr)
1678 return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1681 template <typename A>
1682 uint64_t ObjectFileAddressSpace<A>::get64(pint_t logicalAddr)
1685 return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1688 template <typename A>
1689 typename A::P::uint_t ObjectFileAddressSpace<A>::getP(pint_t logicalAddr)
1692 return P::getP(*((pint_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1695 template <typename A>
1696 uint64_t ObjectFileAddressSpace<A>::getULEB128(pint_t& logicalAddr, pint_t end)
1698 uintptr_t size = (end - logicalAddr);
1699 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1700 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1701 uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
1702 logicalAddr += (laddr-sladdr);
1706 template <typename A>
1707 int64_t ObjectFileAddressSpace<A>::getSLEB128(pint_t& logicalAddr, pint_t end)
1709 uintptr_t size = (end - logicalAddr);
1710 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1711 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1712 int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
1713 logicalAddr += (laddr-sladdr);
1722 template <typename A>
1723 class Reader : public ObjectFile::Reader
1726 static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
1727 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1728 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
1729 virtual ~Reader() {}
1731 virtual const char* getPath() { return fPath; }
1732 virtual time_t getModificationTime() { return fModTime; }
1733 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1734 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1735 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1736 virtual std::vector<Stab>* getStabs() { return &fStabs; }
1737 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
1738 virtual uint32_t updateCpuConstraint(uint32_t current);
1739 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1740 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
1741 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
1743 bool getTranslationUnitSource(const char** dir, const char** name) const;
1746 typedef typename A::P P;
1747 typedef typename A::P::E E;
1748 typedef typename A::P::uint_t pint_t;
1749 //typedef typename std::vector<Atom<A>*> AtomVector;
1750 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1751 typedef typename A::ReferenceKinds Kinds;
1752 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::FDE_Atom_Info FDE_Atom_Info;
1753 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::CIE_Atom_Info CIE_Atom_Info;
1754 typedef class ObjectFileAddressSpace<A> OAS;
1755 friend class ObjectFileAddressSpace<A>;
1756 friend class AnonymousAtom<A>;
1757 friend class TentativeAtom<A>;
1758 friend class AbsoluteAtom<A>;
1759 friend class SectionBoundaryAtom<A>;
1760 friend class SymbolAtom<A>;
1761 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
1763 void addReferencesForSection(const macho_section<P>* sect);
1764 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1765 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1766 const char* getDwarfString(uint64_t form, const uint8_t* p);
1767 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1768 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1769 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1770 static const char* assureFullPath(const char* path);
1771 AtomAndOffset findAtomAndOffset(pint_t addr);
1772 AtomAndOffset findAtomAndOffsetForSection(pint_t addr, unsigned int sectionIndex);
1773 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1774 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1775 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1776 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1777 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1778 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
1779 BaseAtom* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
1780 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
1781 void validSectionType(uint8_t type);
1782 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1783 void setCpuConstraint(uint32_t cpusubtype);
1784 const macho_section<P>* getSectionForAddress(pint_t);
1785 ObjectFile::Atom* getFunctionAtomFromFDEAddress(pint_t);
1786 ObjectFile::Atom* getFunctionAtomFromLSDAAddress(pint_t);
1787 void addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target);
1788 void addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding);
1789 bool isSectDiffReloc(uint8_t r_type);
1792 BaseAtom* findAtomByName(const char*);
1796 uint32_t fOrdinalBase;
1797 const ObjectFile::ReaderOptions& fOptions;
1798 const macho_header<P>* fHeader;
1799 const char* fStrings;
1800 const macho_nlist<P>* fSymbols;
1801 uint32_t fSymbolCount;
1802 const macho_segment_command<P>* fSegment;
1803 const uint32_t* fIndirectTable;
1804 std::vector<BaseAtom*> fAtoms;
1805 AddrToAtomMap fAddrToAtom;
1806 AddrToAtomMap fAddrToAbsoluteAtom;
1807 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
1808 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1809 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1810 std::vector<const char*> fDtraceProviderInfo;
1811 ObjectFile::Reader::DebugInfoKind fDebugInfo;
1813 const macho_section<P>* fehFrameSection;
1814 std::set<BaseAtom*> fLSDAAtoms;
1815 const macho_section<P>* fDwarfDebugInfoSect;
1816 const macho_section<P>* fDwarfDebugAbbrevSect;
1817 const macho_section<P>* fDwarfDebugLineSect;
1818 const macho_section<P>* fDwarfDebugStringSect;
1819 const char* fDwarfTranslationUnitDir;
1820 const char* fDwarfTranslationUnitFile;
1821 std::map<uint32_t,const char*> fDwarfIndexToFile;
1822 std::vector<Stab> fStabs;
1823 std::vector<FDE_Atom_Info> fFDEInfos;
1824 std::vector<CIE_Atom_Info> fCIEInfos;
1826 bool fHasDTraceProbes;
1827 bool fHaveIndirectSymbols;
1828 bool fReplacementClasses;
1829 bool fHasLongBranchStubs;
1830 ObjectFile::Reader::ObjcConstraint fObjConstraint;
1831 uint32_t fCpuConstraint;
1832 const macho_section<P>* fSectionsStart;
1833 const macho_section<P>* fSectionsEnd;
1834 OAS fObjectAddressSpace;
1837 template <typename A>
1838 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1839 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
1840 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
1841 fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL),
1842 fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
1843 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
1844 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
1845 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny),
1846 fSectionsStart(NULL), fSectionsEnd(NULL), fObjectAddressSpace(*this)
1849 if ( ! validFile(fileContent, false, 0) )
1850 throw "not a valid mach-o object file";
1852 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1854 // write out path for -t or -whatsloaded option
1855 if ( options.fLogObjectFiles || options.fLogAllFiles )
1856 printf("%s\n", path);
1858 // cache intersting pointers
1859 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1860 this->setCpuConstraint(header->cpusubtype());
1861 const uint32_t cmd_count = header->ncmds();
1862 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
1863 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
1864 const macho_load_command<P>* cmd = cmds;
1865 uint32_t undefinedStartIndex = 0;
1866 uint32_t undefinedEndIndex = 0;
1867 for (uint32_t i = 0; i < cmd_count; ++i) {
1868 switch (cmd->cmd()) {
1871 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1872 fSymbolCount = symtab->nsyms();
1873 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1874 fStrings = (char*)header + symtab->stroff();
1875 if ( undefinedEndIndex == 0 ) {
1876 undefinedStartIndex = 0;
1877 undefinedEndIndex = symtab->nsyms();
1883 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1884 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
1885 undefinedStartIndex = dsymtab->iundefsym();
1886 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
1894 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1895 fSegment = (macho_segment_command<P>*)cmd;
1899 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
1900 if ( cmd > cmdsEnd )
1901 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
1904 // if there are no load commands, then this file has no content, so no atoms
1905 if ( header->ncmds() < 1 )
1908 fSectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1909 fSectionsEnd = &fSectionsStart[fSegment->nsects()];
1911 // inital guess for number of atoms
1912 fAtoms.reserve(fSymbolCount);
1914 // if there is an __eh_frame section, decode it into chunks to get atoms in that
1915 // section as well as division points for functions in __text
1916 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
1917 if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
1918 fehFrameSection = sect;
1919 if ( libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::getCFIs(fObjectAddressSpace, sect->addr(), sect->size(),
1920 fCIEInfos, fFDEInfos) ) {
1921 //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size());
1922 // add anonymous atoms for each CIE
1923 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
1924 AnonymousAtom<A>* cieAtom = new AnonymousAtom<A>(*this, sect, it->cieAddress, 1);
1925 fAtoms.push_back(cieAtom);
1926 fAddrToAtom[it->cieAddress] = cieAtom;
1928 // add anonymous atoms for each FDE and LSDA
1929 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
1930 //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);
1931 AnonymousAtom<A>* fdeAtom = new AnonymousAtom<A>(*this, sect, it->fdeAddress, 0);
1932 fAtoms.push_back(fdeAtom);
1933 fAddrToAtom[it->fdeAddress] = fdeAtom;
1934 if ( it->lsda.address != 0 ) {
1935 AnonymousAtom<A>* lsdaAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->lsda.address), it->lsda.address, 0);
1936 fAtoms.push_back(lsdaAtom);
1937 fAddrToAtom[it->lsda.address] = lsdaAtom;
1938 fLSDAAtoms.insert(lsdaAtom);
1943 throw "malformed __eh_frame section";
1949 // add all atoms that have entries in symbol table
1950 BaseAtom* sectionEndAtoms[fSegment->nsects()];
1951 for (unsigned int i=0; i < fSegment->nsects(); ++i)
1952 sectionEndAtoms[i] = NULL;
1953 for (int i=fSymbolCount-1; i >= 0 ; --i) {
1954 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name
1955 const macho_nlist<P>& sym = fSymbols[i];
1956 if ( (sym.n_type() & N_STAB) == 0 ) {
1957 uint8_t type = (sym.n_type() & N_TYPE);
1958 if ( type == N_SECT ) {
1959 const macho_section<P>* section = &fSectionsStart[sym.n_sect()-1];
1960 const pint_t sectionStartAddr = section->addr();
1961 const pint_t sectionEndAddr = sectionStartAddr + section->size();
1962 bool suppress = false;
1963 // ignore atoms in debugger sections
1964 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
1965 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
1966 // ignore dtrace probe labels
1967 fHasDTraceProbes = true;
1969 else if ( fStrings[sym.n_strx()] == 'L' ) {
1970 // ignore L labels, <rdar://problem/3962731>
1972 else if ( section == fehFrameSection ) {
1973 // ignore labels in __eh_frame section
1976 // ignore labels for atoms in other sections
1977 switch ( section->flags() & SECTION_TYPE ) {
1979 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
1980 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
1983 case S_4BYTE_LITERALS:
1984 case S_8BYTE_LITERALS:
1985 case S_16BYTE_LITERALS:
1986 case S_CSTRING_LITERALS:
1989 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
1990 if ( (pos != fAddrToAtom.end()) && (pos->second->getSectionRecord() == section) ) {
1991 if ( fLSDAAtoms.count(pos->second) != 0 ) {
1992 // already have LSDA atom from for this address, ignore compiler's label
1997 // another label to an existing address in the same section, make this an alias
1998 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
2002 if ( sym.n_value() == sectionEndAddr ) {
2003 // Symbol address is at end of section. This can interfere
2004 // with a symbol at the start of the next section, so don't
2005 // add to fAddrToAtom. But do track in sectionEndAtoms so we
2006 // still make aliases if there are duplicates.
2007 if ( sectionEndAtoms[sym.n_sect()-1] == NULL ) {
2008 newAtom = new SymbolAtom<A>(*this, &sym, section);
2009 sectionEndAtoms[sym.n_sect()-1] = newAtom;
2010 // if this is a zero length section, so add to fAddrToAtom
2011 if ( sym.n_value() == sectionStartAddr )
2012 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2015 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *sectionEndAtoms[sym.n_sect()-1]);
2019 // make SymbolAtom atom for this address
2020 newAtom = new SymbolAtom<A>(*this, &sym, section);
2021 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2025 fAtoms.push_back(newAtom);
2028 case S_SYMBOL_STUBS:
2029 case S_LAZY_SYMBOL_POINTERS:
2030 case S_NON_LAZY_SYMBOL_POINTERS:
2031 // ignore symboled stubs produces by old ld64
2034 warning("symbol %s found in unsupported section in %s",
2035 &fStrings[sym.n_strx()], this->getPath());
2040 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
2041 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
2043 else if ( (type == N_UNDF) && (sym.n_value() == 0) ) {
2044 const char* symName = &fStrings[sym.n_strx()];
2045 if ( strncmp(symName, "section$start$", 14) == 0)
2046 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, true, symName, &symName[14]));
2047 else if ( strncmp(symName, "section$end$", 12) == 0)
2048 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, false, symName, &symName[12]));
2050 else if ( type == N_ABS ) {
2051 const char* symName = &fStrings[sym.n_strx()];
2052 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
2053 // ignore .objc_class_name_* symbols
2056 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
2057 // ignore empty *.eh symbols
2060 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
2061 fAtoms.push_back(abAtom);
2062 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
2065 else if ( type == N_INDR ) {
2066 fHaveIndirectSymbols = true;
2071 // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names
2072 if ( fehFrameSection != NULL ) {
2073 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2074 // add if not already an atom at that address
2075 if ( fAddrToAtom.find(it->function.address) == fAddrToAtom.end() ) {
2076 AnonymousAtom<A>* funcAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->function.address), it->function.address, 0);
2077 fAtoms.push_back(funcAtom);
2078 fAddrToAtom[it->function.address] = funcAtom;
2079 // even though we've made a new atom, be conservative and make sure they lay out together
2080 if ( canScatterAtoms() ) {
2081 AtomAndOffset prev = findAtomAndOffset(it->function.address-1);
2082 if ( prev.atom != NULL ) {
2083 if ( ((BaseAtom*)(prev.atom))->getSectionRecord() == funcAtom->getSectionRecord() )
2084 new Reference<A>(A::kFollowOn, prev, AtomAndOffset(funcAtom));
2092 // add all fixed size anonymous atoms from special sections
2093 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2094 pint_t atomSize = 0;
2095 uint8_t type (sect->flags() & SECTION_TYPE);
2096 validSectionType(type);
2097 bool suppress = false;
2099 case S_SYMBOL_STUBS:
2101 atomSize = sect->reserved2();
2103 case S_LAZY_SYMBOL_POINTERS:
2105 atomSize = sizeof(pint_t);
2107 case S_NON_LAZY_SYMBOL_POINTERS:
2108 case S_LITERAL_POINTERS:
2109 case S_MOD_INIT_FUNC_POINTERS:
2110 case S_MOD_TERM_FUNC_POINTERS:
2111 atomSize = sizeof(pint_t);
2114 atomSize = sizeof(pint_t)*2;
2116 case S_4BYTE_LITERALS:
2119 case S_8BYTE_LITERALS:
2122 case S_16BYTE_LITERALS:
2126 // special case ObjC classes to synthesize .objc_class_name_* symbols
2127 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
2128 // gcc sometimes over aligns class structure
2129 uint32_t align = 1 << sect->align();
2130 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
2132 // get objc Garbage Collection info
2133 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
2134 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
2135 // struct objc_image_info {
2136 // uint32_t version; // initially 0
2139 // #define OBJC_IMAGE_SUPPORTS_GC 2
2140 // #define OBJC_IMAGE_GC_ONLY 4
2142 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
2143 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
2144 uint32_t flags = E::get32(contents[1]);
2145 if ( (flags & 4) == 4 )
2146 fObjConstraint = ObjectFile::Reader::kObjcGC;
2147 else if ( (flags & 2) == 2 )
2148 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
2150 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
2151 if ( (flags & 1) == 1 )
2152 fReplacementClasses = true;
2153 // don't make atom for this section
2154 atomSize = sect->size();
2158 warning("can't parse __OBJC/__image_info section in %s", fPath);
2161 // special case constant NS/CFString literals and make an atom out of each one
2162 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
2163 atomSize = 4 * sizeof(pint_t);
2167 if ( atomSize != 0 ) {
2168 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
2169 pint_t atomAddr = sect->addr() + sectOffset;
2170 // add if not already an atom at that address
2171 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
2172 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
2174 fAtoms.push_back(newAtom);
2175 fAddrToAtom[atomAddr] = newAtom->redirectTo();
2181 // add all c-string anonymous atoms
2182 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2183 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
2186 BaseAtom* mostAlignedEmptyString = NULL;
2187 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
2188 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
2189 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
2190 stringAddr = sect->addr() + sectOffset;
2191 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
2192 // add if not already a non-zero length atom at that address
2193 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(stringAddr);
2194 if ( (pos == fAddrToAtom.end()) || (pos->second->getSize() == 0) ) {
2195 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
2196 if ( stringLen == 1 ) {
2197 // because of padding it may look like there are lots of empty strings, keep track of all
2198 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
2199 // record empty string with greatest alignment requirement
2200 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
2201 if ( (mostAlignedEmptyString == NULL)
2202 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
2203 mostAlignedEmptyString = newAtom;
2204 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
2208 fAtoms.push_back(newAtom);
2209 fAddrToAtom[stringAddr] = newAtom;
2213 // map all uses of empty strings to the most aligned one
2214 if ( mostAlignedEmptyString != NULL ) {
2215 // make most aligned atom a real atom
2216 fAtoms.push_back(mostAlignedEmptyString);
2217 // map all other empty atoms to this one
2218 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
2219 fAddrToAtom[it->first] = mostAlignedEmptyString;
2225 // sort all atoms so far by address and section
2226 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2228 //fprintf(stderr, "sorted atoms:\n");
2229 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
2230 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
2232 // create atoms to cover any non-debug ranges not handled above
2233 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2234 pint_t sectionStartAddr = sect->addr();
2235 pint_t sectionEndAddr = sect->addr() + sect->size();
2236 // don't set follow-on atoms in __eh_frame section
2237 const bool setFollowOnAtom = !canScatterAtoms() && (sect != fehFrameSection);
2238 if ( sect->size() != 0 ) {
2239 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
2240 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
2241 fDebugInfo = kDebugInfoDwarf;
2242 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
2243 fDwarfDebugInfoSect = sect;
2244 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
2245 fDwarfDebugAbbrevSect = sect;
2246 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
2247 fDwarfDebugLineSect = sect;
2248 else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
2249 fDwarfDebugStringSect = sect;
2252 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
2253 throw "object file contains old DWARF debug info - rebuild with newer compiler";
2255 uint8_t type (sect->flags() & SECTION_TYPE);
2260 // if there is not an atom already at the start of this section, add an anonymous one
2261 pint_t previousAtomAddr = 0;
2262 BaseAtom* previousAtom = NULL;
2263 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
2264 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
2265 fAddrToAtom[sect->addr()] = newAtom;
2266 fAtoms.push_back(newAtom);
2267 previousAtomAddr = sectionStartAddr;
2268 previousAtom = newAtom;
2269 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2271 // calculate size of all atoms in this section and add follow-on references
2272 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2273 BaseAtom* atom = (BaseAtom*)(*it);
2274 pint_t atomAddr = atom->getObjectAddress();
2275 if ( atom->getSectionRecord() == sect ) {
2276 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
2277 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
2278 previousAtom->setSize(atomAddr - previousAtomAddr);
2279 if ( setFollowOnAtom && (atom != previousAtom) )
2280 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
2282 previousAtomAddr = atomAddr;
2283 previousAtom = atom;
2286 if ( previousAtom != NULL ) {
2287 // set last atom in section
2288 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
2296 // check for object file that defines no objc classes, but uses objc classes
2297 // check for dtrace provider info
2298 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
2299 const macho_nlist<P>& sym = fSymbols[i];
2300 if ( (sym.n_type() & N_STAB) == 0 ) {
2301 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
2302 const char* undefinedName = &fStrings[sym.n_strx()];
2303 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
2306 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
2307 if ( strchr(undefinedName, '$') != NULL ) {
2308 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
2309 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
2310 // is extra provider info
2311 fDtraceProviderInfo.push_back(undefinedName);
2319 // add relocation based references to sections that have atoms with pending names
2320 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2321 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
2322 addReferencesForSection(sect);
2325 // update any anonymous atoms that need references built in order to name themselves
2326 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
2327 (*it)->resolveName();
2330 // add relocation based references to other sections
2331 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2332 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
2333 addReferencesForSection(sect);
2336 // add objective-c references
2338 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2339 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
2340 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
2341 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
2342 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
2343 if ( classRef->getFixUpOffset() == 0 ) {
2344 const char* classStr = classRef->getTargetName();
2345 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
2346 const char* className;
2347 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
2348 new Reference<A>(A::kNoFixUp, ao, className, 0);
2356 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
2357 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
2358 AnonymousAtom<A>* localNonLazy = *it;
2359 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
2360 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
2361 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
2365 // add personality references to CIEs
2366 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2367 if ( it->personality.offsetInFDE != 0 )
2368 addCiePersonalityReference(fAddrToAtom[it->cieAddress], it->personality.offsetInFDE, it->personality.encodingOfAddress);
2371 // add all references for FDEs, including implicit group references
2372 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2373 AtomAndOffset funcAO = this->findAtomAndOffset(it->function.address);
2374 if ( funcAO.offset != 0 )
2375 warning("FDE does not point to start of function %s\n", funcAO.atom->getDisplayName());
2376 AtomAndOffset fdeAO = this->findAtomAndOffset(it->fdeAddress);
2377 if ( fdeAO.offset != 0 )
2378 warning("FDE does start its own atom %s\n", funcAO.atom->getDisplayName());
2379 AtomAndOffset cieAO = this->findAtomAndOffset(it->cie.address);
2380 if ( cieAO.offset != 0 )
2381 warning("CIE does start its own atom %s\n", cieAO.atom->getDisplayName());
2382 AtomAndOffset lsdaAO;
2383 if ( it->lsda.address != 0 ) {
2384 lsdaAO = this->findAtomAndOffset(it->lsda.address);
2385 if ( lsdaAO.offset != 0 )
2386 warning("LSDA does start its own atom %s\n", lsdaAO.atom->getDisplayName());
2389 // add reference from FDE to CIE
2390 AtomAndOffset cieInfdeAO = AtomAndOffset(fdeAO.atom, it->cie.offsetInFDE);
2391 new Reference<A>(A::kPointerDiff32, cieInfdeAO, cieAO, cieInfdeAO);
2393 // add reference from FDE to function
2394 addFdeReference(it->function.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->function.offsetInFDE), funcAO);
2396 // add reference from FDE to LSDA
2397 if ( it->lsda.address != 0 ) {
2398 addFdeReference(it->lsda.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->lsda.offsetInFDE), lsdaAO);
2401 // FDE is in group lead by function atom
2402 new Reference<A>(A::kGroupSubordinate, funcAO, fdeAO);
2404 // LSDA is in group lead by function atom
2405 if ( it->lsda.address != 0 ) {
2406 new Reference<A>(A::kGroupSubordinate, funcAO, lsdaAO);
2407 // add back reference from LSDA to owning function
2408 new Reference<A>(A::kNoFixUp, lsdaAO, funcAO);
2411 // compute compact encoding for this FDE
2412 if ( fOptions.fAddCompactUnwindEncoding ) {
2413 ((BaseAtom*)(funcAO.atom))->setCompactUnwindEncoding(it->fdeAddress);
2414 // add reference from function atom to personality function
2415 // the only reference a CIE can have is the reference to the personality function
2416 std::vector<class ObjectFile::Reference*>& cieRefs = cieAO.atom->getReferences();
2417 if ( cieRefs.size() == 1 ) {
2418 new Reference<A>((typename A::ReferenceKinds)((BaseAtom*)(funcAO.atom))->getPersonalityReferenceKind(),
2419 funcAO, cieRefs[0]->getTargetName(), 0);
2424 // add command line aliases
2425 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
2426 BaseAtom* target = this->findAtomByName(it->realName);
2427 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
2428 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
2431 // add dtrace probe locations
2432 if ( fHasDTraceProbes ) {
2433 for (uint32_t i=0; i < fSymbolCount; ++i) {
2434 const macho_nlist<P>& sym = fSymbols[i];
2435 if ( (sym.n_type() & N_STAB) == 0 ) {
2436 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
2437 const char* symbolName = &fStrings[sym.n_strx()];
2438 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
2439 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
2440 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
2447 // turn indirect symbols into SymbolAliasAtom
2448 if ( fHaveIndirectSymbols ) {
2449 for (uint32_t i=0; i < fSymbolCount; ++i) {
2450 const macho_nlist<P>& sym = fSymbols[i];
2451 if ( (sym.n_type() & N_STAB) == 0 ) {
2452 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
2453 const char* aliasName = &fStrings[sym.n_strx()];
2454 const char* targetName = &fStrings[sym.n_value()];
2455 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
2456 BaseAtom* target = this->findAtomByName(targetName);
2457 // only currently support N_INDR based aliases to something in the same .o file
2458 if ( target != NULL ) {
2459 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
2460 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
2467 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
2468 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
2471 // add translation unit info from dwarf
2473 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2474 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
2475 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2476 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
2477 // if can't parse dwarf, warn and give up
2478 fDwarfTranslationUnitFile = NULL;
2479 fDwarfTranslationUnitDir = NULL;
2480 warning("can't parse dwarf compilation unit info in %s", this->getPath());
2481 fDebugInfo = kDebugInfoNone;
2486 // add line number info to atoms from dwarf
2487 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2488 // file with just data will have no __debug_line info
2489 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
2490 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2491 // validate stmt_list
2492 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
2493 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
2494 if ( debug_line != NULL ) {
2495 struct line_reader_data* lines = line_open(&debug_line[stmtList],
2496 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
2497 struct line_info result;
2498 ObjectFile::Atom* curAtom = NULL;
2499 uint32_t curAtomOffset = 0;
2500 uint32_t curAtomAddress = 0;
2501 uint32_t curAtomSize = 0;
2502 if ( lines != NULL ) {
2503 while ( line_next (lines, &result, line_stop_pc) ) {
2504 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
2505 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
2506 // work around weird debug line table compiler generates if no functions in __text section
2507 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
2509 // for performance, see if in next pc is in current atom
2510 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
2511 curAtomOffset = result.pc - curAtomAddress;
2513 // or pc at end of current atom
2514 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
2515 curAtomOffset = result.pc - curAtomAddress;
2518 // do slow look up of atom by address
2519 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
2521 if ( curAtom == NULL )
2522 break; // file has line info but no functions
2523 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
2524 // a one line function can be returned by line_next() as one entry with pc at end of blob
2525 // look for alt atom starting at end of previous atom
2526 uint32_t previousEnd = curAtomAddress+curAtomSize;
2527 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
2528 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
2530 curAtomOffset = alt.offset;
2531 curAtomAddress = previousEnd - alt.offset;
2532 curAtomSize = curAtom->getSize();
2535 curAtomOffset = ao.offset;
2536 curAtomAddress = result.pc - ao.offset;
2537 curAtomSize = curAtom->getSize();
2541 curAtomOffset = ao.offset;
2542 curAtomAddress = result.pc - ao.offset;
2543 curAtomSize = curAtom->getSize();
2546 const char* filename;
2547 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2548 if ( pos == fDwarfIndexToFile.end() ) {
2549 filename = line_file(lines, result.file);
2550 fDwarfIndexToFile[result.file] = filename;
2553 filename = pos->second;
2555 ObjectFile::LineInfo info;
2556 info.atomOffset = curAtomOffset;
2557 info.fileName = filename;
2558 info.lineNumber = result.line;
2559 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2560 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2561 ((BaseAtom*)curAtom)->addLineInfo(info);
2562 if ( result.end_of_sequence ) {
2570 warning("could not parse dwarf line number info in %s", this->getPath());
2576 // if no dwarf, try processing stabs debugging info
2577 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2578 // scan symbol table for stabs entries
2579 fStabs.reserve(fSymbolCount); // reduce re-allocations
2580 BaseAtom* currentAtom = NULL;
2581 pint_t currentAtomAddress = 0;
2582 enum { start, inBeginEnd, inFun } state = start;
2583 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2584 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2585 bool useStab = true;
2586 uint8_t type = sym->n_type();
2587 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2588 if ( (type & N_STAB) != 0 ) {
2589 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
2593 stab.other = sym->n_sect();
2594 stab.desc = sym->n_desc();
2595 stab.value = sym->n_value();
2601 // beginning of function block
2603 // fall into case to lookup atom by addresss
2606 currentAtomAddress = sym->n_value();
2607 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2608 if ( currentAtom != NULL ) {
2609 stab.atom = currentAtom;
2610 stab.string = symString;
2613 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
2614 (uint64_t)sym->n_value(), path);
2623 // not associated with an atom, just copy
2624 stab.string = symString;
2628 // n_value field is NOT atom address ;-(
2629 // need to find atom by name match
2630 const char* colon = strchr(symString, ':');
2631 if ( colon != NULL ) {
2632 // build underscore leading name
2633 int nameLen = colon - symString;
2634 char symName[nameLen+2];
2635 strlcpy(&symName[1], symString, nameLen+1);
2637 symName[nameLen+1] = '\0';
2638 currentAtom = findAtomByName(symName);
2639 if ( currentAtom != NULL ) {
2640 stab.atom = currentAtom;
2641 stab.string = symString;
2645 // might be a debug-note without trailing :G()
2646 currentAtom = findAtomByName(symString);
2647 if ( currentAtom != NULL ) {
2648 stab.atom = currentAtom;
2649 stab.string = symString;
2652 if ( stab.atom == NULL ) {
2653 // ld_classic added bogus GSYM stabs for old style dtrace probes
2654 if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
2655 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
2661 // old style stabs without BNSYM
2663 currentAtomAddress = sym->n_value();
2664 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2665 if ( currentAtom != NULL ) {
2666 stab.atom = currentAtom;
2667 stab.string = symString;
2670 warning("can't find atom for stabs FUN at %08llX in %s",
2671 (uint64_t)currentAtomAddress, path);
2676 stab.string = symString;
2682 stab.string = symString;
2683 // -gfull built .o file
2686 warning("unknown stabs type 0x%X in %s", type, path);
2690 stab.atom = currentAtom;
2699 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2700 if ( nestedAtom != NULL ) {
2701 stab.atom = nestedAtom;
2702 stab.string = symString;
2705 warning("can't find atom for stabs 0x%X at %08llX in %s",
2706 type, (uint64_t)sym->n_value(), path);
2713 // adjust value to be offset in atom
2714 stab.value -= currentAtomAddress;
2716 stab.string = symString;
2723 if ( sym->n_sect() != 0 ) {
2724 // found another start stab, must be really old stabs...
2725 currentAtomAddress = sym->n_value();
2726 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2727 if ( currentAtom != NULL ) {
2728 stab.atom = currentAtom;
2729 stab.string = symString;
2732 warning("can't find atom for stabs FUN at %08llX in %s",
2733 (uint64_t)currentAtomAddress, path);
2737 // found ending stab, switch back to start state
2738 stab.string = symString;
2739 stab.atom = currentAtom;
2747 // adjust value to be offset in atom
2748 stab.value -= currentAtomAddress;
2749 stab.atom = currentAtom;
2752 stab.string = symString;
2756 stab.atom = currentAtom;
2757 stab.string = symString;
2762 // add to list of stabs for this .o file
2764 fStabs.push_back(stab);
2770 // special case precompiled header .o file (which has no content) to have one empty atom
2771 if ( fAtoms.size() == 0 ) {
2772 int pathLen = strlen(path);
2773 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2774 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2775 //phony->fSynthesizedName = ".gch.o";
2776 fAtoms.push_back(phony);
2781 // sort all atoms by address
2782 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2784 // set ordinal and sort references in each atom
2785 uint32_t index = fOrdinalBase;
2786 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2787 BaseAtom* atom = (BaseAtom*)(*it);
2788 atom->setOrdinal(index++);
2789 atom->sortReferences();
2794 template <typename A>
2795 const macho_section<typename A::P>* Reader<A>::getSectionForAddress(pint_t addr)
2797 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2798 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) )
2801 throwf("section not found for address 0x%08llX", (uint64_t)addr);
2804 template <typename A>
2805 ObjectFile::Atom* Reader<A>::getFunctionAtomFromFDEAddress(pint_t addr)
2807 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2808 if ( it->fdeAddress == addr ) {
2809 return findAtomAndOffset(it->function.address).atom;
2812 // CIEs won't be in fFDEInfos
2816 template <typename A>
2817 ObjectFile::Atom* Reader<A>::getFunctionAtomFromLSDAAddress(pint_t addr)
2819 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2820 if ( it->lsda.address == addr ) {
2821 return findAtomAndOffset(it->function.address).atom;
2830 uint64_t ObjectFileAddressSpace<x86_64>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
2832 // mach-o x86_64 is different, the content of a section with a relocation is the addend
2833 uint64_t result = 0;
2834 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + relocsOffset);
2835 const macho_relocation_info<P>* relocsEnd = &relocs[relocsCount];
2836 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2837 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address());
2838 if ( reloc->r_address() == sectOffset ) {
2839 switch ( reloc->r_type() ) {
2840 case X86_64_RELOC_UNSIGNED:
2841 result += fReader.fSymbols[reloc->r_symbolnum()].n_value();
2843 case X86_64_RELOC_SUBTRACTOR:
2844 result -= fReader.fSymbols[reloc->r_symbolnum()].n_value();
2846 case X86_64_RELOC_GOT:
2847 // there is no good address to return here.
2848 // GOT slots are synthsized by the linker
2849 // this is used for the reference to the personality function in CIEs
2853 fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset, reloc->r_type(), reloc->r_symbolnum());
2858 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result);
2862 template <typename A>
2863 typename A::P::uint_t ObjectFileAddressSpace<A>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
2865 // in all architectures except x86_64, the section contents are already fixed up to point
2866 // to content in the same object file.
2872 // FSF exception handling Pointer-Encoding constants
2873 // Used in CFI augmentation by gcc compiler
2875 DW_EH_PE_ptr = 0x00,
2876 DW_EH_PE_uleb128 = 0x01,
2877 DW_EH_PE_udata2 = 0x02,
2878 DW_EH_PE_udata4 = 0x03,
2879 DW_EH_PE_udata8 = 0x04,
2880 DW_EH_PE_signed = 0x08,
2881 DW_EH_PE_sleb128 = 0x09,
2882 DW_EH_PE_sdata2 = 0x0A,
2883 DW_EH_PE_sdata4 = 0x0B,
2884 DW_EH_PE_sdata8 = 0x0C,
2885 DW_EH_PE_absptr = 0x00,
2886 DW_EH_PE_pcrel = 0x10,
2887 DW_EH_PE_textrel = 0x20,
2888 DW_EH_PE_datarel = 0x30,
2889 DW_EH_PE_funcrel = 0x40,
2890 DW_EH_PE_aligned = 0x50,
2891 DW_EH_PE_indirect = 0x80,
2892 DW_EH_PE_omit = 0xFF
2896 void Reader<x86_64>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
2898 if ( encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4) )
2899 throw "unexpected personality encoding in CIE";
2901 // walk relocs looking for reloc in this CIE
2902 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
2903 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
2904 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
2905 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2906 if ( reloc->r_address() == sectOffset ) {
2907 switch ( reloc->r_type() ) {
2908 case X86_64_RELOC_GOT:
2909 if ( !reloc->r_extern() )
2910 throw "GOT reloc not extern for personality function";
2911 new Reference<x86_64>(x86_64::kPCRel32GOT, AtomAndOffset(cieAtom, offsetInCIE), &fStrings[fSymbols[reloc->r_symbolnum()].n_strx()], 4);
2914 throw "expected GOT reloc for personality function";
2918 throw "personality function not found for CIE";
2922 bool Reader<ppc>::isSectDiffReloc(uint8_t r_type)
2925 case PPC_RELOC_LOCAL_SECTDIFF:
2926 case PPC_RELOC_SECTDIFF:
2933 bool Reader<ppc64>::isSectDiffReloc(uint8_t r_type)
2936 case PPC_RELOC_LOCAL_SECTDIFF:
2937 case PPC_RELOC_SECTDIFF:
2944 bool Reader<x86>::isSectDiffReloc(uint8_t r_type)
2947 case GENERIC_RELOC_LOCAL_SECTDIFF:
2948 case GENERIC_RELOC_SECTDIFF:
2955 bool Reader<arm>::isSectDiffReloc(uint8_t r_type)
2958 case ARM_RELOC_LOCAL_SECTDIFF:
2959 case ARM_RELOC_SECTDIFF:
2965 template <typename A>
2966 void Reader<A>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
2968 if ( (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4)) && (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel)) )
2969 throw "unexpected personality encoding in CIE";
2971 // walk relocs looking for personality reloc in this CIE
2972 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
2973 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
2974 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
2975 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2976 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2980 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2981 if ( sreloc->r_address() == sectOffset ) {
2982 if ( isSectDiffReloc(sreloc->r_type()) ) {
2983 // r_value is address of non-lazy-pointer to personality function
2984 new Reference<A>(A::kPointerDiff32, AtomAndOffset(cieAtom, offsetInCIE), AtomAndOffset(cieAtom, offsetInCIE),
2985 findAtomAndOffset(sreloc->r_value()));
2991 throw "can't find relocation for personality in CIE";
2994 template <typename A>
2995 void Reader<A>::addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target)
2997 if ( (encoding & 0xF0) != DW_EH_PE_pcrel )
2998 throw "unsupported encoding in FDE";
2999 Kinds kind = A::kNoFixUp;
3000 switch ( encoding & 0xF ) {
3002 kind = A::kPointerDiff;
3004 case DW_EH_PE_sdata4:
3005 kind = A::kPointerDiff32;
3008 throw "unsupported encoding in FDE";
3010 new Reference<A>(kind, inFDE, inFDE, target);
3013 template <typename A>
3014 typename A::P::uint_t ObjectFileAddressSpace<A>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
3016 pint_t startAddr = addr;
3021 switch (encoding & 0x0F) {
3023 result = getP(addr);
3024 p += sizeof(pint_t);
3027 case DW_EH_PE_uleb128:
3028 result = getULEB128(addr, end);
3030 case DW_EH_PE_udata2:
3031 result = get16(addr);
3035 case DW_EH_PE_udata4:
3036 result = get32(addr);
3040 case DW_EH_PE_udata8:
3041 result = get64(addr);
3045 case DW_EH_PE_sleb128:
3046 result = getSLEB128(addr, end);
3048 case DW_EH_PE_sdata2:
3049 result = (int16_t)get16(addr);
3053 case DW_EH_PE_sdata4:
3054 result = (int32_t)get32(addr);
3058 case DW_EH_PE_sdata8:
3059 result = get64(addr);
3064 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3067 // then add relative offset
3068 switch ( encoding & 0x70 ) {
3069 case DW_EH_PE_absptr:
3072 case DW_EH_PE_pcrel:
3073 result += startAddr;
3075 case DW_EH_PE_textrel:
3076 throw "DW_EH_PE_textrel pointer encoding not supported";
3078 case DW_EH_PE_datarel:
3079 throw "DW_EH_PE_datarel pointer encoding not supported";
3081 case DW_EH_PE_funcrel:
3082 throw "DW_EH_PE_funcrel pointer encoding not supported";
3084 case DW_EH_PE_aligned:
3085 throw "DW_EH_PE_aligned pointer encoding not supported";
3088 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3092 if ( encoding & DW_EH_PE_indirect )
3093 result = getP(result);
3099 uint32_t SymbolAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3103 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
3104 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality);
3105 if ( (result & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) {
3106 //if ( fOwner.fOptions.fForDyld )
3107 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3109 if ( fOwner.fOptions.fWarnCompactUnwind )
3110 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3116 uint32_t SymbolAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3120 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
3121 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality);
3122 if ( (result & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) {
3123 //if ( fOwner.fOptions.fForDyld )
3124 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3126 if ( fOwner.fOptions.fWarnCompactUnwind )
3127 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3133 uint32_t SymbolAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3135 // compact encoding not supported for ppc
3140 uint32_t SymbolAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3142 // compact encoding not supported for ppc64
3147 uint32_t SymbolAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3149 // compact encoding not supported for arm
3154 template <typename A>
3155 uint8_t SymbolAtom<A>::getLSDAReferenceKind() const
3157 return A::kGroupSubordinate;
3161 uint8_t SymbolAtom<x86_64>::getPersonalityReferenceKind() const
3163 return x86_64::kGOTNoFixUp;
3167 uint8_t SymbolAtom<x86>::getPersonalityReferenceKind() const
3169 return x86::kNoFixUp;
3172 template <typename A>
3173 uint8_t SymbolAtom<A>::getPersonalityReferenceKind() const
3175 // only used with architectures that support compact unwinding
3181 uint32_t AnonymousAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3185 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
3186 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality);
3187 if ( (result & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) {
3188 //if ( fOwner.fOptions.fForDyld )
3189 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3191 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3197 uint32_t AnonymousAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3201 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
3202 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality);
3203 if ( (result & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) {
3204 //if ( fOwner.fOptions.fForDyld )
3205 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3207 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3213 uint32_t AnonymousAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3215 // compact encoding not supported for ppc
3220 uint32_t AnonymousAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3222 // compact encoding not supported for ppc64
3227 uint32_t AnonymousAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3229 // compact encoding not supported for arm
3234 template <typename A>
3235 uint8_t AnonymousAtom<A>::getLSDAReferenceKind() const
3237 return A::kGroupSubordinate;
3241 uint8_t AnonymousAtom<x86_64>::getPersonalityReferenceKind() const
3243 return x86_64::kGOTNoFixUp;
3247 uint8_t AnonymousAtom<x86>::getPersonalityReferenceKind() const
3249 return x86::kNoFixUp;
3252 template <typename A>
3253 uint8_t AnonymousAtom<A>::getPersonalityReferenceKind() const
3255 // only used with architectures that support compact unwinding
3266 void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
3268 switch (cpusubtype) {
3269 case CPU_SUBTYPE_POWERPC_ALL:
3270 case CPU_SUBTYPE_POWERPC_750:
3271 case CPU_SUBTYPE_POWERPC_7400:
3272 case CPU_SUBTYPE_POWERPC_7450:
3273 case CPU_SUBTYPE_POWERPC_970:
3274 fCpuConstraint = cpusubtype;
3277 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3278 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
3284 void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
3286 switch (cpusubtype) {
3287 case CPU_SUBTYPE_ARM_ALL:
3288 case CPU_SUBTYPE_ARM_V4T:
3289 case CPU_SUBTYPE_ARM_V5TEJ:
3290 case CPU_SUBTYPE_ARM_V6:
3291 case CPU_SUBTYPE_ARM_XSCALE:
3292 case CPU_SUBTYPE_ARM_V7:
3293 fCpuConstraint = cpusubtype;
3296 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3297 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
3302 template <typename A>
3303 void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
3305 // no cpu sub types for this architecture
3309 uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
3311 switch ( previous ) {
3312 case CPU_SUBTYPE_POWERPC_ALL:
3313 return fCpuConstraint;
3315 case CPU_SUBTYPE_POWERPC_750:
3316 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
3317 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
3318 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3319 return fCpuConstraint;
3321 case CPU_SUBTYPE_POWERPC_7400:
3322 case CPU_SUBTYPE_POWERPC_7450:
3323 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3324 return fCpuConstraint;
3326 case CPU_SUBTYPE_POWERPC_970:
3327 // G5 can run everything
3330 throw "Unhandled PPC cpu subtype!";
3339 uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
3342 case CPU_SUBTYPE_ARM_ALL:
3343 return fCpuConstraint;
3345 case CPU_SUBTYPE_ARM_V5TEJ:
3346 // v6, v7, and xscale are more constrained than previous file (v5), so use it
3347 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
3348 || (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3349 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3350 return fCpuConstraint;
3352 case CPU_SUBTYPE_ARM_V4T:
3353 // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
3354 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3355 || (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
3356 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
3357 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3358 return fCpuConstraint;
3360 case CPU_SUBTYPE_ARM_V6:
3361 // v6 can run everything except xscale and v7
3362 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3363 throw "can't mix xscale and v6 code";
3364 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3365 return fCpuConstraint;
3367 case CPU_SUBTYPE_ARM_XSCALE:
3368 // xscale can run everything except v6 and v7
3369 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
3370 throw "can't mix xscale and v6 code";
3371 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3372 throw "can't mix xscale and v7 code";
3374 case CPU_SUBTYPE_ARM_V7:
3375 // v7 can run everything except xscale
3376 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3377 throw "can't mix xscale and v7 code";
3380 throw "Unhandled ARM cpu subtype!";
3385 template <typename A>
3386 uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
3388 // no cpu sub types for this architecture
3392 template <typename A>
3393 void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
3395 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
3396 // a matching provider name, add a by-name kDtraceTypeReference at probe site
3397 const char* dollar = strchr(providerName, '$');
3398 if ( dollar != NULL ) {
3399 int providerNameLen = dollar-providerName+1;
3400 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
3401 const char* typeDollar = strchr(*it, '$');
3402 if ( typeDollar != NULL ) {
3403 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
3404 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
3413 void Reader<x86_64>::validSectionType(uint8_t type)
3416 case S_SYMBOL_STUBS:
3417 throw "symbol_stub sections not valid in x86_64 object files";
3418 case S_LAZY_SYMBOL_POINTERS:
3419 throw "lazy pointer sections not valid in x86_64 object files";
3420 case S_NON_LAZY_SYMBOL_POINTERS:
3421 throw "non lazy pointer sections not valid in x86_64 object files";
3425 template <typename A>
3426 void Reader<A>::validSectionType(uint8_t type)
3430 template <typename A>
3431 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
3433 if ( fDebugInfo == kDebugInfoDwarf ) {
3434 *dir = fDwarfTranslationUnitDir;
3435 *name = fDwarfTranslationUnitFile;
3436 return (fDwarfTranslationUnitFile != NULL);
3441 template <typename A>
3442 BaseAtom* Reader<A>::findAtomByName(const char* name)
3444 // first search the more important atoms
3445 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
3446 const char* atomName = it->second->getName();
3447 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3451 // try all atoms, because this might have been a tentative definition
3452 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
3453 BaseAtom* atom = (BaseAtom*)(*it);
3454 const char* atomName = atom->getName();
3455 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3462 template <typename A>
3463 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
3465 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
3468 template <typename A>
3469 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
3471 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
3474 template <typename A>
3475 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
3477 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
3480 template <typename A>
3481 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
3483 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
3486 template <typename A>
3487 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
3489 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3492 template <typename A>
3493 BaseAtom* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
3495 // add a group subordinate reference from function atom to its eh frame atom
3496 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
3497 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
3498 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
3499 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3500 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3501 new Reference<A>(A::kGroupSubordinate, funcAtom, ehAtom);
3502 return (BaseAtom*)funcAtom;
3507 Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
3509 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3510 // instead check scope of target
3511 BaseAtom* target = findAtomByName(toName);
3512 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
3513 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
3515 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3519 Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
3521 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3522 // instead check scope of target
3523 const char* symbolName = &fStrings[toSymbol->n_strx()];
3524 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) {
3525 AtomAndOffset targetAO = findAtomAndOffsetForSection(toSymbol->n_value(), toSymbol->n_sect());
3526 targetAO.offset = toOffset;
3527 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), targetAO);
3530 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
3535 BaseAtom* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
3537 // add a group subordinate reference from function atom to its eh frame atom
3538 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
3539 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
3540 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
3541 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
3542 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3543 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
3544 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
3545 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3546 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3547 new Reference<x86_64>(x86_64::kGroupSubordinate, funcAtom, ehAtom);
3548 return (BaseAtom*)funcAtom;
3551 warning("can't find matching function for eh symbol %s", ehName);
3555 template <typename A>
3556 AtomAndOffset Reader<A>::findAtomAndOffsetForSection(pint_t addr, unsigned int expectedSectionIndex)
3558 AtomAndOffset ao = findAtomAndOffset(addr);
3559 if ( ao.atom != NULL ) {
3560 if ( ((BaseAtom*)(ao.atom))->getSectionIndex() == expectedSectionIndex )
3563 // The atom found is not in the section expected.
3564 // This probably means there was a label at the end of the section.
3565 // Do a slow sequential lookup
3566 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); ++it) {
3567 BaseAtom* atom = *it;
3568 if ( atom->getSectionIndex() == expectedSectionIndex ) {
3569 pint_t objAddr = atom->getObjectAddress();
3570 if ( (objAddr == addr) || ((objAddr < addr) && (objAddr+atom->getSize() > addr)) ) {
3571 return AtomAndOffset(atom, addr-atom->getObjectAddress());
3576 return AtomAndOffset(NULL);
3579 template <typename A>
3580 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
3582 // STL has no built-in for "find largest key that is same or less than"
3583 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
3584 // if no atoms up to this address return none found
3585 if ( it == fAddrToAtom.begin() )
3586 return AtomAndOffset(NULL);
3587 // otherwise upper_bound gets us next key, so we back up one
3589 AtomAndOffset result;
3590 result.atom = it->second;
3591 result.offset = addr - it->first;
3592 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
3593 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
3597 // "scattered" relocations enable you to offset into an atom past the end of it
3598 // baseAddr is the address of the target atom,
3599 // realAddr is the points into it
3600 template <typename A>
3601 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
3603 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
3604 if ( it != fAddrToAtom.end() ) {
3605 AtomAndOffset result;
3606 result.atom = it->second;
3607 result.offset = realAddr - it->first;
3608 if ( result.atom->isThumb() )
3609 result.offset &= -2;
3610 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
3613 // getting here means we have a scattered relocation to an address without a label
3614 // we should never get here...
3615 // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
3616 return findAtomAndOffset(realAddr);
3620 /* Skip over a LEB128 value (signed or unsigned). */
3622 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
3624 while (*offset != end && **offset >= 0x80)
3630 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
3631 or error. On overflow, skip past the rest of the uleb128. */
3633 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
3635 uint64_t result = 0;
3642 return (uint64_t) -1;
3644 b = **offset & 0x7f;
3646 if (bit >= 64 || b << bit >> bit != b)
3647 result = (uint64_t) -1;
3649 result |= b << bit, bit += 7;
3650 } while (*(*offset)++ >= 0x80);
3655 /* Skip over a DWARF attribute of form FORM. */
3656 template <typename A>
3657 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
3658 uint8_t addr_size, bool dwarf64)
3668 case DW_FORM_block2:
3669 if (end - *offset < 2)
3671 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
3674 case DW_FORM_block4:
3675 if (end - *offset < 4)
3677 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
3695 case DW_FORM_string:
3696 while (*offset != end && **offset)
3705 sz = read_uleb128 (offset, end);
3708 case DW_FORM_block1:
3716 case DW_FORM_ref_udata:
3717 skip_leb128 (offset, end);
3721 case DW_FORM_ref_addr:
3728 if (end - *offset < sz)
3734 template <typename A>
3735 const char* Reader<A>::getDwarfString(uint64_t form, const uint8_t* p)
3737 if ( form == DW_FORM_string )
3738 return (const char*)p;
3739 else if ( form == DW_FORM_strp ) {
3740 uint32_t offset = E::get32(*((uint32_t*)p));
3741 const char* dwarfStrings = (char*)(fHeader) + fDwarfDebugStringSect->offset();
3742 if ( offset > fDwarfDebugStringSect->size() ) {
3743 warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->getPath());
3746 return &dwarfStrings[offset];
3748 warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->getPath());
3753 // Look at the compilation unit DIE and determine
3754 // its NAME, compilation directory (in COMP_DIR) and its
3755 // line number information offset (in STMT_LIST). NAME and COMP_DIR
3756 // may be NULL (especially COMP_DIR) if they are not in the .o file;
3757 // STMT_LIST will be (uint64_t) -1.
3759 // At present this assumes that there's only one compilation unit DIE.
3761 template <typename A>
3762 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
3763 uint64_t *stmt_list)
3765 const uint8_t * debug_info;
3766 const uint8_t * debug_abbrev;
3769 const uint8_t * end;
3770 const uint8_t * enda;
3773 uint64_t abbrev_base;
3775 uint8_t address_size;
3780 *stmt_list = (uint64_t) -1;
3782 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
3785 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
3786 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
3789 if (fDwarfDebugInfoSect->size() < 12)
3790 /* Too small to be a real debug_info section. */
3792 sz = A::P::E::get32(*(uint32_t*)di);
3794 dwarf64 = sz == 0xffffffff;
3796 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
3797 else if (sz > 0xffffff00)
3798 /* Unknown dwarf format. */
3801 /* Verify claimed size. */
3802 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
3805 vers = A::P::E::get16(*(uint16_t*)di);
3806 if (vers < 2 || vers > 3)
3807 /* DWARF version wrong for this code.
3808 Chances are we could continue anyway, but we don't know for sure. */
3812 /* Find the debug_abbrev section. */
3813 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
3814 di += dwarf64 ? 8 : 4;
3816 if (abbrev_base > fDwarfDebugAbbrevSect->size())
3818 da = debug_abbrev + abbrev_base;
3819 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
3821 address_size = *di++;
3823 /* Find the abbrev number we're looking for. */
3825 abbrev = read_uleb128 (&di, end);
3826 if (abbrev == (uint64_t) -1)
3829 /* Skip through the debug_abbrev section looking for that abbrev. */
3832 uint64_t this_abbrev = read_uleb128 (&da, enda);
3835 if (this_abbrev == abbrev)
3836 /* This is almost always taken. */
3838 skip_leb128 (&da, enda); /* Skip the tag. */
3841 da++; /* Skip the DW_CHILDREN_* value. */
3844 attr = read_uleb128 (&da, enda);
3845 skip_leb128 (&da, enda);
3846 } while (attr != 0 && attr != (uint64_t) -1);
3851 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
3852 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
3856 da++; /* Skip the DW_CHILDREN_* value. */
3858 /* Now, go through the DIE looking for DW_AT_name,
3859 DW_AT_comp_dir, and DW_AT_stmt_list. */
3862 uint64_t attr = read_uleb128 (&da, enda);
3863 uint64_t form = read_uleb128 (&da, enda);
3865 if (attr == (uint64_t) -1)
3870 if (form == DW_FORM_indirect)
3871 form = read_uleb128 (&di, end);
3873 if (attr == DW_AT_name)
3874 *name = getDwarfString(form, di);
3875 else if (attr == DW_AT_comp_dir)
3876 *comp_dir = getDwarfString(form, di);
3877 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
3878 *stmt_list = A::P::E::get32(*(uint32_t*)di);
3879 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
3880 *stmt_list = A::P::E::get64(*(uint64_t*)di);
3881 if (! skip_form (&di, end, form, address_size, dwarf64))
3886 template <typename A>
3887 const char* Reader<A>::assureFullPath(const char* path)
3889 if ( path[0] == '/' )
3891 char cwdbuff[MAXPATHLEN];
3892 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
3894 asprintf(&result, "%s/%s", cwdbuff, path);
3895 if ( result != NULL )
3904 // To implement architecture xxx, you must write template specializations for the following six methods:
3905 // Reader<xxx>::validFile()
3906 // Reader<xxx>::addRelocReference()
3907 // Reference<xxx>::getDescription()
3913 bool Reader<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
3915 const macho_header<P>* header = (const macho_header<P>*)fileContent;
3916 if ( header->magic() != MH_MAGIC )
3918 if ( header->cputype() != CPU_TYPE_POWERPC )
3920 if ( header->filetype() != MH_OBJECT )
3926 bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
3928 const macho_header<P>* header = (const macho_header<P>*)fileContent;
3929 if ( header->magic() != MH_MAGIC_64 )
3931 if ( header->cputype() != CPU_TYPE_POWERPC64 )
3933 if ( header->filetype() != MH_OBJECT )
3939 bool Reader<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
3941 const macho_header<P>* header = (const macho_header<P>*)fileContent;
3942 if ( header->magic() != MH_MAGIC )
3944 if ( header->cputype() != CPU_TYPE_I386 )
3946 if ( header->filetype() != MH_OBJECT )
3952 bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
3954 const macho_header<P>* header = (const macho_header<P>*)fileContent;
3955 if ( header->magic() != MH_MAGIC_64 )
3957 if ( header->cputype() != CPU_TYPE_X86_64 )
3959 if ( header->filetype() != MH_OBJECT )
3965 bool Reader<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
3967 const macho_header<P>* header = (const macho_header<P>*)fileContent;
3968 if ( header->magic() != MH_MAGIC )
3970 if ( header->cputype() != CPU_TYPE_ARM )
3972 if ( header->filetype() != MH_OBJECT )
3974 if ( subtypeMustMatch && ((cpu_subtype_t)header->cpusubtype() != subtype) )
3979 template <typename A>
3980 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
3982 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
3986 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
3988 return addRelocReference_powerpc(sect, reloc);
3992 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
3994 return addRelocReference_powerpc(sect, reloc);
3999 // ppc and ppc64 both use the same relocations, so process them in one common routine
4001 template <typename A>
4002 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
4003 const macho_relocation_info<typename A::P>* reloc)
4008 int32_t displacement = 0;
4009 uint32_t instruction = 0;
4010 uint32_t offsetInTarget;
4012 bool result = false;
4013 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4014 const macho_relocation_info<P>* nextReloc = &reloc[1];
4015 const char* targetName = NULL;
4016 bool weakImport = false;
4017 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4018 if ( reloc->r_type() != PPC_RELOC_PAIR )
4019 instruction = BigEndian::get32(*fixUpPtr);
4020 srcAddr = sect->addr() + reloc->r_address();
4021 if ( reloc->r_extern() ) {
4022 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4023 targetName = &fStrings[targetSymbol->n_strx()];
4024 weakImport = this->isWeakImportSymbol(targetSymbol);
4026 switch ( reloc->r_type() ) {
4027 case PPC_RELOC_BR24:
4029 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4030 displacement = (instruction & 0x03FFFFFC);
4031 if ( (displacement & 0x02000000) != 0 )
4032 displacement |= 0xFC000000;
4035 printf("bad instruction for BR24 reloc");
4037 if ( reloc->r_extern() ) {
4038 offsetInTarget = srcAddr + displacement;
4039 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4040 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4041 addDtraceExtraInfos(srcAddr, &targetName[16]);
4043 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4044 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4045 addDtraceExtraInfos(srcAddr, &targetName[20]);
4047 else if ( weakImport )
4048 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
4050 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
4053 dstAddr = srcAddr + displacement;
4054 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
4055 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
4056 targetName = atom->getName();
4057 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4058 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4059 addDtraceExtraInfos(srcAddr, &targetName[16]);
4061 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4062 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4063 addDtraceExtraInfos(srcAddr, &targetName[20]);
4065 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4066 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
4067 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
4069 makeReference(A::kBranch24, srcAddr, dstAddr);
4073 case PPC_RELOC_BR14:
4075 displacement = (instruction & 0x0000FFFC);
4076 if ( (displacement & 0x00008000) != 0 )
4077 displacement |= 0xFFFF0000;
4078 if ( reloc->r_extern() ) {
4079 offsetInTarget = srcAddr + displacement;
4080 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
4083 dstAddr = srcAddr + displacement;
4084 makeReference(A::kBranch14, srcAddr, dstAddr);
4088 case PPC_RELOC_PAIR:
4089 // skip, processed by a previous look ahead
4091 case PPC_RELOC_LO16:
4093 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4094 throw "PPC_RELOC_LO16 missing following pair";
4097 lowBits = (instruction & 0xFFFF);
4098 if ( reloc->r_extern() ) {
4099 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4100 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
4103 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4104 if ( reloc->r_symbolnum() == R_ABS ) {
4105 // find absolute symbol that corresponds to pointerValue
4106 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4107 if ( pos != fAddrToAbsoluteAtom.end() )
4108 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
4110 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4113 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4118 case PPC_RELOC_LO14:
4120 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4121 throw "PPC_RELOC_LO14 missing following pair";
4124 lowBits = (instruction & 0xFFFC);
4125 if ( reloc->r_extern() ) {
4126 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4127 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
4130 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4131 if ( reloc->r_symbolnum() == R_ABS ) {
4132 // find absolute symbol that corresponds to pointerValue
4133 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4134 if ( pos != fAddrToAbsoluteAtom.end() )
4135 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
4137 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4140 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4145 case PPC_RELOC_HI16:
4147 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4148 throw "PPC_RELOC_HI16 missing following pair";
4151 if ( reloc->r_extern() ) {
4152 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4153 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
4156 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4157 if ( reloc->r_symbolnum() == R_ABS ) {
4158 // find absolute symbol that corresponds to pointerValue
4159 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4160 if ( pos != fAddrToAbsoluteAtom.end() )
4161 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
4163 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4166 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4171 case PPC_RELOC_HA16:
4173 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4174 throw "PPC_RELOC_HA16 missing following pair";
4177 lowBits = (nextReloc->r_address() & 0x0000FFFF);
4178 if ( reloc->r_extern() ) {
4179 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4180 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
4183 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4184 if ( reloc->r_symbolnum() == R_ABS ) {
4185 // find absolute symbol that corresponds to pointerValue
4186 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4187 if ( pos != fAddrToAbsoluteAtom.end() )
4188 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
4190 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4193 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4198 case PPC_RELOC_VANILLA:
4200 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
4201 if ( reloc->r_extern() ) {
4203 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
4205 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
4208 new Reference<A>(A::kPointer, findAtomAndOffset(srcAddr), findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()));
4212 case PPC_RELOC_JBSR:
4213 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
4214 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4215 throw "PPC_RELOC_JBSR missing following pair";
4217 if ( !fHasLongBranchStubs )
4218 warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath);
4219 fHasLongBranchStubs = true;
4221 if ( reloc->r_extern() ) {
4222 throw "PPC_RELOC_JBSR should not be using an external relocation";
4224 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
4225 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4226 displacement = (instruction & 0x03FFFFFC);
4227 if ( (displacement & 0x02000000) != 0 )
4228 displacement |= 0xFC000000;
4231 fprintf(stderr, "bad instruction for BR24 reloc");
4235 warning("unknown relocation type %d", reloc->r_type());
4239 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4240 srcAddr = sect->addr() + sreloc->r_address();
4241 dstAddr = sreloc->r_value();
4242 uint32_t betterDstAddr;
4243 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4244 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4245 const macho_relocation_info<P>* nextReloc = &reloc[1];
4246 // file format allows pair to be scattered or not
4247 bool nextRelocIsPair = false;
4248 uint32_t nextRelocAddress = 0;
4249 uint32_t nextRelocValue = 0;
4250 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4251 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
4252 nextRelocIsPair = true;
4253 nextRelocAddress = nextReloc->r_address();
4258 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
4259 nextRelocIsPair = true;
4260 nextRelocAddress = nextSReloc->r_address();
4261 nextRelocValue = nextSReloc->r_value();
4265 switch (sreloc->r_type()) {
4266 case PPC_RELOC_VANILLA:
4268 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
4269 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
4270 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4271 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
4274 case PPC_RELOC_BR14:
4276 instruction = BigEndian::get32(*fixUpPtr);
4277 displacement = (instruction & 0x0000FFFC);
4278 if ( (displacement & 0x00008000) != 0 )
4279 displacement |= 0xFFFF0000;
4280 betterDstAddr = srcAddr+displacement;
4281 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
4282 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
4285 case PPC_RELOC_BR24:
4287 instruction = BigEndian::get32(*fixUpPtr);
4288 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4289 displacement = (instruction & 0x03FFFFFC);
4290 if ( (displacement & 0x02000000) != 0 )
4291 displacement |= 0xFC000000;
4292 betterDstAddr = srcAddr+displacement;
4293 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
4297 case PPC_RELOC_LO16_SECTDIFF:
4299 if ( ! nextRelocIsPair ) {
4300 throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
4302 instruction = BigEndian::get32(*fixUpPtr);
4303 lowBits = (instruction & 0xFFFF);
4304 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4305 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4308 case PPC_RELOC_LO14_SECTDIFF:
4310 if ( ! nextRelocIsPair ) {
4311 throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
4313 instruction = BigEndian::get32(*fixUpPtr);
4314 lowBits = (instruction & 0xFFFC);
4315 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4316 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4319 case PPC_RELOC_HA16_SECTDIFF:
4321 if ( ! nextRelocIsPair ) {
4322 throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
4324 instruction = BigEndian::get32(*fixUpPtr);
4325 lowBits = (nextRelocAddress & 0x0000FFFF);
4326 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4327 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4330 case PPC_RELOC_LO14:
4332 if ( ! nextRelocIsPair ) {
4333 throw "PPC_RELOC_LO14 missing following pair";
4335 instruction = BigEndian::get32(*fixUpPtr);
4336 lowBits = (instruction & 0xFFFC);
4337 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4338 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
4341 case PPC_RELOC_LO16:
4343 if ( ! nextRelocIsPair ) {
4344 throw "PPC_RELOC_LO16 missing following pair";
4346 instruction = BigEndian::get32(*fixUpPtr);
4347 lowBits = (instruction & 0xFFFF);
4348 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4349 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
4352 case PPC_RELOC_HA16:
4354 if ( ! nextRelocIsPair ) {
4355 throw "PPC_RELOC_HA16 missing following pair";
4357 instruction = BigEndian::get32(*fixUpPtr);
4358 lowBits = (nextRelocAddress & 0xFFFF);
4359 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
4360 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
4363 case PPC_RELOC_HI16:
4365 if ( ! nextRelocIsPair ) {
4366 throw "PPC_RELOC_HI16 missing following pair";
4368 instruction = BigEndian::get32(*fixUpPtr);
4369 lowBits = (nextRelocAddress & 0xFFFF);
4370 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
4371 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
4374 case PPC_RELOC_SECTDIFF:
4375 case PPC_RELOC_LOCAL_SECTDIFF:
4377 if ( ! nextRelocIsPair ) {
4378 throw "PPC_RELOC_SECTDIFF missing following pair";
4380 Kinds kind = A::kPointerDiff32;;
4381 uint32_t contentAddr = 0;
4382 switch ( sreloc->r_length() ) {
4384 throw "bad diff relocations r_length (0) for ppc architecture";
4386 kind = A::kPointerDiff16;
4387 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
4390 kind = A::kPointerDiff32;
4391 contentAddr = BigEndian::get32(*fixUpPtr);
4394 kind = A::kPointerDiff64;
4395 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
4398 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4399 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4400 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4401 // check for addend encoded in the section content
4402 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4403 // dstAddr, nextRelocValue, contentAddr);
4404 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4405 if ( toao.atom == srcao.atom )
4406 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4407 else if ( fromao.atom == srcao.atom )
4408 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4410 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4412 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4413 // srcao.atom->getDisplayName(), srcao.offset,
4414 // fromao.atom->getDisplayName(), fromao.offset,
4415 // toao.atom->getDisplayName(), toao.offset);
4416 new Reference<A>(kind, srcao, fromao, toao);
4419 case PPC_RELOC_PAIR:
4421 case PPC_RELOC_HI16_SECTDIFF:
4422 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
4425 warning("unknown scattered relocation type %d", sreloc->r_type());
4433 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
4438 bool result = false;
4439 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4440 srcAddr = sect->addr() + reloc->r_address();
4441 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4442 switch ( reloc->r_type() ) {
4443 case GENERIC_RELOC_VANILLA:
4445 x86::ReferenceKinds kind = x86::kPointer;
4446 uint32_t pointerValue = E::get32(*fixUpPtr);
4447 if ( reloc->r_pcrel() ) {
4448 switch( reloc->r_length() ) {
4450 kind = x86::kPCRel8;
4451 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
4454 kind = x86::kPCRel16;
4455 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
4458 kind = x86::kPCRel32;
4459 pointerValue += srcAddr + sizeof(uint32_t);
4462 throw "bad pc-rel vanilla relocation length";
4465 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
4466 kind = x86::kAbsolute32;
4467 if ( reloc->r_length() != 2 )
4468 throw "bad vanilla relocation length";
4471 kind = x86::kPointer;
4472 if ( reloc->r_length() != 2 )
4473 throw "bad vanilla relocation length";
4475 if ( reloc->r_extern() ) {
4476 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4477 if ( this->isWeakImportSymbol(targetSymbol) ) {
4478 if ( reloc->r_pcrel() )
4479 kind = x86::kPCRel32WeakImport;
4481 kind = x86::kPointerWeakImport;
4483 const char* targetName = &fStrings[targetSymbol->n_strx()];
4484 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4485 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4486 addDtraceExtraInfos(srcAddr, &targetName[16]);
4488 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4489 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4490 addDtraceExtraInfos(srcAddr, &targetName[20]);
4493 makeByNameReference(kind, srcAddr, targetName, pointerValue);
4496 AtomAndOffset targetAO = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
4497 const char* targetName = targetAO.atom->getName();
4498 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4499 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4500 addDtraceExtraInfos(srcAddr, &targetName[16]);
4502 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4503 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4504 addDtraceExtraInfos(srcAddr, &targetName[20]);
4506 // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol
4507 else if ( reloc->r_pcrel() && (targetAO.atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4508 && ((AnonymousAtom<x86>*)targetAO.atom)->isWeakImportStub() )
4509 new Reference<x86>(x86::kPCRel32WeakImport, findAtomAndOffset(srcAddr), targetAO);
4510 else if ( reloc->r_symbolnum() != R_ABS )
4511 new Reference<x86>(kind, findAtomAndOffset(srcAddr), targetAO);
4513 // find absolute symbol that corresponds to pointerValue
4514 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
4515 if ( pos != fAddrToAbsoluteAtom.end() )
4516 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
4518 throwf("R_ABS reloc but no absolute symbol at target address");
4524 warning("unknown relocation type %d", reloc->r_type());
4528 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4529 srcAddr = sect->addr() + sreloc->r_address();
4530 dstAddr = sreloc->r_value();
4531 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4532 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4533 const macho_relocation_info<P>* nextReloc = &reloc[1];
4534 pint_t betterDstAddr;
4535 // file format allows pair to be scattered or not
4536 bool nextRelocIsPair = false;
4537 uint32_t nextRelocAddress = 0;
4538 uint32_t nextRelocValue = 0;
4539 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4540 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
4541 nextRelocIsPair = true;
4542 nextRelocAddress = nextReloc->r_address();
4547 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
4548 nextRelocIsPair = true;
4549 nextRelocAddress = nextSReloc->r_address();
4550 nextRelocValue = nextSReloc->r_value();
4553 switch (sreloc->r_type()) {
4554 case GENERIC_RELOC_VANILLA:
4555 betterDstAddr = LittleEndian::get32(*fixUpPtr);
4556 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
4557 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4558 if ( sreloc->r_pcrel() ) {
4559 switch ( sreloc->r_length() ) {
4561 betterDstAddr += srcAddr + 4;
4562 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
4565 betterDstAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)) + srcAddr + 2;
4566 makeReferenceWithToBase(x86::kPCRel16, srcAddr, betterDstAddr, dstAddr);
4569 betterDstAddr = *((uint8_t*)fixUpPtr) + srcAddr + 1;
4570 makeReferenceWithToBase(x86::kPCRel8, srcAddr, betterDstAddr, dstAddr);
4573 throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc");
4578 if ( sreloc->r_length() != 2 )
4579 throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
4580 if ( strcmp(sect->segname(), "__TEXT") == 0 )
4581 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
4583 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
4586 case GENERIC_RELOC_SECTDIFF:
4587 case GENERIC_RELOC_LOCAL_SECTDIFF:
4589 if ( !nextRelocIsPair ) {
4590 throw "GENERIC_RELOC_SECTDIFF missing following pair";
4592 x86::ReferenceKinds kind = x86::kPointerDiff;
4593 uint32_t contentAddr = 0;
4594 switch ( sreloc->r_length() ) {
4597 throw "bad length for GENERIC_RELOC_SECTDIFF";
4599 kind = x86::kPointerDiff16;
4600 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
4603 kind = x86::kPointerDiff;
4604 contentAddr = LittleEndian::get32(*fixUpPtr);
4607 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4608 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4609 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4610 // check for addend encoded in the section content
4611 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4612 // dstAddr, nextRelocValue, contentAddr);
4613 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4614 if ( toao.atom == srcao.atom )
4615 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4616 else if ( fromao.atom == srcao.atom )
4617 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4619 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4621 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4622 // srcao.atom->getDisplayName(), srcao.offset,
4623 // fromao.atom->getDisplayName(), fromao.offset,
4624 // toao.atom->getDisplayName(), toao.offset);
4625 new Reference<x86>(kind, srcao, fromao, toao);
4628 case GENERIC_RELOC_PAIR:
4629 // do nothing, already used via a look ahead
4632 warning("unknown scattered relocation type %d", sreloc->r_type());
4639 bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
4642 uint64_t dstAddr = 0;
4645 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
4646 bool result = false;
4647 const macho_nlist<P>* targetSymbol = NULL;
4648 const char* targetName = NULL;
4649 srcAddr = sect->addr() + reloc->r_address();
4650 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4651 //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address());
4652 if ( reloc->r_extern() ) {
4653 targetSymbol = &fSymbols[reloc->r_symbolnum()];
4654 targetName = &fStrings[targetSymbol->n_strx()];
4656 switch ( reloc->r_type() ) {
4657 case X86_64_RELOC_UNSIGNED:
4658 if ( reloc->r_pcrel() )
4659 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
4660 switch ( reloc->r_length() ) {
4663 throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
4665 kind = x86_64::kPointer32;
4668 kind = x86_64::kPointer;
4671 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
4672 if ( reloc->r_extern() ) {
4673 makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
4676 makeReference(kind, srcAddr, dstAddr);
4677 // verify that dstAddr is in the section being targeted
4678 int sectNum = reloc->r_symbolnum();
4679 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
4680 const macho_section<P>* const targetSection = §ionsStart[sectNum-1];
4681 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
4682 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4683 srcAddr, sect->sectname(), targetSection->sectname());
4687 case X86_64_RELOC_SIGNED:
4688 case X86_64_RELOC_SIGNED_1:
4689 case X86_64_RELOC_SIGNED_2:
4690 case X86_64_RELOC_SIGNED_4:
4691 if ( ! reloc->r_pcrel() )
4692 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
4693 if ( reloc->r_length() != 2 )
4694 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
4695 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4696 if ( reloc->r_extern() ) {
4697 switch ( reloc->r_type() ) {
4698 case X86_64_RELOC_SIGNED:
4699 kind = x86_64::kPCRel32;
4700 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
4701 if ( addend == (uint64_t)(-1) ) {
4703 kind = x86_64::kPCRel32_1;
4705 else if ( addend == (uint64_t)(-2) ) {
4707 kind = x86_64::kPCRel32_2;
4709 else if ( addend == (uint64_t)(-4) ) {
4711 kind = x86_64::kPCRel32_4;
4714 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
4715 case X86_64_RELOC_SIGNED_1:
4716 kind = x86_64::kPCRel32_1;
4719 case X86_64_RELOC_SIGNED_2:
4720 kind = x86_64::kPCRel32_2;
4723 case X86_64_RELOC_SIGNED_4:
4724 kind = x86_64::kPCRel32_4;
4728 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
4731 uint64_t ripRelativeOffset = addend;
4732 switch ( reloc->r_type() ) {
4733 case X86_64_RELOC_SIGNED:
4734 dstAddr = srcAddr + 4 + ripRelativeOffset;
4735 kind = x86_64::kPCRel32;
4737 case X86_64_RELOC_SIGNED_1:
4738 dstAddr = srcAddr + 5 + ripRelativeOffset;
4739 kind = x86_64::kPCRel32_1;
4741 case X86_64_RELOC_SIGNED_2:
4742 dstAddr = srcAddr + 6 + ripRelativeOffset;
4743 kind = x86_64::kPCRel32_2;
4745 case X86_64_RELOC_SIGNED_4:
4746 dstAddr = srcAddr + 8 + ripRelativeOffset;
4747 kind = x86_64::kPCRel32_4;
4750 makeReference(kind, srcAddr, dstAddr);
4751 // verify that dstAddr is in the section being targeted
4752 int sectNum = reloc->r_symbolnum();
4753 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
4754 const macho_section<P>* const targetSection = §ionsStart[sectNum-1];
4755 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
4756 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4757 srcAddr, sect->sectname(), targetSection->sectname());
4761 case X86_64_RELOC_BRANCH:
4762 if ( ! reloc->r_pcrel() )
4763 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
4764 if ( reloc->r_length() == 2 ) {
4765 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4766 if ( reloc->r_extern() ) {
4767 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4768 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
4769 addDtraceExtraInfos(srcAddr, &targetName[16]);
4771 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4772 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4773 addDtraceExtraInfos(srcAddr, &targetName[16]);
4775 else if ( isWeakImportSymbol(targetSymbol) )
4776 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
4778 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
4781 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
4784 else if ( reloc->r_length() == 0 ) {
4785 dstAddr = *((int8_t*)fixUpPtr);
4786 if ( reloc->r_extern() ) {
4787 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
4790 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
4794 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
4797 case X86_64_RELOC_GOT:
4798 if ( ! reloc->r_extern() )
4799 throw "not extern and X86_64_RELOC_GOT not supported";
4800 if ( ! reloc->r_pcrel() )
4801 throw "not pcrel and X86_64_RELOC_GOT not supported";
4802 if ( reloc->r_length() != 2 )
4803 throw "length != 2 and X86_64_RELOC_GOT not supported";
4804 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4805 if ( isWeakImportSymbol(targetSymbol) )
4806 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
4808 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
4810 case X86_64_RELOC_GOT_LOAD:
4811 if ( ! reloc->r_extern() )
4812 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
4813 if ( ! reloc->r_pcrel() )
4814 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
4815 if ( reloc->r_length() != 2 )
4816 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
4817 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4818 if ( isWeakImportSymbol(targetSymbol) )
4819 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
4821 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
4823 case X86_64_RELOC_SUBTRACTOR:
4825 if ( reloc->r_pcrel() )
4826 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
4827 if ( reloc->r_length() < 2 )
4828 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
4829 if ( !reloc->r_extern() )
4830 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
4831 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
4832 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
4833 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
4835 if ( nextReloc->r_pcrel() )
4836 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
4837 if ( nextReloc->r_length() != reloc->r_length() )
4838 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
4839 Reference<x86_64>* ref;
4840 bool negativeAddend;
4841 if ( reloc->r_length() == 2 ) {
4842 kind = x86_64::kPointerDiff32;
4843 dstAddr = E::get32(*fixUpPtr); // addend is in content
4844 negativeAddend = ((dstAddr & 0x80000000) != 0);
4847 kind = x86_64::kPointerDiff;
4848 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
4849 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
4851 AtomAndOffset inAtomAndOffset = this->findAtomAndOffset(srcAddr);
4852 ObjectFile::Atom* inAtom = inAtomAndOffset.atom;
4853 // create reference with "to" target
4854 if ( nextReloc->r_extern() ) {
4855 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
4856 const char* targetName = &fStrings[targetSymbol->n_strx()];
4857 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
4858 // if "to" is in this atom, change by-name to a direct reference
4859 if ( strcmp(targetName, inAtom->getName()) == 0 )
4860 ref->setTarget(*inAtom, 0);
4863 ref = makeReference(kind, srcAddr, dstAddr);
4865 // add in "from" target
4866 if ( reloc->r_extern() ) {
4867 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
4868 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
4869 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
4870 // from target is translation unit scoped, so use a direct reference
4871 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
4873 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
4874 // if "from" is in this atom, change by-name to a direct reference
4875 ref->setFromTarget(*inAtom);
4878 // some non-static other atom
4879 ref->setFromTargetName(fromTargetName);
4883 throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0";
4885 // addend goes in from side iff negative
4886 if ( negativeAddend )
4887 ref->setFromTargetOffset(-dstAddr);
4889 ref->setToTargetOffset(dstAddr);
4893 warning("unknown relocation type %d", reloc->r_type());
4899 /// Reader<arm>::addRelocReference -
4900 /// turns arm relocation entries into references. Returns true if the next
4901 /// relocation should be skipped, false otherwise.
4903 bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
4904 const macho_relocation_info<arm::P>* reloc)
4906 uint32_t * fixUpPtr;
4907 int32_t displacement;
4908 uint32_t instruction = 0;
4909 bool result = false;
4912 uint32_t pointerValue;
4913 arm::ReferenceKinds kind = arm::kNoFixUp;
4915 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4916 // non-scattered relocation
4917 const char* targetName = NULL;
4918 bool weakImport = false;
4920 srcAddr = sect->addr() + reloc->r_address();
4921 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4922 if ( reloc->r_type() != ARM_RELOC_PAIR )
4923 instruction = LittleEndian::get32(*fixUpPtr);
4925 if ( reloc->r_extern() ) {
4926 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4927 targetName = &fStrings[targetSymbol->n_strx()];
4928 weakImport = this->isWeakImportSymbol(targetSymbol);
4931 switch ( reloc->r_type() ) {
4932 case ARM_RELOC_BR24:
4933 // Sign-extend displacement
4934 displacement = (instruction & 0x00FFFFFF) << 2;
4935 if ( (displacement & 0x02000000) != 0 )
4936 displacement |= 0xFC000000;
4937 // The pc added will be +8 from the pc
4939 // If this is BLX add H << 1
4940 if ((instruction & 0xFE000000) == 0xFA000000)
4941 displacement += ((instruction & 0x01000000) >> 23);
4943 if ( reloc->r_extern() ) {
4944 uint32_t offsetInTarget = srcAddr + displacement;
4945 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4946 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
4947 addDtraceExtraInfos(srcAddr, &targetName[16]);
4949 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4950 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4951 addDtraceExtraInfos(srcAddr, &targetName[20]);
4953 else if ( weakImport )
4954 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
4956 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
4959 dstAddr = srcAddr + displacement;
4960 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
4961 // check for dtrace probes and weak_import stubs
4962 const char* targetName = atom->getName();
4963 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4964 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
4965 addDtraceExtraInfos(srcAddr, &targetName[16]);
4967 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4968 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4969 addDtraceExtraInfos(srcAddr, &targetName[20]);
4971 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4972 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
4973 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
4974 else if ( reloc->r_symbolnum() != R_ABS )
4975 makeReference(arm::kBranch24, srcAddr, dstAddr);
4977 // find absolute symbol that corresponds to pointerValue
4978 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4979 if ( pos != fAddrToAbsoluteAtom.end() )
4980 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
4982 throwf("R_ABS reloc but no absolute symbol at target address");
4987 case ARM_THUMB_RELOC_BR22:
4988 // thumb2 added two more bits to displacement, complicating the displacement decoding
4990 uint32_t s = (instruction >> 10) & 0x1;
4991 uint32_t j1 = (instruction >> 29) & 0x1;
4992 uint32_t j2 = (instruction >> 27) & 0x1;
4993 uint32_t imm10 = instruction & 0x3FF;
4994 uint32_t imm11 = (instruction >> 16) & 0x7FF;
4995 uint32_t i1 = (j1 == s);
4996 uint32_t i2 = (j2 == s);
4997 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5001 displacement = sdis;
5003 // The pc added will be +4 from the pc
5005 // If the instruction was blx, force the low 2 bits to be clear
5006 dstAddr = srcAddr + displacement;
5007 if ((instruction & 0xF8000000) == 0xE8000000)
5008 dstAddr &= 0xFFFFFFFC;
5010 if ( reloc->r_extern() ) {
5011 uint32_t offsetInTarget = dstAddr;
5012 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5013 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5014 addDtraceExtraInfos(srcAddr, &targetName[16]);
5016 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5017 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5018 addDtraceExtraInfos(srcAddr, &targetName[20]);
5020 else if ( weakImport )
5021 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
5023 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
5026 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5027 // check for dtrace probes and weak_import stubs
5028 const char* targetName = atom->getName();
5029 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5030 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5031 addDtraceExtraInfos(srcAddr, &targetName[16]);
5033 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5034 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5035 addDtraceExtraInfos(srcAddr, &targetName[20]);
5037 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5038 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5039 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
5040 else if ( reloc->r_symbolnum() != R_ABS )
5041 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
5043 // find absolute symbol that corresponds to pointerValue
5044 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5045 if ( pos != fAddrToAbsoluteAtom.end() )
5046 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
5048 throwf("R_ABS reloc but no absolute symbol at target address");
5053 case ARM_RELOC_VANILLA:
5054 if ( reloc->r_length() != 2 )
5055 throw "bad length for ARM_RELOC_VANILLA";
5057 pointerValue = instruction;
5058 kind = arm::kPointer;
5059 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5060 kind = arm::kReadOnlyPointer;
5062 kind = arm::kPointerWeakImport;
5063 if ( reloc->r_extern() ) {
5064 makeByNameReference(kind, srcAddr, targetName, pointerValue);
5067 AtomAndOffset at = findAtomAndOffset(srcAddr);
5068 AtomAndOffset to = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
5069 if ( to.atom->isThumb() )
5071 new Reference<arm>(kind, at, to);
5075 case ARM_THUMB_32BIT_BRANCH:
5076 // work around for <rdar://problem/6489480>
5080 warning("unexpected relocation type %u", reloc->r_type());
5085 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
5086 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
5087 srcAddr = sect->addr() + sreloc->r_address();
5088 dstAddr = sreloc->r_value();
5089 uint32_t betterDstAddr;
5090 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
5091 instruction = LittleEndian::get32(*fixUpPtr);
5093 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
5094 // relocation types, and it is an error to see one otherwise.
5095 bool nextRelocIsPair = false;
5096 uint32_t nextRelocAddress = 0;
5097 uint32_t nextRelocValue = 0;
5098 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
5099 nextRelocIsPair = true;
5100 nextRelocAddress = nextSReloc->r_address();
5101 nextRelocValue = nextSReloc->r_value();
5105 switch (sreloc->r_type()) {
5106 case ARM_RELOC_VANILLA:
5107 if ( sreloc->r_length() != 2 )
5108 throw "bad length for ARM_RELOC_VANILLA";
5110 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
5111 betterDstAddr = LittleEndian::get32(*fixUpPtr);
5112 kind = arm::kPointer;
5113 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5114 kind = arm::kReadOnlyPointer;
5115 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
5116 makeReferenceWithToBase(kind, srcAddr, betterDstAddr, dstAddr);
5119 case ARM_RELOC_BR24:
5120 // Sign-extend displacement
5121 displacement = (instruction & 0x00FFFFFF) << 2;
5122 if ( (displacement & 0x02000000) != 0 )
5123 displacement |= 0xFC000000;
5124 // The pc added will be +8 from the pc
5126 // If this is BLX add H << 1
5127 if ((instruction & 0xFE000000) == 0xFA000000)
5128 displacement += ((instruction & 0x01000000) >> 23);
5129 betterDstAddr = srcAddr+displacement;
5130 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
5133 case ARM_THUMB_RELOC_BR22:
5134 // thumb2 added two more bits to displacement, complicating the displacement decoding
5136 uint32_t s = (instruction >> 10) & 0x1;
5137 uint32_t j1 = (instruction >> 29) & 0x1;
5138 uint32_t j2 = (instruction >> 27) & 0x1;
5139 uint32_t imm10 = instruction & 0x3FF;
5140 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5141 uint32_t i1 = (j1 == s);
5142 uint32_t i2 = (j2 == s);
5143 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5147 displacement = sdis;
5149 // The pc added will be +4 from the pc
5151 betterDstAddr = srcAddr+displacement;
5152 // If the instruction was blx, force the low 2 bits to be clear
5153 if ((instruction & 0xF8000000) == 0xE8000000)
5154 betterDstAddr &= 0xFFFFFFFC;
5155 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
5158 case ARM_RELOC_SECTDIFF:
5159 case ARM_RELOC_LOCAL_SECTDIFF:
5160 if ( !nextRelocIsPair ) {
5161 throw "ARM_RELOC_SECTDIFF missing following pair";
5163 if ( sreloc->r_length() != 2 )
5164 throw "bad length for ARM_RELOC_SECTDIFF";
5166 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
5167 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
5168 AtomAndOffset toao = findAtomAndOffset(dstAddr);
5169 // check for addend encoded in the section content
5170 pointerValue = LittleEndian::get32(*fixUpPtr);
5171 if ( (dstAddr - nextRelocValue) != pointerValue ) {
5172 if ( toao.atom == srcao.atom )
5173 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
5174 else if ( fromao.atom == srcao.atom )
5175 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
5177 fromao.offset += (dstAddr - pointerValue) - nextRelocValue;
5179 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
5184 warning("unexpected srelocation type %u", sreloc->r_type());
5191 template <typename A>
5192 void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
5194 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
5195 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
5196 switch ( sect->flags() & SECTION_TYPE ) {
5197 case S_SYMBOL_STUBS:
5198 case S_LAZY_SYMBOL_POINTERS:
5199 // we ignore compiler generated stubs, so ignore those relocs too
5202 // ignore all relocations in __eh_frame section
5203 if ( sect == fehFrameSection )
5205 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
5206 const uint32_t relocCount = sect->nreloc();
5207 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
5208 for (uint32_t r = 0; r < relocCount; ++r) {
5210 if ( addRelocReference(sect, &relocs[r]) )
5213 catch (const char* msg) {
5214 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
5223 const char* Reference<x86>::getDescription() const
5225 static char temp[2048];
5228 sprintf(temp, "reference to ");
5230 case x86::kFollowOn:
5231 sprintf(temp, "followed by ");
5233 case x86::kGroupSubordinate:
5234 sprintf(temp, "group subordinate ");
5236 case x86::kPointerWeakImport:
5237 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5240 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5242 case x86::kPointerDiff:
5244 // by-name references have quoted names
5245 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5246 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5247 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5248 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5249 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5253 case x86::kPointerDiff16:
5255 // by-name references have quoted names
5256 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5257 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5258 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5259 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5260 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5264 case x86::kPCRel32WeakImport:
5265 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
5268 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
5271 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
5274 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
5276 case x86::kAbsolute32:
5277 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
5279 case x86::kImageOffset32:
5280 sprintf(temp, "offset 0x%04X, 32bit offset of ", fFixUpOffsetInSrc);
5282 case x86::kPointerDiff24:
5283 sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5284 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5285 this->getFromTargetDisplayName(), fFromTarget.offset );
5288 case x86::kDtraceProbe:
5289 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5291 case x86::kDtraceProbeSite:
5292 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5294 case x86::kDtraceIsEnabledSite:
5295 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5297 case x86::kDtraceTypeReference:
5298 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5301 // always quote by-name references
5302 if ( fToTargetName != NULL ) {
5304 strcat(temp, fToTargetName);
5307 else if ( fToTarget.atom != NULL ) {
5308 strcat(temp, fToTarget.atom->getDisplayName());
5311 strcat(temp, "NULL target");
5313 if ( fToTarget.offset != 0 )
5314 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5321 const char* Reference<ppc>::getDescription() const
5323 static char temp[2048];
5326 sprintf(temp, "reference to ");
5328 case ppc::kFollowOn:
5329 sprintf(temp, "followed by ");
5331 case ppc::kGroupSubordinate:
5332 sprintf(temp, "group subordinate ");
5334 case ppc::kPointerWeakImport:
5335 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5338 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5340 case ppc::kPointerDiff16:
5342 // by-name references have quoted names
5343 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5344 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5345 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5346 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5347 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5350 case ppc::kPointerDiff32:
5352 // by-name references have quoted names
5353 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5354 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5355 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5356 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5357 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5360 case ppc::kPointerDiff64:
5361 throw "unsupported refrence kind";
5363 case ppc::kBranch24WeakImport:
5364 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5366 case ppc::kBranch24:
5367 case ppc::kBranch14:
5368 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5370 case ppc::kPICBaseLow16:
5371 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5373 case ppc::kPICBaseLow14:
5374 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5376 case ppc::kPICBaseHigh16:
5377 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5379 case ppc::kAbsLow16:
5380 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5382 case ppc::kAbsLow14:
5383 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5385 case ppc::kAbsHigh16:
5386 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
5388 case ppc::kAbsHigh16AddLow:
5389 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5391 case ppc::kDtraceProbe:
5392 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5394 case ppc::kDtraceProbeSite:
5395 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5397 case ppc::kDtraceIsEnabledSite:
5398 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5400 case ppc::kDtraceTypeReference:
5401 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5404 // always quote by-name references
5405 if ( fToTargetName != NULL ) {
5407 strcat(temp, fToTargetName);
5410 else if ( fToTarget.atom != NULL ) {
5411 strcat(temp, fToTarget.atom->getDisplayName());
5414 strcat(temp, "NULL target");
5416 if ( fToTarget.offset != 0 )
5417 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5423 const char* Reference<ppc64>::getDescription() const
5425 static char temp[2048];
5427 case ppc64::kNoFixUp:
5428 sprintf(temp, "reference to ");
5430 case ppc64::kFollowOn:
5431 sprintf(temp, "followed by ");
5433 case ppc64::kGroupSubordinate:
5434 sprintf(temp, "group subordinate ");
5436 case ppc64::kPointerWeakImport:
5437 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5439 case ppc64::kPointer:
5440 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5442 case ppc64::kPointerDiff64:
5444 // by-name references have quoted names
5445 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5446 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5447 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5448 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5449 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5452 case ppc64::kPointerDiff32:
5454 // by-name references have quoted names
5455 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5456 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5457 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5458 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5459 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5462 case ppc64::kPointerDiff16:
5464 // by-name references have quoted names
5465 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5466 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5467 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5468 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5469 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5472 case ppc64::kBranch24WeakImport:
5473 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5475 case ppc64::kBranch24:
5476 case ppc64::kBranch14:
5477 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5479 case ppc64::kPICBaseLow16:
5480 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5482 case ppc64::kPICBaseLow14:
5483 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5485 case ppc64::kPICBaseHigh16:
5486 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5488 case ppc64::kAbsLow16:
5489 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5491 case ppc64::kAbsLow14:
5492 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5494 case ppc64::kAbsHigh16:
5495 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
5497 case ppc64::kAbsHigh16AddLow:
5498 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5500 case ppc64::kDtraceProbe:
5501 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5503 case ppc64::kDtraceProbeSite:
5504 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5506 case ppc64::kDtraceIsEnabledSite:
5507 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5509 case ppc64::kDtraceTypeReference:
5510 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5513 // always quote by-name references
5514 if ( fToTargetName != NULL ) {
5516 strcat(temp, fToTargetName);
5519 else if ( fToTarget.atom != NULL ) {
5520 strcat(temp, fToTarget.atom->getDisplayName());
5523 strcat(temp, "NULL target");
5525 if ( fToTarget.offset != 0 )
5526 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5533 const char* Reference<x86_64>::getDescription() const
5535 static char temp[2048];
5537 case x86_64::kNoFixUp:
5538 sprintf(temp, "reference to ");
5540 case x86_64::kFollowOn:
5541 sprintf(temp, "followed by ");
5543 case x86_64::kGroupSubordinate:
5544 sprintf(temp, "group subordinate ");
5546 case x86_64::kPointerWeakImport:
5547 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5549 case x86_64::kPointer:
5550 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5552 case x86_64::kPointer32:
5553 sprintf(temp, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc);
5555 case x86_64::kPointerDiff32:
5556 case x86_64::kPointerDiff:
5558 // by-name references have quoted names
5559 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5560 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5561 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
5562 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5563 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5564 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5568 case x86_64::kPCRel32:
5569 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
5571 case x86_64::kPCRel32_1:
5572 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
5574 case x86_64::kPCRel32_2:
5575 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
5577 case x86_64::kPCRel32_4:
5578 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
5580 case x86_64::kBranchPCRel32:
5581 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
5583 case x86_64::kBranchPCRel32WeakImport:
5584 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
5586 case x86_64::kPCRel32GOT:
5587 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5589 case x86_64::kPCRel32GOTWeakImport:
5590 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5592 case x86_64::kPCRel32GOTLoad:
5593 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5595 case x86_64::kPCRel32GOTLoadWeakImport:
5596 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5598 case x86_64::kGOTNoFixUp:
5599 sprintf(temp, "reference to GOT entry for ");
5601 case x86_64::kBranchPCRel8:
5602 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
5604 case x86_64::kPointerDiff24:
5605 sprintf(temp, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5606 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5607 this->getFromTargetDisplayName(), fFromTarget.offset );
5609 case x86_64::kImageOffset32:
5610 sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc);
5612 case x86_64::kDtraceProbe:
5613 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5615 case x86_64::kDtraceProbeSite:
5616 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5618 case x86_64::kDtraceIsEnabledSite:
5619 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5621 case x86_64::kDtraceTypeReference:
5622 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5625 // always quote by-name references
5626 if ( fToTargetName != NULL ) {
5628 strcat(temp, fToTargetName);
5631 else if ( fToTarget.atom != NULL ) {
5632 strcat(temp, fToTarget.atom->getDisplayName());
5635 strcat(temp, "NULL target");
5637 if ( fToTarget.offset != 0 )
5638 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5645 const char* Reference<arm>::getDescription() const
5647 static char temp[2048];
5650 sprintf(temp, "reference to ");
5652 case arm::kFollowOn:
5653 sprintf(temp, "followed by ");
5655 case arm::kGroupSubordinate:
5656 sprintf(temp, "group subordinate ");
5659 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5661 case arm::kPointerWeakImport:
5662 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5664 case arm::kPointerDiff:
5666 // by-name references have quoted names
5667 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5668 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5669 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5670 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5671 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5674 case arm::kReadOnlyPointer:
5675 sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc);
5677 case arm::kBranch24:
5678 case arm::kThumbBranch22:
5679 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5681 case arm::kBranch24WeakImport:
5682 case arm::kThumbBranch22WeakImport:
5683 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5685 case arm::kDtraceProbe:
5686 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5688 case arm::kDtraceProbeSite:
5689 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5691 case arm::kDtraceIsEnabledSite:
5692 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5694 case arm::kDtraceTypeReference:
5695 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5698 // always quote by-name references
5699 if ( fToTargetName != NULL ) {
5701 strcat(temp, fToTargetName);
5704 else if ( fToTarget.atom != NULL ) {
5705 strcat(temp, fToTarget.atom->getDisplayName());
5708 strcat(temp, "NULL target");
5710 if ( fToTarget.offset != 0 )
5711 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5718 bool Reference<x86>::isBranch() const
5722 case x86::kPCRel32WeakImport:
5730 bool Reference<x86_64>::isBranch() const
5733 case x86_64::kBranchPCRel32:
5734 case x86_64::kBranchPCRel32WeakImport:
5742 bool Reference<ppc>::isBranch() const
5745 case ppc::kBranch24:
5746 case ppc::kBranch24WeakImport:
5754 bool Reference<ppc64>::isBranch() const
5757 case ppc64::kBranch24:
5758 case ppc64::kBranch24WeakImport:
5766 bool Reference<arm>::isBranch() const
5769 case arm::kBranch24:
5770 case arm::kBranch24WeakImport:
5771 case arm::kThumbBranch22:
5772 case arm::kThumbBranch22WeakImport:
5781 }; // namespace relocatable
5782 }; // namespace mach_o
5784 #endif // __OBJECT_FILE_MACH_O__