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 ObjectFile::Reference* getFDE();
300 virtual Atom* getPersonalityPointer();
301 virtual void setCompactUnwindEncoding(uint64_t ehAtomAddress);
303 uint32_t fStabsStartIndex;
304 uint32_t fStabsCount;
306 ObjectFile::UnwindInfo fSingleUnwindInfo[1];
307 bool fHasCompactUnwindInfo;
311 ObjectFile::Reference* BaseAtom::getLSDA()
313 const uint8_t groupKind = this->getLSDAReferenceKind();
314 const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
315 for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
316 ObjectFile::Reference* ref = *it;
317 if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kLSDAType) ) {
324 ObjectFile::Reference* BaseAtom::getFDE()
326 const uint8_t groupKind = this->getLSDAReferenceKind();
327 const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
328 for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
329 ObjectFile::Reference* ref = *it;
330 if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kCFIType) ) {
337 ObjectFile::Atom* BaseAtom::getPersonalityPointer()
339 const uint8_t personalityKind = this->getPersonalityReferenceKind();
340 const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
341 for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
342 ObjectFile::Reference* ref = *it;
343 if ( ref->getKind() == personalityKind ) {
344 if ( strcmp(ref->getTarget().getSectionName(), "__nl_symbol_ptr") == 0 )
345 return &ref->getTarget();
346 if ( strcmp(ref->getTarget().getSectionName(), "__pointers") == 0 )
347 return &ref->getTarget();
354 void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress)
356 fSingleUnwindInfo[0].unwindInfo = this->getCompactUnwindEncoding(ehAtomAddress);
357 fHasCompactUnwindInfo = true;
364 bool operator()(const class BaseAtom* left, const class BaseAtom* right) {
367 uint64_t leftAddr = left->getObjectAddress();
368 uint64_t rightAddr = right->getObjectAddress();
369 if ( leftAddr < rightAddr ) {
372 else if ( leftAddr > rightAddr ) {
376 // if they have same address, one might be the end of a section and the other the start of the next section
377 const void* leftSection = left->getSectionRecord();
378 const void* rightSection = right->getSectionRecord();
379 if ( leftSection != rightSection ) {
380 return ( leftSection < rightSection );
382 // if they have same address and section, one might be an alias
383 bool leftAlias = left->isAlias();
384 bool rightAlias = right->isAlias();
385 if ( leftAlias && rightAlias ) {
386 // sort multiple aliases for same address first by scope
387 ObjectFile::Atom::Scope leftScope = left->getScope();
388 ObjectFile::Atom::Scope rightScope = right->getScope();
389 if ( leftScope != rightScope ) {
390 return ( leftScope < rightScope );
392 // sort multiple aliases for same address then by name
393 return ( strcmp(left->getName(), right->getName()) < 0 );
395 else if ( leftAlias ) {
398 else if ( rightAlias ) {
401 // one might be a section start or end label
402 switch ( left->getContentType() ) {
403 case ObjectFile::Atom::kSectionStart:
405 case ObjectFile::Atom::kSectionEnd:
410 switch ( right->getContentType() ) {
411 case ObjectFile::Atom::kSectionStart:
413 case ObjectFile::Atom::kSectionEnd:
418 // they could be tentative defintions
419 switch ( left->getDefinitionKind() ) {
420 case ObjectFile::Atom::kTentativeDefinition:
421 // sort tentative definitions by name
422 return ( strcmp(left->getName(), right->getName()) < 0 );
423 case ObjectFile::Atom::kAbsoluteSymbol:
424 // sort absolute symbols with same address by name
425 return ( strcmp(left->getName(), right->getName()) < 0 );
427 // hack for rdar://problem/5102873
428 if ( !left->isZeroFill() || !right->isZeroFill() )
429 warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath());
439 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
440 // pointing to it. A C function or global variable is represented by one of these atoms.
443 template <typename A>
444 class SymbolAtom : public BaseAtom
447 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
448 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
449 { return fOwner.getTranslationUnitSource(dir, name); }
450 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
451 virtual const char* getDisplayName() const { return getName(); }
452 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
453 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
454 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
455 virtual ObjectFile::Atom::ContentType getContentType() const { return fType; }
456 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
457 virtual bool dontDeadStrip() const;
458 virtual bool isZeroFill() const;
459 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
460 virtual uint64_t getSize() const { return fSize; }
461 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
462 virtual bool mustRemainInSection() const { return true; }
463 virtual const char* getSectionName() const;
464 virtual Segment<A>& getSegment() const { return *fSegment; }
465 virtual ObjectFile::Atom& getFollowOnAtom() const;
466 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
467 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
468 virtual void copyRawContent(uint8_t buffer[]) const;
469 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
470 virtual void setSize(uint64_t size);
471 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
472 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
473 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
474 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
475 virtual uint64_t getObjectAddress() const { return fAddress; }
476 virtual const void* getSectionRecord() const { return (const void*)fSection; }
477 virtual unsigned int getSectionIndex() const { return 1 + (fSection - fOwner.fSectionsStart); }
478 virtual uint8_t getLSDAReferenceKind() const;
479 virtual uint8_t getPersonalityReferenceKind() const;
480 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
483 typedef typename A::P P;
484 typedef typename A::P::E E;
485 typedef typename A::P::uint_t pint_t;
486 typedef typename A::ReferenceKinds Kinds;
487 typedef typename std::vector<Reference<A>*> ReferenceVector;
488 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
489 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
490 friend class Reader<A>;
492 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
493 virtual ~SymbolAtom() {}
496 const macho_nlist<P>* fSymbol;
499 const macho_section<P>* fSection;
500 Segment<A>* fSegment;
501 ReferenceVector fReferences;
502 std::vector<ObjectFile::LineInfo> fLineInfo;
503 ObjectFile::Atom::Scope fScope;
504 SymbolTableInclusion fSymbolTableInclusion;
505 ObjectFile::Atom::ContentType fType;
506 ObjectFile::Alignment fAlignment;
510 template <typename A>
511 SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
512 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fType(ObjectFile::Atom::kUnclassifiedType), fAlignment(0)
514 fSingleUnwindInfo[0].startOffset = 0;
515 fSingleUnwindInfo[0].unwindInfo = 0;
516 uint8_t type = symbol->n_type();
517 if ( (type & N_EXT) == 0 )
518 fScope = ObjectFile::Atom::scopeTranslationUnit;
519 else if ( (type & N_PEXT) != 0 )
520 fScope = ObjectFile::Atom::scopeLinkageUnit;
522 fScope = ObjectFile::Atom::scopeGlobal;
523 if ( (type & N_TYPE) == N_SECT ) {
525 fSegment = new Segment<A>(fSection);
526 fAddress = fSymbol->n_value();
527 pint_t sectionStartAddr = section->addr();
528 pint_t sectionEndAddr = section->addr()+section->size();
529 if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) {
530 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",
531 this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(),
532 (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) );
536 warning("unknown symbol type: %d", type);
539 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
540 // support for .o files built with old ld64
541 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
542 const char* name = this->getName();
543 const int nameLen = strlen(name);
544 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
545 // switch symbol to point at name that does not have trailing $stub
546 char correctName[nameLen];
547 strncpy(correctName, name, nameLen-5);
548 correctName[nameLen-5] = '\0';
549 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
550 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
551 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
552 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
559 // support for labeled stubs
560 switch ( section->flags() & SECTION_TYPE ) {
562 setSize(section->reserved2());
564 case S_LAZY_SYMBOL_POINTERS:
565 case S_NON_LAZY_SYMBOL_POINTERS:
566 setSize(sizeof(pint_t));
568 case S_4BYTE_LITERALS:
571 case S_8BYTE_LITERALS:
574 case S_16BYTE_LITERALS:
577 case S_CSTRING_LITERALS:
578 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
579 fType = ObjectFile::Atom::kCStringType;
584 // size calculate later after next atom is found
589 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
591 // compute whether this atom needs to be in symbol table
592 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
593 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
595 else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) {
596 // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
597 // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
598 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
601 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
604 // work around malformed icc generated .o files <rdar://problem/5349847>
605 // if section starts with a symbol and that symbol address does not match section alignment, then force it to
606 if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) )
607 fAlignment.modulus = 0;
611 template <typename A>
612 bool SymbolAtom<A>::dontDeadStrip() const
614 // the symbol can have a no-dead-strip bit
615 if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 )
617 // or the section can have a no-dead-strip bit
618 return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP );
622 template <typename A>
623 const char* SymbolAtom<A>::getSectionName() const
625 if ( fOwner.fOptions.fForFinalLinkedImage ) {
626 if ( strcmp(fSection->sectname(), "__textcoal_nt") == 0 )
628 else if ( strcmp(fSection->sectname(), "__const_coal") == 0 )
630 else if ( strcmp(fSection->sectname(), "__datacoal_nt") == 0 )
632 else if ( fOwner.fOptions.fAutoOrderInitializers && (strcmp(fSection->sectname(), "__StaticInit") == 0) )
635 switch ( fSection->flags() & SECTION_TYPE ) {
636 case S_4BYTE_LITERALS:
637 case S_8BYTE_LITERALS:
638 case S_16BYTE_LITERALS:
644 if ( strlen(fSection->sectname()) > 15 ) {
645 static char temp[18];
646 strncpy(temp, fSection->sectname(), 16);
650 return fSection->sectname();
653 template <typename A>
654 ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
656 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
657 Reference<A>* ref = *it;
658 if ( ref->getKind() == A::kFollowOn )
659 return ref->getTarget();
661 return *((ObjectFile::Atom*)NULL);
664 template <typename A>
665 bool SymbolAtom<A>::isZeroFill() const
667 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
674 Beyond(uint64_t offset) : fOffset(offset) {}
675 bool operator()(ObjectFile::Reference* ref) const {
676 return ( ref->getFixUpOffset() >= fOffset );
683 template <typename A>
684 void SymbolAtom<A>::setSize(uint64_t size)
686 // when resizing, any references beyond the new size are tossed
687 if ( (fSize != 0) && (fReferences.size() > 0) )
688 fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end());
693 template <typename A>
694 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
698 bzero(buffer, fSize);
700 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
701 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
709 // A SymbolAliasAtom represents an alternate name for a SymbolAtom
712 template <typename A>
713 class SymbolAliasAtom : public BaseAtom
716 virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); }
717 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
718 { return fAliasOf.getTranslationUnitSource(dir, name); }
719 virtual const char* getName() const { return fName; }
720 virtual const char* getDisplayName() const { return fName; }
721 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
722 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); }
723 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); }
724 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
725 virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); }
726 virtual bool isThumb() const { return fAliasOf.isThumb(); }
727 virtual uint64_t getSize() const { return 0; }
728 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
729 virtual bool mustRemainInSection() const { return true; }
730 virtual const char* getSectionName() const { return fAliasOf.getSectionName(); }
731 virtual Segment<A>& getSegment() const { return (Segment<A>&)fAliasOf.getSegment(); }
732 virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; }
733 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
734 virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); }
735 virtual void copyRawContent(uint8_t buffer[]) const {}
736 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
737 virtual void setSize(uint64_t size) { }
738 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
739 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
740 virtual void addLineInfo(const ObjectFile::LineInfo& info) { }
741 virtual const ObjectFile::ReaderOptions& getOptions() const { return fAliasOf.getOptions(); }
742 virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); }
743 virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); }
744 virtual unsigned int getSectionIndex() const { return fAliasOf.getSectionIndex(); }
745 virtual bool isAlias() const { return true; }
748 typedef typename A::P P;
749 typedef typename std::vector<Reference<A>*> ReferenceVector;
750 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
751 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
752 friend class Reader<A>;
754 SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
755 virtual ~SymbolAliasAtom() {}
758 const BaseAtom& fAliasOf;
759 ObjectFile::Atom::Scope fScope;
761 ReferenceVector fReferences;
765 template <typename A>
766 SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
767 : fName(name), fAliasOf(aliasOf)
769 //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
770 if ( symbol != NULL ) {
771 uint8_t type = symbol->n_type();
772 if ( (type & N_EXT) == 0 )
773 fScope = ObjectFile::Atom::scopeTranslationUnit;
774 else if ( (type & N_PEXT) != 0 )
775 fScope = ObjectFile::Atom::scopeLinkageUnit;
777 fScope = ObjectFile::Atom::scopeGlobal;
778 fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
781 // aliases defined on the command line are initially global scope
782 fScope = ObjectFile::Atom::scopeGlobal;
783 fDontDeadStrip = false;
785 // add follow-on reference to real atom
786 new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
791 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
792 // For instance, "int foo;" is neither a declaration or a definition and
793 // is represented by a TentativeAtom.
795 template <typename A>
796 class TentativeAtom : public BaseAtom
799 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
800 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
801 { return fOwner.getTranslationUnitSource(dir, name); }
802 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
803 virtual const char* getDisplayName() const { return getName(); }
804 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
805 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
806 virtual bool isZeroFill() const { return fOwner.fOptions.fOptimizeZeroFill; }
807 virtual bool isThumb() const { return false; }
808 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
809 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
810 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
811 virtual uint64_t getSize() const { return fSymbol->n_value(); }
812 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
813 virtual bool mustRemainInSection() const { return true; }
814 virtual const char* getSectionName() const;
815 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
816 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
817 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
818 virtual ObjectFile::Alignment getAlignment() const;
819 virtual void copyRawContent(uint8_t buffer[]) const;
820 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
821 virtual void setSize(uint64_t size) { }
822 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
823 virtual void sortReferences() { }
824 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
825 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
826 virtual uint64_t getObjectAddress() const { return ULLONG_MAX; }
827 virtual const void* getSectionRecord() const { return NULL; }
828 virtual unsigned int getSectionIndex() const { return 0; }
831 typedef typename A::P P;
832 typedef typename A::P::E E;
833 typedef typename A::P::uint_t pint_t;
834 typedef typename A::ReferenceKinds Kinds;
835 friend class Reader<A>;
837 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
838 virtual ~TentativeAtom() {}
841 const macho_nlist<P>* fSymbol;
842 ObjectFile::Atom::Scope fScope;
843 static std::vector<ObjectFile::Reference*> fgNoReferences;
846 template <typename A>
847 std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
849 template <typename A>
850 TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
851 : fOwner(owner), fSymbol(symbol)
853 uint8_t type = symbol->n_type();
854 if ( (type & N_EXT) == 0 )
855 fScope = ObjectFile::Atom::scopeTranslationUnit;
856 else if ( (type & N_PEXT) != 0 )
857 fScope = ObjectFile::Atom::scopeLinkageUnit;
859 fScope = ObjectFile::Atom::scopeGlobal;
860 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
861 // tentative definition
864 warning("unknown symbol type: %d", type);
866 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
870 template <typename A>
871 ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
873 uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc());
874 if ( alignment == 0 ) {
875 // common symbols align to their size
876 // that is, a 4-byte common aligns to 4-bytes
877 // if this size is not a power of two,
878 // then round up to the next power of two
879 uint64_t size = this->getSize();
880 alignment = 63 - (uint8_t)__builtin_clzll(size);
881 if ( size != (1ULL << alignment) )
884 // limit alignment of extremely large commons to 2^15 bytes (8-page)
885 if ( alignment < 12 )
886 return ObjectFile::Alignment(alignment);
888 return ObjectFile::Alignment(12);
891 template <typename A>
892 const char* TentativeAtom<A>::getSectionName() const
894 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
901 template <typename A>
902 void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
904 bzero(buffer, getSize());
909 // An AnonymousAtom represents compiler generated data that has no name.
910 // For instance, a literal C-string or a 64-bit floating point constant
911 // is represented by an AnonymousAtom.
913 template <typename A>
914 class AnonymousAtom : public BaseAtom
917 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
918 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
919 virtual const char* getName() const { return fSynthesizedName; }
920 virtual const char* getDisplayName() const;
921 virtual ObjectFile::Atom::Scope getScope() const;
922 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; }
923 virtual ObjectFile::Atom::ContentType getContentType() const { return fType; }
924 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
925 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
926 virtual bool isZeroFill() const;
927 virtual bool isThumb() const { return false; }
928 virtual uint64_t getSize() const { return fSize; }
929 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
930 virtual bool mustRemainInSection() const { return true; }
931 virtual const char* getSectionName() const;
932 virtual Segment<A>& getSegment() const { return *fSegment; }
933 virtual ObjectFile::Atom& getFollowOnAtom() const;
934 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
935 virtual ObjectFile::Alignment getAlignment() const;
936 virtual void copyRawContent(uint8_t buffer[]) const;
937 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
938 virtual void setSize(uint64_t size) { fSize = size; }
939 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
940 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
941 virtual void addLineInfo(const ObjectFile::LineInfo& info);
942 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
943 virtual uint64_t getObjectAddress() const { return fAddress; }
944 virtual const void* getSectionRecord() const { return (const void*)fSection; }
945 virtual unsigned int getSectionIndex() const { return fSectionIndex; }
946 BaseAtom* redirectTo() { return fRedirect; }
947 bool isWeakImportStub() { return fWeakImportStub; }
949 virtual uint8_t getLSDAReferenceKind() const;
950 virtual uint8_t getPersonalityReferenceKind() const;
951 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
954 typedef typename A::P P;
955 typedef typename A::P::E E;
956 typedef typename A::P::uint_t pint_t;
957 typedef typename A::ReferenceKinds Kinds;
958 typedef typename std::vector<Reference<A>*> ReferenceVector;
959 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
960 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
961 friend class Reader<A>;
963 AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
964 virtual ~AnonymousAtom() {}
965 static bool cstringsHaveLabels();
968 const char* fSynthesizedName;
969 const char* fDisplayName;
970 const macho_section<P>* fSection;
973 Segment<A>* fSegment;
974 ReferenceVector fReferences;
977 bool fWeakImportStub;
978 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
979 ObjectFile::Atom::Scope fScope;
980 ObjectFile::Atom::DefinitionKind fKind;
981 ObjectFile::Atom::ContentType fType;
982 unsigned int fSectionIndex;
985 template <typename A>
986 AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
987 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
988 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
989 fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition),
990 fType(ObjectFile::Atom::kUnclassifiedType), fSectionIndex(1 + (section - owner.fSectionsStart))
992 fSegment = new Segment<A>(fSection);
994 uint8_t type = fSection->flags() & SECTION_TYPE;
995 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
999 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
1004 if ( section == owner.fehFrameSection ) {
1008 fDontDeadStrip = false;
1009 if ( fOwner.fOptions.fForFinalLinkedImage )
1010 fSynthesizedName = "CIE";
1012 fSynthesizedName = "EH_frame1";
1016 fSynthesizedName = ".eh_PENDING";
1017 fDontDeadStrip = false;
1018 owner.fAtomsPendingAName.push_back(this);
1020 fType = ObjectFile::Atom::kCFIType;
1021 // FDEs and CIEs don't need to be in symbol table of final linked images <rdar://problem/4180168>
1022 if ( !fOwner.fOptions.fNoEHLabels )
1023 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1025 else if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
1026 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
1027 fSynthesizedName = ".objc_class_name_PENDING";
1028 owner.fAtomsPendingAName.push_back(this);
1029 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1030 if ( fOwner.fOptions.fForFinalLinkedImage )
1031 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1033 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
1034 fScope = ObjectFile::Atom::scopeGlobal;
1036 else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
1037 // handle .o files created by old ld64 -r that are missing cstring section type
1038 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
1039 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
1041 else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) {
1042 fSynthesizedName = "cfstring-pointer-name-PENDING";
1043 fScope = ObjectFile::Atom::scopeLinkageUnit;
1044 owner.fAtomsPendingAName.push_back(this);
1045 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1046 fDontDeadStrip = false;
1047 fKind = ObjectFile::Atom::kWeakDefinition;
1049 else if ( (fSection->flags() & S_ATTR_SOME_INSTRUCTIONS) != 0 ) {
1050 fDontDeadStrip = false;
1051 asprintf((char**)&fSynthesizedName, "anon-func-0x%X", addr);
1053 else if ( strncmp(fSection->sectname(), "__gcc_except_tab",16) == 0 ) {
1054 fType = ObjectFile::Atom::kLSDAType;
1055 fDontDeadStrip = false;
1056 fSynthesizedName = ".lsda_PENDING";
1057 owner.fAtomsPendingAName.push_back(this);
1058 if ( !fOwner.fOptions.fNoEHLabels )
1059 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1061 else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1062 fSynthesizedName = "objc-class-pointer-name-PENDING";
1063 fScope = ObjectFile::Atom::scopeLinkageUnit;
1064 owner.fAtomsPendingAName.push_back(this);
1065 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1066 fKind = ObjectFile::Atom::kWeakDefinition;
1068 else if ( section == owner.fUTF16Section ) {
1069 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1070 fDontDeadStrip = false;
1071 fScope = ObjectFile::Atom::scopeLinkageUnit;
1072 fKind = ObjectFile::Atom::kWeakDefinition;
1073 char* name = new char[16+5*size];
1074 strcpy(name, "utf16-string=");
1075 char* s = &name[13];
1076 const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr());
1077 unsigned int wordCount = size/2;
1078 bool needSeperator = false;
1079 for(unsigned int i=0; i < wordCount; ++i) {
1080 if ( needSeperator )
1082 sprintf(s, "%04X", E::get32(words[i]));
1084 needSeperator = true;
1086 fSynthesizedName = name;
1089 asprintf((char**)&fSynthesizedName, "lutf16-0x%X", addr);
1093 case S_CSTRING_LITERALS:
1095 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
1096 if ( (strcmp(fSection->sectname(), "__cstring") == 0) && (strcmp(section->segname(), "__TEXT") == 0) )
1097 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
1099 asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str);
1100 fScope = ObjectFile::Atom::scopeLinkageUnit;
1101 fKind = ObjectFile::Atom::kWeakDefinition;
1102 fType = ObjectFile::Atom::kCStringType;
1103 fDontDeadStrip = false;
1104 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
1105 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1108 case S_4BYTE_LITERALS:
1110 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1111 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
1112 fScope = ObjectFile::Atom::scopeLinkageUnit;
1113 fKind = ObjectFile::Atom::kWeakDefinition;
1114 fDontDeadStrip = false;
1117 case S_8BYTE_LITERALS:
1119 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1120 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
1121 fScope = ObjectFile::Atom::scopeLinkageUnit;
1122 fKind = ObjectFile::Atom::kWeakDefinition;
1123 fDontDeadStrip = false;
1126 case S_16BYTE_LITERALS:
1128 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1129 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
1130 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
1131 fScope = ObjectFile::Atom::scopeLinkageUnit;
1132 fKind = ObjectFile::Atom::kWeakDefinition;
1133 fDontDeadStrip = false;
1136 case S_LITERAL_POINTERS:
1138 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1139 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
1140 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
1141 fSynthesizedName = "literal-pointer-name-PENDING";
1142 fScope = ObjectFile::Atom::scopeLinkageUnit;
1143 fKind = ObjectFile::Atom::kWeakDefinition;
1144 fDontDeadStrip = false;
1145 owner.fAtomsPendingAName.push_back(this);
1146 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1149 case S_MOD_INIT_FUNC_POINTERS:
1150 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1152 case S_MOD_TERM_FUNC_POINTERS:
1153 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1155 case S_SYMBOL_STUBS:
1157 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
1158 index += fSection->reserved1();
1159 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1160 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
1161 uint32_t strOffset = sym->n_strx();
1162 // want name to not have $stub suffix, this is what automatic stub generation expects
1163 fSynthesizedName = &fOwner.fStrings[strOffset];
1164 // check for weak import
1165 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
1166 // sometimes the compiler gets confused and generates a stub to a static function
1167 // if so, we should redirect any call to the stub to be calls to the real static function atom
1168 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
1169 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
1170 if ( staticAtom != NULL )
1171 fRedirect = staticAtom;
1173 fKind = ObjectFile::Atom::kWeakDefinition;
1174 // might be a spurious stub for a static function, make stub static too
1175 if ( (sym->n_type() & N_EXT) == 0 )
1176 fScope = ObjectFile::Atom::scopeTranslationUnit;
1178 fScope = ObjectFile::Atom::scopeLinkageUnit;
1181 case S_LAZY_SYMBOL_POINTERS:
1182 case S_NON_LAZY_SYMBOL_POINTERS:
1184 // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when
1185 // generating the new compressed LINKEDIT format
1186 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) && fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
1187 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1188 dummySection->set_segname("__DATA");
1189 dummySection->set_sectname("__nl_symbol_ptr");
1190 fSection = dummySection;
1191 fSegment = new Segment<A>(fSection);
1194 fDontDeadStrip = false;
1195 fScope = ObjectFile::Atom::scopeLinkageUnit;
1196 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
1197 index += fSection->reserved1();
1198 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1199 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1200 // Silly codegen with non-lazy pointer to a local symbol
1201 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1202 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
1203 // All atoms not created yet, so we need to scan symbol table
1204 const macho_nlist<P>* closestSym = NULL;
1205 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1206 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
1207 if ( ((sym->n_type() & N_TYPE) == N_SECT)
1208 && ((sym->n_type() & N_STAB) == 0) ) {
1209 if ( sym->n_value() == nonLazyPtrValue ) {
1210 const char* name = &fOwner.fStrings[sym->n_strx()];
1211 char* str = new char[strlen(name)+16];
1213 strcat(str, "$non_lazy_ptr");
1214 fSynthesizedName = str;
1215 // add direct reference to target later, because its atom may not be constructed yet
1216 fOwner.fLocalNonLazys.push_back(this);
1217 fScope = ObjectFile::Atom::scopeTranslationUnit;
1218 fType = ObjectFile::Atom::kNonLazyPointer;
1221 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1226 // add direct reference to target later, because its atom may not be constructed yet
1227 if ( closestSym != NULL ) {
1228 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1230 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1231 fSynthesizedName = str;
1234 fSynthesizedName = "$interior$non_lazy_ptr";
1236 fScope = ObjectFile::Atom::scopeTranslationUnit;
1237 fOwner.fLocalNonLazys.push_back(this);
1238 fType = ObjectFile::Atom::kNonLazyPointer;
1241 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1242 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1243 char* str = new char[strlen(name)+16];
1245 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1246 strcat(str, "$lazy_ptr");
1247 fType = ObjectFile::Atom::kLazyPointer;
1250 strcat(str, "$non_lazy_ptr");
1251 fType = ObjectFile::Atom::kNonLazyPointer;
1253 fSynthesizedName = str;
1255 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1256 fKind = ObjectFile::Atom::kWeakDefinition;
1258 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1259 // target is translation unit scoped, so add direct reference to target
1260 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1261 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1264 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1265 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1267 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1272 throwf("section type %d not supported with address=0x%08llX", type, (uint64_t)addr);
1274 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1277 // x86_64 uses L labels on cstrings to allow relocs with addends
1278 template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1279 template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1281 template <typename A>
1282 void AnonymousAtom<A>::addLineInfo(const ObjectFile::LineInfo& info)
1284 // <rdar://problem/6545406> don't warn if line table has entries for stubs
1285 if ( (fSection->flags() & SECTION_TYPE) != S_SYMBOL_STUBS )
1286 warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath());
1289 template <typename A>
1290 void AnonymousAtom<A>::resolveName()
1292 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1293 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1294 // references are not yet sorted, so scan the vector
1295 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1296 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1297 const char* superStr = (*rit)->getTargetName();
1298 if ( strncmp(superStr, "cstring", 7) == 0 ) {
1299 const char* superClassName;
1300 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1301 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1306 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1307 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1308 const char* classStr = (*rit)->getTargetName();
1309 if ( strncmp(classStr, "cstring", 7) == 0 ) {
1310 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1316 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
1317 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1318 if ( references.size() < 1 )
1319 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1320 ObjectFile::Reference* ref = references[0];
1321 const char* str = ref->getTargetName();
1322 if ( strncmp(str, "cstring", 7) == 0 ) {
1323 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1326 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1327 // references are not yet sorted, so scan the vector
1328 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1329 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1330 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1331 const char* superStr = (*rit)->getTargetName();
1332 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1333 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1335 else if ( (superStr != NULL) && (strncmp(superStr, "utf16-string=", 13) == 0) ) {
1336 asprintf((char**)&fSynthesizedName, "cfstring-utf16=%s", &superStr[13]);
1339 // compiled with -fwritable-strings or a non-ASCII string
1340 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1341 fScope = ObjectFile::Atom::scopeTranslationUnit;
1342 fSynthesizedName = "cfstring-not-coalesable";
1343 if ( (*rit)->getTargetOffset() != 0 )
1344 warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner.getPath());
1350 else if ( fSection == fOwner.fehFrameSection ) {
1352 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromFDEAddress(fAddress);
1353 if ( funcAtom != NULL )
1354 asprintf((char**)&fSynthesizedName, "%s.eh", funcAtom->getDisplayName());
1356 else if ( fOwner.fLSDAAtoms.count(this) != 0) {
1357 // give name to LSDA
1358 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromLSDAAddress(fAddress);
1359 if ( funcAtom != NULL )
1360 asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
1362 else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1363 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1364 if ( references.size() != 1 )
1365 throwf("__objc_classrefs element missing reloc (count=%ld) for target class in %s", references.size(), fOwner.getPath());
1366 const char* targetName = references[0]->getTargetName();
1367 if ( strncmp(targetName, "_OBJC_CLASS_$_", 14) == 0 )
1368 asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", &targetName[14]);
1370 asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", targetName);
1375 template <typename A>
1376 const char* AnonymousAtom<A>::getDisplayName() const
1378 if ( fSynthesizedName != NULL )
1379 return fSynthesizedName;
1381 if ( fDisplayName != NULL )
1382 return fDisplayName;
1384 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1385 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1386 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
1389 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
1391 return fDisplayName;
1395 template <typename A>
1396 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1402 template <typename A>
1403 bool AnonymousAtom<A>::isZeroFill() const
1405 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
1409 template <typename A>
1410 const char* AnonymousAtom<A>::getSectionName() const
1412 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1413 switch ( fSection->flags() & SECTION_TYPE ) {
1414 case S_4BYTE_LITERALS:
1415 case S_8BYTE_LITERALS:
1416 case S_16BYTE_LITERALS:
1421 if ( strlen(fSection->sectname()) > 15 ) {
1422 static char temp[18];
1423 strncpy(temp, fSection->sectname(), 16);
1427 return fSection->sectname();
1430 template <typename A>
1431 ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
1433 // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
1434 if ( fType == ObjectFile::Atom::kCFIType )
1435 return ObjectFile::Alignment(0);
1437 switch ( fSection->flags() & SECTION_TYPE ) {
1438 case S_4BYTE_LITERALS:
1439 return ObjectFile::Alignment(2);
1440 case S_8BYTE_LITERALS:
1441 return ObjectFile::Alignment(3);
1442 case S_16BYTE_LITERALS:
1443 return ObjectFile::Alignment(4);
1444 case S_NON_LAZY_SYMBOL_POINTERS:
1445 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
1446 case S_CSTRING_LITERALS:
1447 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1448 return ObjectFile::Alignment(fSection->align());
1450 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
1455 template <typename A>
1456 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1458 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1459 Reference<A>* ref = *it;
1460 if ( ref->getKind() == A::kFollowOn )
1461 return ref->getTarget();
1463 return *((ObjectFile::Atom*)NULL);
1466 template <typename A>
1467 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1471 bzero(buffer, fSize);
1473 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1474 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1479 // An AbsoluteAtom represents an N_ABS symbol which can only be created in
1480 // assembly language and usable by static executables such as the kernel/
1482 template <typename A>
1483 class AbsoluteAtom : public BaseAtom
1486 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1487 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1488 { return fOwner.getTranslationUnitSource(dir, name); }
1489 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1490 virtual const char* getDisplayName() const { return getName(); }
1491 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1492 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1493 virtual bool isZeroFill() const { return false; }
1494 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
1495 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1496 virtual bool dontDeadStrip() const { return false; }
1497 virtual uint64_t getSize() const { return 0; }
1498 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1499 virtual bool mustRemainInSection() const { return true; }
1500 virtual const char* getSectionName() const { return "._absolute"; }
1501 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1502 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1503 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1504 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1505 virtual void copyRawContent(uint8_t buffer[]) const { }
1506 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1507 virtual void setSize(uint64_t size) { }
1508 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1509 virtual void sortReferences() { }
1510 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1511 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1512 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1513 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1514 virtual const void* getSectionRecord() const { return NULL; }
1515 virtual unsigned int getSectionIndex() const { return 0; }
1518 typedef typename A::P P;
1519 typedef typename A::P::E E;
1520 typedef typename A::P::uint_t pint_t;
1521 typedef typename A::ReferenceKinds Kinds;
1522 friend class Reader<A>;
1524 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1525 virtual ~AbsoluteAtom() {}
1528 const macho_nlist<P>* fSymbol;
1529 ObjectFile::Atom::Scope fScope;
1530 static std::vector<ObjectFile::Reference*> fgNoReferences;
1533 template <typename A>
1534 std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1536 template <typename A>
1537 AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1538 : fOwner(owner), fSymbol(symbol)
1540 // store absolute adress in fSectionOffset
1541 fSectionOffset = symbol->n_value();
1543 uint8_t type = symbol->n_type();
1544 if ( (type & N_EXT) == 0 )
1545 fScope = ObjectFile::Atom::scopeTranslationUnit;
1546 else if ( (type & N_PEXT) != 0 )
1547 fScope = ObjectFile::Atom::scopeLinkageUnit;
1549 fScope = ObjectFile::Atom::scopeGlobal;
1550 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1555 // An SectionBoundaryAtom represent the start or end of a section
1557 template <typename A>
1558 class SectionBoundaryAtom : public BaseAtom
1561 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1562 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1563 { return fOwner.getTranslationUnitSource(dir, name); }
1564 virtual const char* getName() const { return fSymbolName; }
1565 virtual const char* getDisplayName() const { return fDisplayName; }
1566 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1567 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition; }
1568 virtual ObjectFile::Atom::ContentType getContentType() const { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
1569 virtual bool isZeroFill() const { return fZeroFill; }
1570 virtual bool isThumb() const { return false; }
1571 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
1572 virtual bool dontDeadStrip() const { return false; }
1573 virtual uint64_t getSize() const { return 0; }
1574 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1575 virtual bool mustRemainInSection() const { return true; }
1576 virtual const char* getSectionName() const { return fSectionName; }
1577 virtual ObjectFile::Segment& getSegment() const { return *fSegment; }
1578 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1579 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1580 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1581 virtual void copyRawContent(uint8_t buffer[]) const { }
1582 virtual void setScope(ObjectFile::Atom::Scope newScope) { }
1583 virtual void setSize(uint64_t size) { }
1584 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1585 virtual void sortReferences() { }
1586 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1587 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1588 virtual uint64_t getObjectAddress() const { return 0; }
1589 virtual const void* getSectionRecord() const { return NULL; }
1590 virtual unsigned int getSectionIndex() const { return 0; }
1593 typedef typename A::P P;
1594 typedef typename A::P::E E;
1595 typedef typename A::P::uint_t pint_t;
1596 typedef typename A::ReferenceKinds Kinds;
1597 friend class Reader<A>;
1600 class Segment : public ObjectFile::Segment
1603 Segment(const char* name, bool r, bool w, bool x):
1604 fName(name), fReadable(r), fWritable(w), fExecutable(x) {}
1606 virtual const char* getName() const { return fName; }
1607 virtual bool isContentReadable() const { return fReadable; }
1608 virtual bool isContentWritable() const { return fWritable; }
1609 virtual bool isContentExecutable() const { return fExecutable; }
1617 SectionBoundaryAtom(Reader<A>&, bool start, const char* symbolName, const char* segSectName);
1618 virtual ~SectionBoundaryAtom() {}
1621 class Segment* fSegment;
1622 const char* fSymbolName;
1623 const char* fSectionName;
1624 const char* fDisplayName;
1627 static std::vector<ObjectFile::Reference*> fgNoReferences;
1630 template <typename A>
1631 std::vector<ObjectFile::Reference*> SectionBoundaryAtom<A>::fgNoReferences;
1634 // section$start$__DATA$__my
1635 // section$end$__DATA$__my
1636 template <typename A>
1637 SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
1638 : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start), fZeroFill(false)
1640 const char* segSectDividor = strrchr(segSectName, '$');
1641 if ( segSectDividor == NULL )
1642 throwf("malformed section reference name: %s", symbolName);
1643 fSectionName = segSectDividor + 1;
1644 int segNameLen = segSectDividor - segSectName;
1645 if ( segNameLen > 16 )
1646 throwf("malformed section reference name: %s", symbolName);
1648 strlcpy(segName, segSectName, segNameLen+1);
1649 if ( strcmp(segName, "__TEXT") == 0 )
1650 fSegment = new Segment("__TEXT", true, false, true);
1651 else if ( strcmp(segName, "__DATA") == 0 ) {
1652 fSegment = new Segment("__DATA", true, true, false);
1653 if ( (strcmp(fSectionName, "__bss") == 0) || (strcmp(fSectionName, "__common") == 0) )
1657 fSegment = new Segment(strdup(segName), true, true, false);
1659 asprintf((char**)&fDisplayName, "%s of section '%s' in segment '%s'", (start ? "start" : "end"), fSectionName, segName);
1665 /// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
1666 /// dwarf CFI information in an object file.
1668 template <typename A>
1669 class ObjectFileAddressSpace
1672 ObjectFileAddressSpace(Reader<A>& reader);
1674 typedef typename A::P::uint_t pint_t;
1675 typedef typename A::P P;
1676 typedef typename A::P::uint_t sint_t;
1678 uint8_t get8(pint_t addr);
1679 uint16_t get16(pint_t addr);
1680 uint32_t get32(pint_t addr);
1681 uint64_t get64(pint_t addr);
1682 pint_t getP(pint_t addr);
1683 uint64_t getULEB128(pint_t& addr, pint_t end);
1684 int64_t getSLEB128(pint_t& addr, pint_t end);
1685 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
1687 const void* mappedAddress(pint_t addr, pint_t* relocTarget=NULL);
1688 pint_t relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount);
1689 void buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map);
1692 const uint8_t* fMappingStart;
1693 const macho_section<P>* fSectionsStart;
1694 const macho_section<P>* fSectionsEnd;
1695 std::map<uint32_t,uint64_t> fEHFrameOffsetToTargetMap;
1699 template <typename A>
1700 ObjectFileAddressSpace<A>::ObjectFileAddressSpace(Reader<A>& reader)
1701 : fReader(reader), fMappingStart(NULL), fSectionsStart(NULL), fSectionsEnd(NULL)
1707 template <typename A>
1708 const void* ObjectFileAddressSpace<A>::mappedAddress(pint_t addr, pint_t* relocTarget)
1710 if ( fMappingStart == NULL ) {
1711 // delay initialization until now when fReader.fSegment is set up
1712 fMappingStart = (uint8_t*)fReader.fHeader;
1713 fSectionsStart = (macho_section<P>*)((char*)fReader.fSegment + sizeof(macho_segment_command<P>));
1714 fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()];
1715 // find __eh_frame section and build map of relocations for performance
1716 buildRelocatedMap(fReader.fehFrameSection, fEHFrameOffsetToTargetMap);
1718 // special case lookups in __eh_frame section to be fast
1719 const macho_section<P>* ehSect = fReader.fehFrameSection;
1720 if ( (ehSect->addr() <= addr) && (addr < (ehSect->addr()+ehSect->size())) ) {
1721 pint_t offsetOfAddrInSection = addr - ehSect->addr();
1722 if ( relocTarget != NULL ) {
1723 std::map<uint32_t,uint64_t>::iterator pos = fEHFrameOffsetToTargetMap.find(offsetOfAddrInSection);
1724 if ( pos != fEHFrameOffsetToTargetMap.end() )
1725 *relocTarget = pos->second;
1729 return fMappingStart + ehSect->offset() + offsetOfAddrInSection;
1732 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
1733 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
1734 pint_t offsetOfAddrInSection = addr - sect->addr();
1735 if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
1736 const uint32_t indirectTableOffset = sect->reserved1();
1737 const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t);
1738 const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]);
1739 // return pointer to symbol name which this non-lazy-pointer will point to
1740 if ( relocTarget != NULL )
1741 *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()];
1744 if ( relocTarget != NULL )
1745 *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc());
1747 return fMappingStart + sect->offset() + offsetOfAddrInSection;
1750 throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr);
1757 template <typename A>
1758 uint8_t ObjectFileAddressSpace<A>::get8(pint_t logicalAddr)
1760 return *((uint8_t*)mappedAddress(logicalAddr));
1763 template <typename A>
1764 uint16_t ObjectFileAddressSpace<A>::get16(pint_t logicalAddr)
1766 return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr)));
1769 template <typename A>
1770 uint32_t ObjectFileAddressSpace<A>::get32(pint_t logicalAddr)
1773 return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1776 template <typename A>
1777 uint64_t ObjectFileAddressSpace<A>::get64(pint_t logicalAddr)
1780 return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1783 template <typename A>
1784 typename A::P::uint_t ObjectFileAddressSpace<A>::getP(pint_t logicalAddr)
1787 return P::getP(*((pint_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1790 template <typename A>
1791 uint64_t ObjectFileAddressSpace<A>::getULEB128(pint_t& logicalAddr, pint_t end)
1793 uintptr_t size = (end - logicalAddr);
1794 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1795 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1796 uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
1797 logicalAddr += (laddr-sladdr);
1801 template <typename A>
1802 int64_t ObjectFileAddressSpace<A>::getSLEB128(pint_t& logicalAddr, pint_t end)
1804 uintptr_t size = (end - logicalAddr);
1805 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1806 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1807 int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
1808 logicalAddr += (laddr-sladdr);
1817 template <typename A>
1818 class Reader : public ObjectFile::Reader
1821 static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
1822 static const char* fileKind(const uint8_t* fileContent);
1823 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1824 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
1825 virtual ~Reader() {}
1827 virtual const char* getPath() { return fPath; }
1828 virtual time_t getModificationTime() { return fModTime; }
1829 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1830 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1831 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1832 virtual std::vector<Stab>* getStabs() { return &fStabs; }
1833 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
1834 virtual uint32_t updateCpuConstraint(uint32_t current);
1835 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1836 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
1837 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
1839 bool getTranslationUnitSource(const char** dir, const char** name) const;
1842 typedef typename A::P P;
1843 typedef typename A::P::E E;
1844 typedef typename A::P::uint_t pint_t;
1845 //typedef typename std::vector<Atom<A>*> AtomVector;
1846 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1847 typedef typename A::ReferenceKinds Kinds;
1848 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::FDE_Atom_Info FDE_Atom_Info;
1849 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::CIE_Atom_Info CIE_Atom_Info;
1850 typedef class ObjectFileAddressSpace<A> OAS;
1851 friend class ObjectFileAddressSpace<A>;
1852 friend class AnonymousAtom<A>;
1853 friend class TentativeAtom<A>;
1854 friend class AbsoluteAtom<A>;
1855 friend class SectionBoundaryAtom<A>;
1856 friend class SymbolAtom<A>;
1857 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
1859 void addReferencesForSection(const macho_section<P>* sect);
1860 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1861 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1862 const char* getDwarfString(uint64_t form, const uint8_t* p);
1863 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1864 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1865 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1866 static const char* assureFullPath(const char* path);
1867 AtomAndOffset findAtomAndOffset(pint_t addr);
1868 AtomAndOffset findAtomAndOffsetForSection(pint_t addr, unsigned int sectionIndex);
1869 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1870 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1871 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1872 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1873 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1874 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
1875 BaseAtom* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
1876 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
1877 void validSectionType(uint8_t type);
1878 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1879 void setCpuConstraint(uint32_t cpusubtype);
1880 const macho_section<P>* getSectionForAddress(pint_t);
1881 ObjectFile::Atom* getFunctionAtomFromFDEAddress(pint_t);
1882 ObjectFile::Atom* getFunctionAtomFromLSDAAddress(pint_t);
1883 void addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target);
1884 void addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding);
1885 bool isSectDiffReloc(uint8_t r_type);
1888 BaseAtom* findAtomByName(const char*);
1892 uint32_t fOrdinalBase;
1893 const ObjectFile::ReaderOptions& fOptions;
1894 const macho_header<P>* fHeader;
1895 const char* fStrings;
1896 const macho_nlist<P>* fSymbols;
1897 uint32_t fSymbolCount;
1898 const macho_segment_command<P>* fSegment;
1899 const uint32_t* fIndirectTable;
1900 std::vector<BaseAtom*> fAtoms;
1901 AddrToAtomMap fAddrToAtom;
1902 AddrToAtomMap fAddrToAbsoluteAtom;
1903 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
1904 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1905 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1906 std::vector<const char*> fDtraceProviderInfo;
1907 ObjectFile::Reader::DebugInfoKind fDebugInfo;
1909 const macho_section<P>* fehFrameSection;
1910 const macho_section<P>* fUTF16Section;
1911 std::set<BaseAtom*> fLSDAAtoms;
1912 const macho_section<P>* fDwarfDebugInfoSect;
1913 const macho_section<P>* fDwarfDebugAbbrevSect;
1914 const macho_section<P>* fDwarfDebugLineSect;
1915 const macho_section<P>* fDwarfDebugStringSect;
1916 const char* fDwarfTranslationUnitDir;
1917 const char* fDwarfTranslationUnitFile;
1918 std::map<uint32_t,const char*> fDwarfIndexToFile;
1919 std::vector<Stab> fStabs;
1920 std::vector<FDE_Atom_Info> fFDEInfos;
1921 std::vector<CIE_Atom_Info> fCIEInfos;
1923 bool fHasDTraceProbes;
1924 bool fHaveIndirectSymbols;
1925 bool fReplacementClasses;
1926 bool fHasLongBranchStubs;
1927 ObjectFile::Reader::ObjcConstraint fObjConstraint;
1928 uint32_t fCpuConstraint;
1929 const macho_section<P>* fSectionsStart;
1930 const macho_section<P>* fSectionsEnd;
1931 OAS fObjectAddressSpace;
1934 template <typename A>
1935 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1936 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
1937 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
1938 fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), fUTF16Section(NULL),
1939 fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
1940 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
1941 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
1942 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny),
1943 fSectionsStart(NULL), fSectionsEnd(NULL), fObjectAddressSpace(*this)
1946 if ( ! validFile(fileContent, false, 0) )
1947 throw "not a valid mach-o object file";
1949 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1951 // write out path for -t or -whatsloaded option
1952 if ( options.fLogObjectFiles || options.fLogAllFiles )
1953 printf("%s\n", path);
1955 // cache intersting pointers
1956 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1957 this->setCpuConstraint(header->cpusubtype());
1958 const uint32_t cmd_count = header->ncmds();
1959 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
1960 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
1961 const macho_load_command<P>* cmd = cmds;
1962 uint32_t undefinedStartIndex = 0;
1963 uint32_t undefinedEndIndex = 0;
1964 for (uint32_t i = 0; i < cmd_count; ++i) {
1965 switch (cmd->cmd()) {
1968 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1969 fSymbolCount = symtab->nsyms();
1970 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1971 fStrings = (char*)header + symtab->stroff();
1972 if ( undefinedEndIndex == 0 ) {
1973 undefinedStartIndex = 0;
1974 undefinedEndIndex = symtab->nsyms();
1980 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1981 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
1982 undefinedStartIndex = dsymtab->iundefsym();
1983 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
1991 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1992 fSegment = (macho_segment_command<P>*)cmd;
1996 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
1997 if ( cmd > cmdsEnd )
1998 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
2001 // if there are no load commands, then this file has no content, so no atoms
2002 if ( header->ncmds() < 1 )
2005 fSectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
2006 fSectionsEnd = &fSectionsStart[fSegment->nsects()];
2008 // inital guess for number of atoms
2009 fAtoms.reserve(fSymbolCount);
2011 // if there is an __eh_frame section, decode it into chunks to get atoms in that
2012 // section as well as division points for functions in __text
2013 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2014 if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
2015 fehFrameSection = sect;
2016 const char* msg = libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::getCFIs(fObjectAddressSpace, sect->addr(),
2017 sect->size(), fFDEInfos, fCIEInfos);
2018 if ( msg != NULL ) {
2019 throwf("malformed __eh_frame section: %s", msg);
2022 //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size());
2023 // add anonymous atoms for each CIE
2024 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2025 AnonymousAtom<A>* cieAtom = new AnonymousAtom<A>(*this, sect, it->cieAddress, 1);
2026 fAtoms.push_back(cieAtom);
2027 fAddrToAtom[it->cieAddress] = cieAtom;
2029 // add anonymous atoms for each FDE and LSDA
2030 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2031 //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);
2032 AnonymousAtom<A>* fdeAtom = new AnonymousAtom<A>(*this, sect, it->fdeAddress, 0);
2033 fAtoms.push_back(fdeAtom);
2034 fAddrToAtom[it->fdeAddress] = fdeAtom;
2035 if ( it->lsda.address != 0 ) {
2036 AnonymousAtom<A>* lsdaAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->lsda.address), it->lsda.address, 0);
2037 fAtoms.push_back(lsdaAtom);
2038 fAddrToAtom[it->lsda.address] = lsdaAtom;
2039 fLSDAAtoms.insert(lsdaAtom);
2044 else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) && (sect->size() != 0) ) {
2045 // if there is a __ustring section parse it into atoms
2046 fUTF16Section = sect;
2047 // first find all cleave points
2048 const uint16_t* words = (uint16_t*)((char*)(fHeader) + fUTF16Section->offset());
2049 unsigned int wordCount = fUTF16Section->size()/2;
2050 std::vector<pint_t> utf16Addreses;
2051 bool inString = false;
2052 for (unsigned int i=0; i < wordCount; ++i) {
2054 if ( words[i] == 0x0000 ) {
2059 if ( words[i] == 0x0000 ) {
2060 // skip over zero padding
2064 utf16Addreses.push_back(fUTF16Section->addr() + i*2);
2068 utf16Addreses.push_back(fUTF16Section->addr() + sect->size());
2069 // build map of symbols
2070 std::map<pint_t, const macho_nlist<P>* > symbolMap;
2071 for (int i=fSymbolCount-1; i >= 0 ; --i) {
2072 const macho_nlist<P>& sym = fSymbols[i];
2073 if ( (sym.n_type() & N_STAB) == 0 ) {
2074 uint8_t type = (sym.n_type() & N_TYPE);
2075 if ( type == N_SECT ) {
2076 if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) {
2077 // rdar://problem/7429384 don't coalesce UTF16 strings unless label starts with ___utf16_string
2078 if ( strncmp(&fStrings[sym.n_strx()], "___utf16_string", 15) != 0 ) {
2079 symbolMap[sym.n_value()] = &sym;
2080 // <rdar://problem/7516793> if this symbol is a string of just 0x0000, it may not be in utf16Addreses
2081 if ( words[(sym.n_value() - sect->addr())/2] == 0x0000 ) {
2082 for(typename std::vector<pint_t>::iterator sit=utf16Addreses.begin(); sit != utf16Addreses.end(); ++sit) {
2083 if ( *sit == sym.n_value() ) {
2084 // already in utf16Addreses
2087 if ( *sit > sym.n_value() ) {
2089 utf16Addreses.insert(sit, sym.n_value());
2099 // make atom for each string
2100 for(int i=utf16Addreses.size()-2; i >=0 ; --i) {
2101 pint_t size = utf16Addreses[i+1] - utf16Addreses[i];
2102 typename std::map<pint_t, const macho_nlist<P>* >::iterator pos = symbolMap.find(utf16Addreses[i]);
2103 if ( pos == symbolMap.end() ) {
2104 AnonymousAtom<A>* strAtom = new AnonymousAtom<A>(*this, fUTF16Section, utf16Addreses[i], size);
2105 fAtoms.push_back(strAtom);
2106 fAddrToAtom[utf16Addreses[i]] = strAtom;
2109 SymbolAtom<A>* newAtom = new SymbolAtom<A>(*this, pos->second, fUTF16Section);
2110 fAtoms.push_back(newAtom);
2111 fAddrToAtom[utf16Addreses[i]] = newAtom;
2112 newAtom->setSize(size);
2119 // add all atoms that have entries in symbol table
2120 BaseAtom* sectionEndAtoms[fSegment->nsects()];
2121 for (unsigned int i=0; i < fSegment->nsects(); ++i)
2122 sectionEndAtoms[i] = NULL;
2123 for (int i=fSymbolCount-1; i >= 0 ; --i) {
2124 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name
2125 const macho_nlist<P>& sym = fSymbols[i];
2126 if ( (sym.n_type() & N_STAB) == 0 ) {
2127 uint8_t type = (sym.n_type() & N_TYPE);
2128 if ( type == N_SECT ) {
2129 const macho_section<P>* section = &fSectionsStart[sym.n_sect()-1];
2130 const pint_t sectionStartAddr = section->addr();
2131 const pint_t sectionEndAddr = sectionStartAddr + section->size();
2132 bool suppress = false;
2133 // ignore atoms in debugger sections
2134 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
2135 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
2136 // ignore dtrace probe labels
2137 fHasDTraceProbes = true;
2139 else if ( fStrings[sym.n_strx()] == 'L' ) {
2140 // ignore L labels, <rdar://problem/3962731>
2142 else if ( section == fehFrameSection ) {
2143 // ignore labels in __eh_frame section
2145 else if ( section == fUTF16Section ) {
2146 // ignore labels in __ustring section
2149 // ignore labels for atoms in other sections
2150 switch ( section->flags() & SECTION_TYPE ) {
2152 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
2153 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
2156 case S_4BYTE_LITERALS:
2157 case S_8BYTE_LITERALS:
2158 case S_16BYTE_LITERALS:
2159 case S_CSTRING_LITERALS:
2162 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
2163 if ( (pos != fAddrToAtom.end()) && (pos->second->getSectionRecord() == section) ) {
2164 if ( fLSDAAtoms.count(pos->second) != 0 ) {
2165 // already have LSDA atom from for this address, ignore compiler's label
2170 // another label to an existing address in the same section, make this an alias
2171 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
2175 if ( sym.n_value() == sectionEndAddr ) {
2176 // Symbol address is at end of section. This can interfere
2177 // with a symbol at the start of the next section, so don't
2178 // add to fAddrToAtom. But do track in sectionEndAtoms so we
2179 // still make aliases if there are duplicates.
2180 if ( sectionEndAtoms[sym.n_sect()-1] == NULL ) {
2181 newAtom = new SymbolAtom<A>(*this, &sym, section);
2182 sectionEndAtoms[sym.n_sect()-1] = newAtom;
2183 // if this is a zero length section, so add to fAddrToAtom
2184 if ( sym.n_value() == sectionStartAddr )
2185 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2188 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *sectionEndAtoms[sym.n_sect()-1]);
2192 // make SymbolAtom atom for this address
2193 newAtom = new SymbolAtom<A>(*this, &sym, section);
2194 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2198 fAtoms.push_back(newAtom);
2201 case S_SYMBOL_STUBS:
2202 case S_LAZY_SYMBOL_POINTERS:
2203 case S_NON_LAZY_SYMBOL_POINTERS:
2204 // ignore symboled stubs produces by old ld64
2207 warning("symbol %s found in unsupported section in %s",
2208 &fStrings[sym.n_strx()], this->getPath());
2213 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
2214 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
2216 else if ( (type == N_UNDF) && (sym.n_value() == 0) ) {
2217 const char* symName = &fStrings[sym.n_strx()];
2218 if ( strncmp(symName, "section$start$", 14) == 0)
2219 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, true, symName, &symName[14]));
2220 else if ( strncmp(symName, "section$end$", 12) == 0)
2221 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, false, symName, &symName[12]));
2223 else if ( type == N_ABS ) {
2224 const char* symName = &fStrings[sym.n_strx()];
2225 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
2226 // ignore .objc_class_name_* symbols
2229 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
2230 // ignore empty *.eh symbols
2233 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
2234 fAtoms.push_back(abAtom);
2235 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
2238 else if ( type == N_INDR ) {
2239 fHaveIndirectSymbols = true;
2244 // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names
2245 if ( fehFrameSection != NULL ) {
2246 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2247 // add if not already an atom at that address
2248 if ( fAddrToAtom.find(it->function.address) == fAddrToAtom.end() ) {
2249 AnonymousAtom<A>* funcAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->function.address), it->function.address, 0);
2250 fAtoms.push_back(funcAtom);
2251 fAddrToAtom[it->function.address] = funcAtom;
2252 // even though we've made a new atom, be conservative and make sure they lay out together
2253 if ( canScatterAtoms() ) {
2254 AtomAndOffset prev = findAtomAndOffset(it->function.address-1);
2255 if ( prev.atom != NULL ) {
2256 if ( ((BaseAtom*)(prev.atom))->getSectionRecord() == funcAtom->getSectionRecord() )
2257 new Reference<A>(A::kFollowOn, prev, AtomAndOffset(funcAtom));
2265 // add all fixed size anonymous atoms from special sections
2266 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2267 pint_t atomSize = 0;
2268 uint8_t type (sect->flags() & SECTION_TYPE);
2269 validSectionType(type);
2270 bool suppress = false;
2272 case S_SYMBOL_STUBS:
2274 atomSize = sect->reserved2();
2276 case S_LAZY_SYMBOL_POINTERS:
2278 atomSize = sizeof(pint_t);
2280 case S_NON_LAZY_SYMBOL_POINTERS:
2281 case S_LITERAL_POINTERS:
2282 case S_MOD_INIT_FUNC_POINTERS:
2283 case S_MOD_TERM_FUNC_POINTERS:
2284 atomSize = sizeof(pint_t);
2287 atomSize = sizeof(pint_t)*2;
2289 case S_4BYTE_LITERALS:
2292 case S_8BYTE_LITERALS:
2295 case S_16BYTE_LITERALS:
2299 // special case ObjC classes to synthesize .objc_class_name_* symbols
2300 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
2301 // gcc sometimes over aligns class structure
2302 uint32_t align = 1 << sect->align();
2303 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
2305 // get objc Garbage Collection info
2306 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
2307 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
2308 // struct objc_image_info {
2309 // uint32_t version; // initially 0
2312 // #define OBJC_IMAGE_SUPPORTS_GC 2
2313 // #define OBJC_IMAGE_GC_ONLY 4
2315 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
2316 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
2317 uint32_t flags = E::get32(contents[1]);
2318 if ( (flags & 4) == 4 )
2319 fObjConstraint = ObjectFile::Reader::kObjcGC;
2320 else if ( (flags & 2) == 2 )
2321 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
2323 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
2324 if ( (flags & 1) == 1 )
2325 fReplacementClasses = true;
2326 // don't make atom for this section
2327 atomSize = sect->size();
2331 warning("can't parse __OBJC/__image_info section in %s", fPath);
2334 // special case constant NS/CFString literals and make an atom out of each one
2335 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
2336 atomSize = 4 * sizeof(pint_t);
2338 // special case class reference sections
2339 else if ( (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0) ) {
2340 atomSize = sizeof(pint_t);;
2344 if ( atomSize != 0 ) {
2345 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
2346 pint_t atomAddr = sect->addr() + sectOffset;
2347 // add if not already an atom at that address
2348 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
2349 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
2351 fAtoms.push_back(newAtom);
2352 fAddrToAtom[atomAddr] = newAtom->redirectTo();
2358 // add all c-string anonymous atoms
2359 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2360 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
2363 BaseAtom* mostAlignedEmptyString = NULL;
2364 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
2365 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
2366 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
2367 stringAddr = sect->addr() + sectOffset;
2368 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
2369 // add if not already a non-zero length atom at that address
2370 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(stringAddr);
2371 if ( (pos == fAddrToAtom.end()) || (pos->second->getSize() == 0) ) {
2372 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
2373 if ( stringLen == 1 ) {
2374 // because of padding it may look like there are lots of empty strings, keep track of all
2375 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
2376 // record empty string with greatest alignment requirement
2377 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
2378 if ( (mostAlignedEmptyString == NULL)
2379 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
2380 mostAlignedEmptyString = newAtom;
2381 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
2385 fAtoms.push_back(newAtom);
2386 fAddrToAtom[stringAddr] = newAtom;
2390 // map all uses of empty strings to the most aligned one
2391 if ( mostAlignedEmptyString != NULL ) {
2392 // make most aligned atom a real atom
2393 fAtoms.push_back(mostAlignedEmptyString);
2394 // map all other empty atoms to this one
2395 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
2396 fAddrToAtom[it->first] = mostAlignedEmptyString;
2402 // sort all atoms so far by address and section
2403 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2405 //fprintf(stderr, "sorted atoms:\n");
2406 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
2407 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
2409 // create atoms to cover any non-debug ranges not handled above
2410 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2411 pint_t sectionStartAddr = sect->addr();
2412 pint_t sectionEndAddr = sect->addr() + sect->size();
2413 // don't set follow-on atoms in __eh_frame section
2414 const bool setFollowOnAtom = !canScatterAtoms() && (sect != fehFrameSection);
2415 if ( sect->size() != 0 ) {
2416 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
2417 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
2418 fDebugInfo = kDebugInfoDwarf;
2419 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
2420 fDwarfDebugInfoSect = sect;
2421 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
2422 fDwarfDebugAbbrevSect = sect;
2423 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
2424 fDwarfDebugLineSect = sect;
2425 else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
2426 fDwarfDebugStringSect = sect;
2429 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
2430 throw "object file contains old DWARF debug info - rebuild with newer compiler";
2432 uint8_t type (sect->flags() & SECTION_TYPE);
2437 // if there is not an atom already at the start of this section, add an anonymous one
2438 pint_t previousAtomAddr = 0;
2439 BaseAtom* previousAtom = NULL;
2440 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
2441 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
2442 fAddrToAtom[sect->addr()] = newAtom;
2443 fAtoms.push_back(newAtom);
2444 previousAtomAddr = sectionStartAddr;
2445 previousAtom = newAtom;
2446 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2448 // calculate size of all atoms in this section and add follow-on references
2449 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2450 BaseAtom* atom = (BaseAtom*)(*it);
2451 pint_t atomAddr = atom->getObjectAddress();
2452 if ( atom->getSectionRecord() == sect ) {
2453 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
2454 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
2455 previousAtom->setSize(atomAddr - previousAtomAddr);
2456 if ( setFollowOnAtom && (atom != previousAtom) )
2457 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
2459 previousAtomAddr = atomAddr;
2460 previousAtom = atom;
2463 if ( previousAtom != NULL ) {
2464 // set last atom in section
2465 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
2473 // check for object file that defines no objc classes, but uses objc classes
2474 // check for dtrace provider info
2475 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
2476 const macho_nlist<P>& sym = fSymbols[i];
2477 if ( (sym.n_type() & N_STAB) == 0 ) {
2478 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
2479 const char* undefinedName = &fStrings[sym.n_strx()];
2480 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
2483 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
2484 if ( strchr(undefinedName, '$') != NULL ) {
2485 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
2486 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
2487 // is extra provider info
2488 fDtraceProviderInfo.push_back(undefinedName);
2496 // add relocation based references to sections that have atoms with pending names
2497 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2498 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
2499 addReferencesForSection(sect);
2502 // update any anonymous atoms that need references built in order to name themselves
2503 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
2504 (*it)->resolveName();
2507 // add relocation based references to other sections
2508 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2509 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
2510 addReferencesForSection(sect);
2513 // add objective-c references
2515 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2516 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
2517 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
2518 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
2519 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
2520 if ( classRef->getFixUpOffset() == 0 ) {
2521 const char* classStr = classRef->getTargetName();
2522 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
2523 const char* className;
2524 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
2525 new Reference<A>(A::kNoFixUp, ao, className, 0);
2533 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
2534 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
2535 AnonymousAtom<A>* localNonLazy = *it;
2536 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
2537 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
2538 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
2542 // add personality references to CIEs
2543 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2544 if ( it->personality.offsetInFDE != 0 )
2545 addCiePersonalityReference(fAddrToAtom[it->cieAddress], it->personality.offsetInFDE, it->personality.encodingOfAddress);
2548 // add all references for FDEs, including implicit group references
2549 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2550 AtomAndOffset funcAO = this->findAtomAndOffset(it->function.address);
2551 if ( funcAO.offset != 0 )
2552 warning("FDE does not point to start of function %s\n", funcAO.atom->getDisplayName());
2553 AtomAndOffset fdeAO = this->findAtomAndOffset(it->fdeAddress);
2554 if ( fdeAO.offset != 0 )
2555 warning("FDE does start its own atom %s\n", funcAO.atom->getDisplayName());
2556 AtomAndOffset cieAO = this->findAtomAndOffset(it->cie.address);
2557 if ( cieAO.offset != 0 )
2558 warning("CIE does start its own atom %s\n", cieAO.atom->getDisplayName());
2559 AtomAndOffset lsdaAO;
2560 if ( it->lsda.address != 0 ) {
2561 lsdaAO = this->findAtomAndOffset(it->lsda.address);
2562 if ( lsdaAO.offset != 0 )
2563 warning("LSDA does start its own atom %s\n", lsdaAO.atom->getDisplayName());
2566 // add reference from FDE to CIE
2567 AtomAndOffset cieInfdeAO = AtomAndOffset(fdeAO.atom, it->cie.offsetInFDE);
2568 new Reference<A>(A::kPointerDiff32, cieInfdeAO, cieAO, cieInfdeAO);
2570 // add reference from FDE to function
2571 addFdeReference(it->function.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->function.offsetInFDE), funcAO);
2573 // add reference from FDE to LSDA
2574 if ( it->lsda.address != 0 ) {
2575 addFdeReference(it->lsda.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->lsda.offsetInFDE), lsdaAO);
2578 // FDE is in group lead by function atom
2579 new Reference<A>(A::kGroupSubordinate, funcAO, fdeAO);
2581 // LSDA is in group lead by function atom
2582 if ( it->lsda.address != 0 ) {
2583 new Reference<A>(A::kGroupSubordinate, funcAO, lsdaAO);
2584 // add back reference from LSDA to owning function
2585 new Reference<A>(A::kNoFixUp, lsdaAO, funcAO);
2588 // compute compact encoding for this FDE
2589 if ( fOptions.fAddCompactUnwindEncoding ) {
2590 ((BaseAtom*)(funcAO.atom))->setCompactUnwindEncoding(it->fdeAddress);
2591 // add reference from function atom to personality function
2592 // the only reference a CIE can have is the reference to the personality function
2593 std::vector<class ObjectFile::Reference*>& cieRefs = cieAO.atom->getReferences();
2594 if ( cieRefs.size() == 1 ) {
2595 new Reference<A>((typename A::ReferenceKinds)((BaseAtom*)(funcAO.atom))->getPersonalityReferenceKind(),
2596 funcAO, cieRefs[0]->getTargetName(), 0);
2601 // add command line aliases
2602 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
2603 BaseAtom* target = this->findAtomByName(it->realName);
2604 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
2605 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
2608 // add dtrace probe locations
2609 if ( fHasDTraceProbes ) {
2610 for (uint32_t i=0; i < fSymbolCount; ++i) {
2611 const macho_nlist<P>& sym = fSymbols[i];
2612 if ( (sym.n_type() & N_STAB) == 0 ) {
2613 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
2614 const char* symbolName = &fStrings[sym.n_strx()];
2615 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
2616 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
2617 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
2624 // turn indirect symbols into SymbolAliasAtom
2625 if ( fHaveIndirectSymbols ) {
2626 for (uint32_t i=0; i < fSymbolCount; ++i) {
2627 const macho_nlist<P>& sym = fSymbols[i];
2628 if ( (sym.n_type() & N_STAB) == 0 ) {
2629 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
2630 const char* aliasName = &fStrings[sym.n_strx()];
2631 const char* targetName = &fStrings[sym.n_value()];
2632 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
2633 BaseAtom* target = this->findAtomByName(targetName);
2634 // only currently support N_INDR based aliases to something in the same .o file
2635 if ( target != NULL ) {
2636 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
2637 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
2644 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
2645 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
2648 // add translation unit info from dwarf
2650 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2651 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
2652 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2653 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
2654 // if can't parse dwarf, warn and give up
2655 fDwarfTranslationUnitFile = NULL;
2656 fDwarfTranslationUnitDir = NULL;
2657 warning("can't parse dwarf compilation unit info in %s", this->getPath());
2658 fDebugInfo = kDebugInfoNone;
2663 // add line number info to atoms from dwarf
2664 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2665 // file with just data will have no __debug_line info
2666 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
2667 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2668 // validate stmt_list
2669 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
2670 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
2671 if ( debug_line != NULL ) {
2672 struct line_reader_data* lines = line_open(&debug_line[stmtList],
2673 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
2674 struct line_info result;
2675 ObjectFile::Atom* curAtom = NULL;
2676 uint32_t curAtomOffset = 0;
2677 uint32_t curAtomAddress = 0;
2678 uint32_t curAtomSize = 0;
2679 if ( lines != NULL ) {
2680 while ( line_next (lines, &result, line_stop_pc) ) {
2681 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
2682 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
2683 // work around weird debug line table compiler generates if no functions in __text section
2684 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
2686 // for performance, see if in next pc is in current atom
2687 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
2688 curAtomOffset = result.pc - curAtomAddress;
2690 // or pc at end of current atom
2691 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
2692 curAtomOffset = result.pc - curAtomAddress;
2695 // do slow look up of atom by address
2696 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
2698 if ( curAtom == NULL )
2699 break; // file has line info but no functions
2700 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
2701 // a one line function can be returned by line_next() as one entry with pc at end of blob
2702 // look for alt atom starting at end of previous atom
2703 uint32_t previousEnd = curAtomAddress+curAtomSize;
2704 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
2705 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
2707 curAtomOffset = alt.offset;
2708 curAtomAddress = previousEnd - alt.offset;
2709 curAtomSize = curAtom->getSize();
2712 curAtomOffset = ao.offset;
2713 curAtomAddress = result.pc - ao.offset;
2714 curAtomSize = curAtom->getSize();
2718 curAtomOffset = ao.offset;
2719 curAtomAddress = result.pc - ao.offset;
2720 curAtomSize = curAtom->getSize();
2723 const char* filename;
2724 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2725 if ( pos == fDwarfIndexToFile.end() ) {
2726 filename = line_file(lines, result.file);
2727 fDwarfIndexToFile[result.file] = filename;
2730 filename = pos->second;
2732 ObjectFile::LineInfo info;
2733 info.atomOffset = curAtomOffset;
2734 info.fileName = filename;
2735 info.lineNumber = result.line;
2736 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2737 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2738 ((BaseAtom*)curAtom)->addLineInfo(info);
2739 if ( result.end_of_sequence ) {
2747 warning("could not parse dwarf line number info in %s", this->getPath());
2753 // if no dwarf, try processing stabs debugging info
2754 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2755 // scan symbol table for stabs entries
2756 fStabs.reserve(fSymbolCount); // reduce re-allocations
2757 BaseAtom* currentAtom = NULL;
2758 pint_t currentAtomAddress = 0;
2759 enum { start, inBeginEnd, inFun } state = start;
2760 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2761 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2762 bool useStab = true;
2763 uint8_t type = sym->n_type();
2764 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2765 if ( (type & N_STAB) != 0 ) {
2766 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
2770 stab.other = sym->n_sect();
2771 stab.desc = sym->n_desc();
2772 stab.value = sym->n_value();
2778 // beginning of function block
2780 // fall into case to lookup atom by addresss
2783 currentAtomAddress = sym->n_value();
2784 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2785 if ( currentAtom != NULL ) {
2786 stab.atom = currentAtom;
2787 stab.string = symString;
2790 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
2791 (uint64_t)sym->n_value(), path);
2800 // not associated with an atom, just copy
2801 stab.string = symString;
2805 // n_value field is NOT atom address ;-(
2806 // need to find atom by name match
2807 const char* colon = strchr(symString, ':');
2808 if ( colon != NULL ) {
2809 // build underscore leading name
2810 int nameLen = colon - symString;
2811 char symName[nameLen+2];
2812 strlcpy(&symName[1], symString, nameLen+1);
2814 symName[nameLen+1] = '\0';
2815 currentAtom = findAtomByName(symName);
2816 if ( currentAtom != NULL ) {
2817 stab.atom = currentAtom;
2818 stab.string = symString;
2822 // might be a debug-note without trailing :G()
2823 currentAtom = findAtomByName(symString);
2824 if ( currentAtom != NULL ) {
2825 stab.atom = currentAtom;
2826 stab.string = symString;
2829 if ( stab.atom == NULL ) {
2830 // ld_classic added bogus GSYM stabs for old style dtrace probes
2831 if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
2832 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
2838 // old style stabs without BNSYM
2840 currentAtomAddress = sym->n_value();
2841 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2842 if ( currentAtom != NULL ) {
2843 stab.atom = currentAtom;
2844 stab.string = symString;
2847 warning("can't find atom for stabs FUN at %08llX in %s",
2848 (uint64_t)currentAtomAddress, path);
2853 stab.string = symString;
2859 stab.string = symString;
2860 // -gfull built .o file
2863 warning("unknown stabs type 0x%X in %s", type, path);
2867 stab.atom = currentAtom;
2876 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2877 if ( nestedAtom != NULL ) {
2878 stab.atom = nestedAtom;
2879 stab.string = symString;
2882 warning("can't find atom for stabs 0x%X at %08llX in %s",
2883 type, (uint64_t)sym->n_value(), path);
2890 // adjust value to be offset in atom
2891 stab.value -= currentAtomAddress;
2893 stab.string = symString;
2900 if ( sym->n_sect() != 0 ) {
2901 // found another start stab, must be really old stabs...
2902 currentAtomAddress = sym->n_value();
2903 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2904 if ( currentAtom != NULL ) {
2905 stab.atom = currentAtom;
2906 stab.string = symString;
2909 warning("can't find atom for stabs FUN at %08llX in %s",
2910 (uint64_t)currentAtomAddress, path);
2914 // found ending stab, switch back to start state
2915 stab.string = symString;
2916 stab.atom = currentAtom;
2924 // adjust value to be offset in atom
2925 stab.value -= currentAtomAddress;
2926 stab.atom = currentAtom;
2929 stab.string = symString;
2933 stab.atom = currentAtom;
2934 stab.string = symString;
2939 // add to list of stabs for this .o file
2941 fStabs.push_back(stab);
2947 // special case precompiled header .o file (which has no content) to have one empty atom
2948 if ( fAtoms.size() == 0 ) {
2949 int pathLen = strlen(path);
2950 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2951 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2952 //phony->fSynthesizedName = ".gch.o";
2953 fAtoms.push_back(phony);
2958 // sort all atoms by address
2959 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2961 // set ordinal and sort references in each atom
2962 uint32_t index = fOrdinalBase;
2963 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2964 BaseAtom* atom = (BaseAtom*)(*it);
2965 atom->setOrdinal(index++);
2966 atom->sortReferences();
2971 template <typename A>
2972 const macho_section<typename A::P>* Reader<A>::getSectionForAddress(pint_t addr)
2974 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2975 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) )
2978 throwf("section not found for address 0x%08llX", (uint64_t)addr);
2981 template <typename A>
2982 ObjectFile::Atom* Reader<A>::getFunctionAtomFromFDEAddress(pint_t addr)
2984 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2985 if ( it->fdeAddress == addr ) {
2986 return findAtomAndOffset(it->function.address).atom;
2989 // CIEs won't be in fFDEInfos
2993 template <typename A>
2994 ObjectFile::Atom* Reader<A>::getFunctionAtomFromLSDAAddress(pint_t addr)
2996 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2997 if ( it->lsda.address == addr ) {
2998 return findAtomAndOffset(it->function.address).atom;
3006 void ObjectFileAddressSpace<x86_64>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
3008 // mach-o x86_64 is different, the content of a section with a relocation is the addend
3009 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + sect->reloff());
3010 const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
3011 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3012 std::map<uint32_t,uint64_t>::iterator pos;
3013 switch ( reloc->r_type() ) {
3014 case X86_64_RELOC_UNSIGNED:
3015 pos = map.find(reloc->r_address());
3016 if ( pos != map.end() )
3017 pos->second += fReader.fSymbols[reloc->r_symbolnum()].n_value();
3019 map[reloc->r_address()] = fReader.fSymbols[reloc->r_symbolnum()].n_value();
3021 case X86_64_RELOC_SUBTRACTOR:
3022 map[reloc->r_address()] = -fReader.fSymbols[reloc->r_symbolnum()].n_value();
3024 case X86_64_RELOC_GOT:
3025 // there is no good address to return here.
3026 // GOT slots are synthsized by the linker
3027 // this is used for the reference to the personality function in CIEs
3028 map[reloc->r_address()] = 0;
3031 fprintf(stderr, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc->r_address());
3037 template <typename A>
3038 void ObjectFileAddressSpace<A>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
3040 // in all architectures except x86_64, the section contents are already fixed up to point
3041 // to content in the same object file.
3045 uint64_t ObjectFileAddressSpace<x86_64>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
3047 // mach-o x86_64 is different, the content of a section with a relocation is the addend
3048 uint64_t result = 0;
3049 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + relocsOffset);
3050 const macho_relocation_info<P>* relocsEnd = &relocs[relocsCount];
3051 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3052 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address());
3053 if ( reloc->r_address() == sectOffset ) {
3054 switch ( reloc->r_type() ) {
3055 case X86_64_RELOC_UNSIGNED:
3056 result += fReader.fSymbols[reloc->r_symbolnum()].n_value();
3058 case X86_64_RELOC_SUBTRACTOR:
3059 result -= fReader.fSymbols[reloc->r_symbolnum()].n_value();
3061 case X86_64_RELOC_GOT:
3062 // there is no good address to return here.
3063 // GOT slots are synthsized by the linker
3064 // this is used for the reference to the personality function in CIEs
3068 fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset, reloc->r_type(), reloc->r_symbolnum());
3073 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result);
3077 template <typename A>
3078 typename A::P::uint_t ObjectFileAddressSpace<A>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
3080 // in all architectures except x86_64, the section contents are already fixed up to point
3081 // to content in the same object file.
3087 // FSF exception handling Pointer-Encoding constants
3088 // Used in CFI augmentation by gcc compiler
3090 DW_EH_PE_ptr = 0x00,
3091 DW_EH_PE_uleb128 = 0x01,
3092 DW_EH_PE_udata2 = 0x02,
3093 DW_EH_PE_udata4 = 0x03,
3094 DW_EH_PE_udata8 = 0x04,
3095 DW_EH_PE_signed = 0x08,
3096 DW_EH_PE_sleb128 = 0x09,
3097 DW_EH_PE_sdata2 = 0x0A,
3098 DW_EH_PE_sdata4 = 0x0B,
3099 DW_EH_PE_sdata8 = 0x0C,
3100 DW_EH_PE_absptr = 0x00,
3101 DW_EH_PE_pcrel = 0x10,
3102 DW_EH_PE_textrel = 0x20,
3103 DW_EH_PE_datarel = 0x30,
3104 DW_EH_PE_funcrel = 0x40,
3105 DW_EH_PE_aligned = 0x50,
3106 DW_EH_PE_indirect = 0x80,
3107 DW_EH_PE_omit = 0xFF
3111 void Reader<x86_64>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
3113 if ( encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4) )
3114 throw "unexpected personality encoding in CIE";
3116 // walk relocs looking for reloc in this CIE
3117 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
3118 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
3119 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
3120 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3121 if ( reloc->r_address() == sectOffset ) {
3122 switch ( reloc->r_type() ) {
3123 case X86_64_RELOC_GOT:
3124 if ( !reloc->r_extern() )
3125 throw "GOT reloc not extern for personality function";
3126 new Reference<x86_64>(x86_64::kPCRel32GOT, AtomAndOffset(cieAtom, offsetInCIE), &fStrings[fSymbols[reloc->r_symbolnum()].n_strx()], 4);
3129 throw "expected GOT reloc for personality function";
3133 throw "personality function not found for CIE";
3137 bool Reader<ppc>::isSectDiffReloc(uint8_t r_type)
3140 case PPC_RELOC_LOCAL_SECTDIFF:
3141 case PPC_RELOC_SECTDIFF:
3148 bool Reader<ppc64>::isSectDiffReloc(uint8_t r_type)
3151 case PPC_RELOC_LOCAL_SECTDIFF:
3152 case PPC_RELOC_SECTDIFF:
3159 bool Reader<x86>::isSectDiffReloc(uint8_t r_type)
3162 case GENERIC_RELOC_LOCAL_SECTDIFF:
3163 case GENERIC_RELOC_SECTDIFF:
3170 bool Reader<arm>::isSectDiffReloc(uint8_t r_type)
3173 case ARM_RELOC_LOCAL_SECTDIFF:
3174 case ARM_RELOC_SECTDIFF:
3180 template <typename A>
3181 void Reader<A>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
3183 if ( (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4)) && (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel)) )
3184 throw "unexpected personality encoding in CIE";
3186 // walk relocs looking for personality reloc in this CIE
3187 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
3188 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
3189 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
3190 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3191 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3195 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3196 if ( sreloc->r_address() == sectOffset ) {
3197 if ( isSectDiffReloc(sreloc->r_type()) ) {
3198 // r_value is address of non-lazy-pointer to personality function
3199 new Reference<A>(A::kPointerDiff32, AtomAndOffset(cieAtom, offsetInCIE), AtomAndOffset(cieAtom, offsetInCIE),
3200 findAtomAndOffset(sreloc->r_value()));
3206 throw "can't find relocation for personality in CIE";
3209 template <typename A>
3210 void Reader<A>::addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target)
3212 if ( (encoding & 0xF0) != DW_EH_PE_pcrel )
3213 throw "unsupported encoding in FDE";
3214 Kinds kind = A::kNoFixUp;
3215 switch ( encoding & 0xF ) {
3217 kind = A::kPointerDiff;
3219 case DW_EH_PE_sdata4:
3220 kind = A::kPointerDiff32;
3223 throw "unsupported encoding in FDE";
3225 new Reference<A>(kind, inFDE, inFDE, target);
3228 template <typename A>
3229 typename A::P::uint_t ObjectFileAddressSpace<A>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
3231 pint_t startAddr = addr;
3236 switch (encoding & 0x0F) {
3238 result = getP(addr);
3239 p += sizeof(pint_t);
3242 case DW_EH_PE_uleb128:
3243 result = getULEB128(addr, end);
3245 case DW_EH_PE_udata2:
3246 result = get16(addr);
3250 case DW_EH_PE_udata4:
3251 result = get32(addr);
3255 case DW_EH_PE_udata8:
3256 result = get64(addr);
3260 case DW_EH_PE_sleb128:
3261 result = getSLEB128(addr, end);
3263 case DW_EH_PE_sdata2:
3264 result = (int16_t)get16(addr);
3268 case DW_EH_PE_sdata4:
3269 result = (int32_t)get32(addr);
3273 case DW_EH_PE_sdata8:
3274 result = get64(addr);
3279 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3282 // then add relative offset
3283 switch ( encoding & 0x70 ) {
3284 case DW_EH_PE_absptr:
3287 case DW_EH_PE_pcrel:
3288 // <rdar://problem/7200658> pc-rel sdata4 should return zero if content is zero
3289 if ( (result != 0) || ((encoding & DW_EH_PE_indirect) != 0) )
3290 result += startAddr;
3292 case DW_EH_PE_textrel:
3293 throw "DW_EH_PE_textrel pointer encoding not supported";
3295 case DW_EH_PE_datarel:
3296 throw "DW_EH_PE_datarel pointer encoding not supported";
3298 case DW_EH_PE_funcrel:
3299 throw "DW_EH_PE_funcrel pointer encoding not supported";
3301 case DW_EH_PE_aligned:
3302 throw "DW_EH_PE_aligned pointer encoding not supported";
3305 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3309 if ( encoding & DW_EH_PE_indirect )
3310 result = getP(result);
3316 uint32_t SymbolAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3320 char warningBuffer[1024];
3321 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
3322 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3323 if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
3324 //if ( fOwner.fOptions.fForDyld )
3325 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3327 if ( fOwner.fOptions.fWarnCompactUnwind )
3328 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
3334 uint32_t SymbolAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3338 char warningBuffer[1024];
3339 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
3340 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3341 if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
3342 //if ( fOwner.fOptions.fForDyld )
3343 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3345 if ( fOwner.fOptions.fWarnCompactUnwind )
3346 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
3352 uint32_t SymbolAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3354 // compact encoding not supported for ppc
3359 uint32_t SymbolAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3361 // compact encoding not supported for ppc64
3366 uint32_t SymbolAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3368 // compact encoding not supported for arm
3373 template <typename A>
3374 uint8_t SymbolAtom<A>::getLSDAReferenceKind() const
3376 return A::kGroupSubordinate;
3380 uint8_t SymbolAtom<x86_64>::getPersonalityReferenceKind() const
3382 return x86_64::kGOTNoFixUp;
3386 uint8_t SymbolAtom<x86>::getPersonalityReferenceKind() const
3388 return x86::kNoFixUp;
3391 template <typename A>
3392 uint8_t SymbolAtom<A>::getPersonalityReferenceKind() const
3394 // only used with architectures that support compact unwinding
3400 uint32_t AnonymousAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3404 char warningBuffer[1024];
3405 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
3406 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3407 if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
3408 //if ( fOwner.fOptions.fForDyld )
3409 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3411 if ( fOwner.fOptions.fWarnCompactUnwind )
3412 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3418 uint32_t AnonymousAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3422 char warningBuffer[1024];
3423 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
3424 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3425 if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
3426 //if ( fOwner.fOptions.fForDyld )
3427 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3429 if ( fOwner.fOptions.fWarnCompactUnwind )
3430 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3436 uint32_t AnonymousAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3438 // compact encoding not supported for ppc
3443 uint32_t AnonymousAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3445 // compact encoding not supported for ppc64
3450 uint32_t AnonymousAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3452 // compact encoding not supported for arm
3457 template <typename A>
3458 uint8_t AnonymousAtom<A>::getLSDAReferenceKind() const
3460 return A::kGroupSubordinate;
3464 uint8_t AnonymousAtom<x86_64>::getPersonalityReferenceKind() const
3466 return x86_64::kGOTNoFixUp;
3470 uint8_t AnonymousAtom<x86>::getPersonalityReferenceKind() const
3472 return x86::kNoFixUp;
3475 template <typename A>
3476 uint8_t AnonymousAtom<A>::getPersonalityReferenceKind() const
3478 // only used with architectures that support compact unwinding
3489 void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
3491 switch (cpusubtype) {
3492 case CPU_SUBTYPE_POWERPC_ALL:
3493 case CPU_SUBTYPE_POWERPC_750:
3494 case CPU_SUBTYPE_POWERPC_7400:
3495 case CPU_SUBTYPE_POWERPC_7450:
3496 case CPU_SUBTYPE_POWERPC_970:
3497 fCpuConstraint = cpusubtype;
3500 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3501 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
3507 void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
3509 switch (cpusubtype) {
3510 case CPU_SUBTYPE_ARM_ALL:
3511 case CPU_SUBTYPE_ARM_V4T:
3512 case CPU_SUBTYPE_ARM_V5TEJ:
3513 case CPU_SUBTYPE_ARM_V6:
3514 case CPU_SUBTYPE_ARM_XSCALE:
3515 case CPU_SUBTYPE_ARM_V7:
3516 fCpuConstraint = cpusubtype;
3519 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3520 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
3525 template <typename A>
3526 void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
3528 // no cpu sub types for this architecture
3532 uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
3534 switch ( previous ) {
3535 case CPU_SUBTYPE_POWERPC_ALL:
3536 return fCpuConstraint;
3538 case CPU_SUBTYPE_POWERPC_750:
3539 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
3540 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
3541 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3542 return fCpuConstraint;
3544 case CPU_SUBTYPE_POWERPC_7400:
3545 case CPU_SUBTYPE_POWERPC_7450:
3546 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3547 return fCpuConstraint;
3549 case CPU_SUBTYPE_POWERPC_970:
3550 // G5 can run everything
3553 throw "Unhandled PPC cpu subtype!";
3562 uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
3565 case CPU_SUBTYPE_ARM_ALL:
3566 return fCpuConstraint;
3568 case CPU_SUBTYPE_ARM_V5TEJ:
3569 // v6, v7, and xscale are more constrained than previous file (v5), so use it
3570 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
3571 || (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3572 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3573 return fCpuConstraint;
3575 case CPU_SUBTYPE_ARM_V4T:
3576 // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
3577 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3578 || (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
3579 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
3580 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3581 return fCpuConstraint;
3583 case CPU_SUBTYPE_ARM_V6:
3584 // v6 can run everything except xscale and v7
3585 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3586 throw "can't mix xscale and v6 code";
3587 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3588 return fCpuConstraint;
3590 case CPU_SUBTYPE_ARM_XSCALE:
3591 // xscale can run everything except v6 and v7
3592 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
3593 throw "can't mix xscale and v6 code";
3594 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3595 throw "can't mix xscale and v7 code";
3597 case CPU_SUBTYPE_ARM_V7:
3598 // v7 can run everything except xscale
3599 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3600 throw "can't mix xscale and v7 code";
3603 throw "Unhandled ARM cpu subtype!";
3608 template <typename A>
3609 uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
3611 // no cpu sub types for this architecture
3615 template <typename A>
3616 void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
3618 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
3619 // a matching provider name, add a by-name kDtraceTypeReference at probe site
3620 const char* dollar = strchr(providerName, '$');
3621 if ( dollar != NULL ) {
3622 int providerNameLen = dollar-providerName+1;
3623 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
3624 const char* typeDollar = strchr(*it, '$');
3625 if ( typeDollar != NULL ) {
3626 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
3627 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
3636 void Reader<x86_64>::validSectionType(uint8_t type)
3639 case S_SYMBOL_STUBS:
3640 throw "symbol_stub sections not valid in x86_64 object files";
3641 case S_LAZY_SYMBOL_POINTERS:
3642 throw "lazy pointer sections not valid in x86_64 object files";
3643 case S_NON_LAZY_SYMBOL_POINTERS:
3644 throw "non lazy pointer sections not valid in x86_64 object files";
3648 template <typename A>
3649 void Reader<A>::validSectionType(uint8_t type)
3653 template <typename A>
3654 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
3656 if ( fDebugInfo == kDebugInfoDwarf ) {
3657 *dir = fDwarfTranslationUnitDir;
3658 *name = fDwarfTranslationUnitFile;
3659 return (fDwarfTranslationUnitFile != NULL);
3664 template <typename A>
3665 BaseAtom* Reader<A>::findAtomByName(const char* name)
3667 // first search the more important atoms
3668 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
3669 const char* atomName = it->second->getName();
3670 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3674 // try all atoms, because this might have been a tentative definition
3675 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
3676 BaseAtom* atom = (BaseAtom*)(*it);
3677 const char* atomName = atom->getName();
3678 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3685 template <typename A>
3686 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
3688 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
3691 template <typename A>
3692 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
3694 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
3697 template <typename A>
3698 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
3700 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
3703 template <typename A>
3704 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
3706 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
3709 template <typename A>
3710 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
3712 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3715 template <typename A>
3716 BaseAtom* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
3718 // add a group subordinate reference from function atom to its eh frame atom
3719 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
3720 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
3721 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
3722 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3723 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3724 new Reference<A>(A::kGroupSubordinate, funcAtom, ehAtom);
3725 return (BaseAtom*)funcAtom;
3730 Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
3732 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3733 // instead check scope of target
3734 BaseAtom* target = findAtomByName(toName);
3735 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
3736 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
3738 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3742 Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
3744 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3745 // instead check scope of target
3746 const char* symbolName = &fStrings[toSymbol->n_strx()];
3747 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) {
3748 AtomAndOffset targetAO = findAtomAndOffsetForSection(toSymbol->n_value(), toSymbol->n_sect());
3749 targetAO.offset = toOffset;
3750 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), targetAO);
3753 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
3758 BaseAtom* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
3760 // add a group subordinate reference from function atom to its eh frame atom
3761 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
3762 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
3763 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
3764 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
3765 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3766 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
3767 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
3768 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3769 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3770 new Reference<x86_64>(x86_64::kGroupSubordinate, funcAtom, ehAtom);
3771 return (BaseAtom*)funcAtom;
3774 warning("can't find matching function for eh symbol %s", ehName);
3778 template <typename A>
3779 AtomAndOffset Reader<A>::findAtomAndOffsetForSection(pint_t addr, unsigned int expectedSectionIndex)
3781 AtomAndOffset ao = findAtomAndOffset(addr);
3782 if ( ao.atom != NULL ) {
3783 if ( ((BaseAtom*)(ao.atom))->getSectionIndex() == expectedSectionIndex )
3786 // The atom found is not in the section expected.
3787 // This probably means there was a label at the end of the section.
3788 // Do a slow sequential lookup
3789 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); ++it) {
3790 BaseAtom* atom = *it;
3791 if ( atom->getSectionIndex() == expectedSectionIndex ) {
3792 pint_t objAddr = atom->getObjectAddress();
3793 if ( (objAddr == addr) || ((objAddr < addr) && (objAddr+atom->getSize() > addr)) ) {
3794 return AtomAndOffset(atom, addr-atom->getObjectAddress());
3798 // no atom found that matched section, fall back to one orginally found
3802 template <typename A>
3803 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
3805 // STL has no built-in for "find largest key that is same or less than"
3806 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
3807 // if no atoms up to this address return none found
3808 if ( it == fAddrToAtom.begin() )
3809 return AtomAndOffset(NULL);
3810 // otherwise upper_bound gets us next key, so we back up one
3812 AtomAndOffset result;
3813 result.atom = it->second;
3814 result.offset = addr - it->first;
3815 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
3816 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
3820 // "scattered" relocations enable you to offset into an atom past the end of it
3821 // baseAddr is the address of the target atom,
3822 // realAddr is the points into it
3823 template <typename A>
3824 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
3826 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
3827 if ( it != fAddrToAtom.end() ) {
3828 AtomAndOffset result;
3829 result.atom = it->second;
3830 result.offset = realAddr - it->first;
3831 if ( result.atom->isThumb() )
3832 result.offset &= -2;
3833 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
3836 // getting here means we have a scattered relocation to an address without a label
3837 // so, find the atom that contains the baseAddr, and offset from that to the readAddr
3838 AtomAndOffset result = findAtomAndOffset(baseAddr);
3839 result.offset += (realAddr-baseAddr);
3844 /* Skip over a LEB128 value (signed or unsigned). */
3846 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
3848 while (*offset != end && **offset >= 0x80)
3854 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
3855 or error. On overflow, skip past the rest of the uleb128. */
3857 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
3859 uint64_t result = 0;
3866 return (uint64_t) -1;
3868 b = **offset & 0x7f;
3870 if (bit >= 64 || b << bit >> bit != b)
3871 result = (uint64_t) -1;
3873 result |= b << bit, bit += 7;
3874 } while (*(*offset)++ >= 0x80);
3879 /* Skip over a DWARF attribute of form FORM. */
3880 template <typename A>
3881 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
3882 uint8_t addr_size, bool dwarf64)
3892 case DW_FORM_block2:
3893 if (end - *offset < 2)
3895 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
3898 case DW_FORM_block4:
3899 if (end - *offset < 4)
3901 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
3919 case DW_FORM_string:
3920 while (*offset != end && **offset)
3929 sz = read_uleb128 (offset, end);
3932 case DW_FORM_block1:
3940 case DW_FORM_ref_udata:
3941 skip_leb128 (offset, end);
3945 case DW_FORM_ref_addr:
3952 if (end - *offset < sz)
3958 template <typename A>
3959 const char* Reader<A>::getDwarfString(uint64_t form, const uint8_t* p)
3961 if ( form == DW_FORM_string )
3962 return (const char*)p;
3963 else if ( form == DW_FORM_strp ) {
3964 uint32_t offset = E::get32(*((uint32_t*)p));
3965 const char* dwarfStrings = (char*)(fHeader) + fDwarfDebugStringSect->offset();
3966 if ( offset > fDwarfDebugStringSect->size() ) {
3967 warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->getPath());
3970 return &dwarfStrings[offset];
3972 warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->getPath());
3977 // Look at the compilation unit DIE and determine
3978 // its NAME, compilation directory (in COMP_DIR) and its
3979 // line number information offset (in STMT_LIST). NAME and COMP_DIR
3980 // may be NULL (especially COMP_DIR) if they are not in the .o file;
3981 // STMT_LIST will be (uint64_t) -1.
3983 // At present this assumes that there's only one compilation unit DIE.
3985 template <typename A>
3986 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
3987 uint64_t *stmt_list)
3989 const uint8_t * debug_info;
3990 const uint8_t * debug_abbrev;
3993 const uint8_t * end;
3994 const uint8_t * enda;
3997 uint64_t abbrev_base;
3999 uint8_t address_size;
4004 *stmt_list = (uint64_t) -1;
4006 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
4009 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
4010 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
4013 if (fDwarfDebugInfoSect->size() < 12)
4014 /* Too small to be a real debug_info section. */
4016 sz = A::P::E::get32(*(uint32_t*)di);
4018 dwarf64 = sz == 0xffffffff;
4020 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
4021 else if (sz > 0xffffff00)
4022 /* Unknown dwarf format. */
4025 /* Verify claimed size. */
4026 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
4029 vers = A::P::E::get16(*(uint16_t*)di);
4030 if (vers < 2 || vers > 3)
4031 /* DWARF version wrong for this code.
4032 Chances are we could continue anyway, but we don't know for sure. */
4036 /* Find the debug_abbrev section. */
4037 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
4038 di += dwarf64 ? 8 : 4;
4040 if (abbrev_base > fDwarfDebugAbbrevSect->size())
4042 da = debug_abbrev + abbrev_base;
4043 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
4045 address_size = *di++;
4047 /* Find the abbrev number we're looking for. */
4049 abbrev = read_uleb128 (&di, end);
4050 if (abbrev == (uint64_t) -1)
4053 /* Skip through the debug_abbrev section looking for that abbrev. */
4056 uint64_t this_abbrev = read_uleb128 (&da, enda);
4059 if (this_abbrev == abbrev)
4060 /* This is almost always taken. */
4062 skip_leb128 (&da, enda); /* Skip the tag. */
4065 da++; /* Skip the DW_CHILDREN_* value. */
4068 attr = read_uleb128 (&da, enda);
4069 skip_leb128 (&da, enda);
4070 } while (attr != 0 && attr != (uint64_t) -1);
4075 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
4076 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
4080 da++; /* Skip the DW_CHILDREN_* value. */
4082 /* Now, go through the DIE looking for DW_AT_name,
4083 DW_AT_comp_dir, and DW_AT_stmt_list. */
4086 uint64_t attr = read_uleb128 (&da, enda);
4087 uint64_t form = read_uleb128 (&da, enda);
4089 if (attr == (uint64_t) -1)
4094 if (form == DW_FORM_indirect)
4095 form = read_uleb128 (&di, end);
4097 if (attr == DW_AT_name)
4098 *name = getDwarfString(form, di);
4099 else if (attr == DW_AT_comp_dir)
4100 *comp_dir = getDwarfString(form, di);
4101 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
4102 *stmt_list = A::P::E::get32(*(uint32_t*)di);
4103 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
4104 *stmt_list = A::P::E::get64(*(uint64_t*)di);
4105 if (! skip_form (&di, end, form, address_size, dwarf64))
4110 template <typename A>
4111 const char* Reader<A>::assureFullPath(const char* path)
4113 if ( path[0] == '/' )
4115 char cwdbuff[MAXPATHLEN];
4116 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
4118 asprintf(&result, "%s/%s", cwdbuff, path);
4119 if ( result != NULL )
4128 // To implement architecture xxx, you must write template specializations for the following six methods:
4129 // Reader<xxx>::validFile()
4130 // Reader<xxx>::addRelocReference()
4131 // Reference<xxx>::getDescription()
4137 bool Reader<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4139 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4140 if ( header->magic() != MH_MAGIC )
4142 if ( header->cputype() != CPU_TYPE_POWERPC )
4144 if ( header->filetype() != MH_OBJECT )
4150 bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4152 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4153 if ( header->magic() != MH_MAGIC_64 )
4155 if ( header->cputype() != CPU_TYPE_POWERPC64 )
4157 if ( header->filetype() != MH_OBJECT )
4163 bool Reader<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4165 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4166 if ( header->magic() != MH_MAGIC )
4168 if ( header->cputype() != CPU_TYPE_I386 )
4170 if ( header->filetype() != MH_OBJECT )
4176 bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4178 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4179 if ( header->magic() != MH_MAGIC_64 )
4181 if ( header->cputype() != CPU_TYPE_X86_64 )
4183 if ( header->filetype() != MH_OBJECT )
4189 bool Reader<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
4191 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4192 if ( header->magic() != MH_MAGIC )
4194 if ( header->cputype() != CPU_TYPE_ARM )
4196 if ( header->filetype() != MH_OBJECT )
4198 if ( subtypeMustMatch && ((cpu_subtype_t)header->cpusubtype() != subtype) )
4205 const char* Reader<ppc>::fileKind(const uint8_t* fileContent)
4207 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4208 if ( header->magic() != MH_MAGIC )
4210 if ( header->cputype() != CPU_TYPE_POWERPC )
4212 switch ( header->cpusubtype() ) {
4213 case CPU_SUBTYPE_POWERPC_750:
4215 case CPU_SUBTYPE_POWERPC_7400:
4217 case CPU_SUBTYPE_POWERPC_7450:
4219 case CPU_SUBTYPE_POWERPC_970:
4221 case CPU_SUBTYPE_POWERPC_ALL:
4228 const char* Reader<ppc64>::fileKind(const uint8_t* fileContent)
4230 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4231 if ( header->magic() != MH_MAGIC )
4233 if ( header->cputype() != CPU_TYPE_POWERPC64 )
4239 const char* Reader<x86>::fileKind(const uint8_t* fileContent)
4241 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4242 if ( header->magic() != MH_MAGIC )
4244 if ( header->cputype() != CPU_TYPE_I386 )
4250 const char* Reader<x86_64>::fileKind(const uint8_t* fileContent)
4252 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4253 if ( header->magic() != MH_MAGIC )
4255 if ( header->cputype() != CPU_TYPE_X86_64 )
4261 const char* Reader<arm>::fileKind(const uint8_t* fileContent)
4263 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4264 if ( header->magic() != MH_MAGIC )
4266 if ( header->cputype() != CPU_TYPE_ARM )
4268 switch ( header->cpusubtype() ) {
4269 case CPU_SUBTYPE_ARM_V4T:
4271 case CPU_SUBTYPE_ARM_V5TEJ:
4273 case CPU_SUBTYPE_ARM_V6:
4275 case CPU_SUBTYPE_ARM_V7:
4282 template <typename A>
4283 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
4285 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
4289 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
4291 return addRelocReference_powerpc(sect, reloc);
4295 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
4297 return addRelocReference_powerpc(sect, reloc);
4302 // ppc and ppc64 both use the same relocations, so process them in one common routine
4304 template <typename A>
4305 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
4306 const macho_relocation_info<typename A::P>* reloc)
4311 int32_t displacement = 0;
4312 uint32_t instruction = 0;
4313 uint32_t offsetInTarget;
4315 bool result = false;
4316 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4317 const macho_relocation_info<P>* nextReloc = &reloc[1];
4318 const char* targetName = NULL;
4319 bool weakImport = false;
4320 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4321 if ( reloc->r_type() != PPC_RELOC_PAIR )
4322 instruction = BigEndian::get32(*fixUpPtr);
4323 srcAddr = sect->addr() + reloc->r_address();
4324 if ( reloc->r_extern() ) {
4325 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4326 targetName = &fStrings[targetSymbol->n_strx()];
4327 weakImport = this->isWeakImportSymbol(targetSymbol);
4329 switch ( reloc->r_type() ) {
4330 case PPC_RELOC_BR24:
4332 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4333 displacement = (instruction & 0x03FFFFFC);
4334 if ( (displacement & 0x02000000) != 0 )
4335 displacement |= 0xFC000000;
4338 printf("bad instruction for BR24 reloc");
4340 if ( reloc->r_extern() ) {
4341 offsetInTarget = srcAddr + displacement;
4342 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4343 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4344 addDtraceExtraInfos(srcAddr, &targetName[16]);
4346 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4347 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4348 addDtraceExtraInfos(srcAddr, &targetName[20]);
4350 else if ( weakImport )
4351 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
4353 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
4356 dstAddr = srcAddr + displacement;
4357 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
4358 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
4359 targetName = atom->getName();
4360 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4361 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4362 addDtraceExtraInfos(srcAddr, &targetName[16]);
4364 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4365 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4366 addDtraceExtraInfos(srcAddr, &targetName[20]);
4368 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4369 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
4370 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
4372 makeReference(A::kBranch24, srcAddr, dstAddr);
4376 case PPC_RELOC_BR14:
4378 displacement = (instruction & 0x0000FFFC);
4379 if ( (displacement & 0x00008000) != 0 )
4380 displacement |= 0xFFFF0000;
4381 if ( reloc->r_extern() ) {
4382 offsetInTarget = srcAddr + displacement;
4383 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
4386 dstAddr = srcAddr + displacement;
4387 makeReference(A::kBranch14, srcAddr, dstAddr);
4391 case PPC_RELOC_PAIR:
4392 // skip, processed by a previous look ahead
4394 case PPC_RELOC_LO16:
4396 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4397 throw "PPC_RELOC_LO16 missing following pair";
4400 lowBits = (instruction & 0xFFFF);
4401 if ( reloc->r_extern() ) {
4402 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4403 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
4406 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4407 if ( reloc->r_symbolnum() == R_ABS ) {
4408 // find absolute symbol that corresponds to pointerValue
4409 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4410 if ( pos != fAddrToAbsoluteAtom.end() )
4411 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
4413 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4416 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4421 case PPC_RELOC_LO14:
4423 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4424 throw "PPC_RELOC_LO14 missing following pair";
4427 lowBits = (instruction & 0xFFFC);
4428 if ( reloc->r_extern() ) {
4429 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4430 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
4433 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4434 if ( reloc->r_symbolnum() == R_ABS ) {
4435 // find absolute symbol that corresponds to pointerValue
4436 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4437 if ( pos != fAddrToAbsoluteAtom.end() )
4438 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
4440 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4443 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4448 case PPC_RELOC_HI16:
4450 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4451 throw "PPC_RELOC_HI16 missing following pair";
4454 if ( reloc->r_extern() ) {
4455 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4456 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
4459 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4460 if ( reloc->r_symbolnum() == R_ABS ) {
4461 // find absolute symbol that corresponds to pointerValue
4462 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4463 if ( pos != fAddrToAbsoluteAtom.end() )
4464 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
4466 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4469 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4474 case PPC_RELOC_HA16:
4476 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4477 throw "PPC_RELOC_HA16 missing following pair";
4480 lowBits = (nextReloc->r_address() & 0x0000FFFF);
4481 if ( reloc->r_extern() ) {
4482 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4483 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
4486 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4487 if ( reloc->r_symbolnum() == R_ABS ) {
4488 // find absolute symbol that corresponds to pointerValue
4489 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4490 if ( pos != fAddrToAbsoluteAtom.end() )
4491 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
4493 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4496 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4501 case PPC_RELOC_VANILLA:
4503 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
4504 if ( reloc->r_extern() ) {
4506 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
4508 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
4511 new Reference<A>(A::kPointer, findAtomAndOffset(srcAddr), findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()));
4515 case PPC_RELOC_JBSR:
4516 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
4517 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4518 throw "PPC_RELOC_JBSR missing following pair";
4520 if ( !fHasLongBranchStubs )
4521 warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath);
4522 fHasLongBranchStubs = true;
4524 if ( reloc->r_extern() ) {
4525 throw "PPC_RELOC_JBSR should not be using an external relocation";
4527 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
4528 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4529 displacement = (instruction & 0x03FFFFFC);
4530 if ( (displacement & 0x02000000) != 0 )
4531 displacement |= 0xFC000000;
4534 fprintf(stderr, "bad instruction for BR24 reloc");
4538 warning("unknown relocation type %d", reloc->r_type());
4542 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4543 srcAddr = sect->addr() + sreloc->r_address();
4544 dstAddr = sreloc->r_value();
4545 uint32_t betterDstAddr;
4546 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4547 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4548 const macho_relocation_info<P>* nextReloc = &reloc[1];
4549 // file format allows pair to be scattered or not
4550 bool nextRelocIsPair = false;
4551 uint32_t nextRelocAddress = 0;
4552 uint32_t nextRelocValue = 0;
4553 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4554 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
4555 nextRelocIsPair = true;
4556 nextRelocAddress = nextReloc->r_address();
4561 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
4562 nextRelocIsPair = true;
4563 nextRelocAddress = nextSReloc->r_address();
4564 nextRelocValue = nextSReloc->r_value();
4568 switch (sreloc->r_type()) {
4569 case PPC_RELOC_VANILLA:
4571 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
4572 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
4573 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4574 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
4577 case PPC_RELOC_BR14:
4579 instruction = BigEndian::get32(*fixUpPtr);
4580 displacement = (instruction & 0x0000FFFC);
4581 if ( (displacement & 0x00008000) != 0 )
4582 displacement |= 0xFFFF0000;
4583 betterDstAddr = srcAddr+displacement;
4584 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
4585 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
4588 case PPC_RELOC_BR24:
4590 instruction = BigEndian::get32(*fixUpPtr);
4591 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4592 displacement = (instruction & 0x03FFFFFC);
4593 if ( (displacement & 0x02000000) != 0 )
4594 displacement |= 0xFC000000;
4595 betterDstAddr = srcAddr+displacement;
4596 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
4600 case PPC_RELOC_LO16_SECTDIFF:
4602 if ( ! nextRelocIsPair ) {
4603 throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
4605 instruction = BigEndian::get32(*fixUpPtr);
4606 lowBits = (instruction & 0xFFFF);
4607 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4608 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4611 case PPC_RELOC_LO14_SECTDIFF:
4613 if ( ! nextRelocIsPair ) {
4614 throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
4616 instruction = BigEndian::get32(*fixUpPtr);
4617 lowBits = (instruction & 0xFFFC);
4618 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4619 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4622 case PPC_RELOC_HA16_SECTDIFF:
4624 if ( ! nextRelocIsPair ) {
4625 throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
4627 instruction = BigEndian::get32(*fixUpPtr);
4628 lowBits = (nextRelocAddress & 0x0000FFFF);
4629 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4630 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4633 case PPC_RELOC_LO14:
4635 if ( ! nextRelocIsPair ) {
4636 throw "PPC_RELOC_LO14 missing following pair";
4638 instruction = BigEndian::get32(*fixUpPtr);
4639 lowBits = (instruction & 0xFFFC);
4640 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4641 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
4644 case PPC_RELOC_LO16:
4646 if ( ! nextRelocIsPair ) {
4647 throw "PPC_RELOC_LO16 missing following pair";
4649 instruction = BigEndian::get32(*fixUpPtr);
4650 lowBits = (instruction & 0xFFFF);
4651 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4652 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
4655 case PPC_RELOC_HA16:
4657 if ( ! nextRelocIsPair ) {
4658 throw "PPC_RELOC_HA16 missing following pair";
4660 instruction = BigEndian::get32(*fixUpPtr);
4661 lowBits = (nextRelocAddress & 0xFFFF);
4662 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
4663 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
4666 case PPC_RELOC_HI16:
4668 if ( ! nextRelocIsPair ) {
4669 throw "PPC_RELOC_HI16 missing following pair";
4671 instruction = BigEndian::get32(*fixUpPtr);
4672 lowBits = (nextRelocAddress & 0xFFFF);
4673 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
4674 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
4677 case PPC_RELOC_SECTDIFF:
4678 case PPC_RELOC_LOCAL_SECTDIFF:
4680 if ( ! nextRelocIsPair ) {
4681 throw "PPC_RELOC_SECTDIFF missing following pair";
4683 Kinds kind = A::kPointerDiff32;;
4684 uint32_t contentAddr = 0;
4685 switch ( sreloc->r_length() ) {
4687 throw "bad diff relocations r_length (0) for ppc architecture";
4689 kind = A::kPointerDiff16;
4690 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
4693 kind = A::kPointerDiff32;
4694 contentAddr = BigEndian::get32(*fixUpPtr);
4697 kind = A::kPointerDiff64;
4698 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
4701 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4702 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4703 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4704 // check for addend encoded in the section content
4705 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4706 // dstAddr, nextRelocValue, contentAddr);
4707 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4708 if ( toao.atom == srcao.atom )
4709 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4710 else if ( fromao.atom == srcao.atom )
4711 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4713 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4715 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4716 // srcao.atom->getDisplayName(), srcao.offset,
4717 // fromao.atom->getDisplayName(), fromao.offset,
4718 // toao.atom->getDisplayName(), toao.offset);
4719 new Reference<A>(kind, srcao, fromao, toao);
4722 case PPC_RELOC_PAIR:
4724 case PPC_RELOC_HI16_SECTDIFF:
4725 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
4728 warning("unknown scattered relocation type %d", sreloc->r_type());
4736 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
4741 bool result = false;
4742 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4743 srcAddr = sect->addr() + reloc->r_address();
4744 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4745 switch ( reloc->r_type() ) {
4746 case GENERIC_RELOC_VANILLA:
4748 x86::ReferenceKinds kind = x86::kPointer;
4749 uint32_t pointerValue = E::get32(*fixUpPtr);
4750 if ( reloc->r_pcrel() ) {
4751 switch( reloc->r_length() ) {
4753 kind = x86::kPCRel8;
4754 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
4757 kind = x86::kPCRel16;
4758 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
4761 kind = x86::kPCRel32;
4762 pointerValue += srcAddr + sizeof(uint32_t);
4765 throw "bad pc-rel vanilla relocation length";
4768 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
4769 kind = x86::kAbsolute32;
4770 if ( reloc->r_length() != 2 )
4771 throw "bad vanilla relocation length";
4774 kind = x86::kPointer;
4775 if ( reloc->r_length() != 2 )
4776 throw "bad vanilla relocation length";
4778 if ( reloc->r_extern() ) {
4779 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4780 if ( this->isWeakImportSymbol(targetSymbol) ) {
4781 if ( reloc->r_pcrel() )
4782 kind = x86::kPCRel32WeakImport;
4784 kind = x86::kPointerWeakImport;
4786 const char* targetName = &fStrings[targetSymbol->n_strx()];
4787 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4788 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4789 addDtraceExtraInfos(srcAddr, &targetName[16]);
4791 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4792 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4793 addDtraceExtraInfos(srcAddr, &targetName[20]);
4796 makeByNameReference(kind, srcAddr, targetName, pointerValue);
4799 AtomAndOffset targetAO = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
4800 const char* targetName = targetAO.atom->getName();
4801 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4802 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4803 addDtraceExtraInfos(srcAddr, &targetName[16]);
4805 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4806 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4807 addDtraceExtraInfos(srcAddr, &targetName[20]);
4809 // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol
4810 else if ( reloc->r_pcrel() && (targetAO.atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4811 && ((AnonymousAtom<x86>*)targetAO.atom)->isWeakImportStub() )
4812 new Reference<x86>(x86::kPCRel32WeakImport, findAtomAndOffset(srcAddr), targetAO);
4813 else if ( reloc->r_symbolnum() != R_ABS )
4814 new Reference<x86>(kind, findAtomAndOffset(srcAddr), targetAO);
4816 // find absolute symbol that corresponds to pointerValue
4817 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
4818 if ( pos != fAddrToAbsoluteAtom.end() )
4819 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
4821 throwf("R_ABS reloc but no absolute symbol at target address");
4827 warning("unknown relocation type %d", reloc->r_type());
4831 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4832 srcAddr = sect->addr() + sreloc->r_address();
4833 dstAddr = sreloc->r_value();
4834 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4835 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4836 const macho_relocation_info<P>* nextReloc = &reloc[1];
4837 pint_t betterDstAddr;
4838 // file format allows pair to be scattered or not
4839 bool nextRelocIsPair = false;
4840 uint32_t nextRelocAddress = 0;
4841 uint32_t nextRelocValue = 0;
4842 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4843 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
4844 nextRelocIsPair = true;
4845 nextRelocAddress = nextReloc->r_address();
4850 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
4851 nextRelocIsPair = true;
4852 nextRelocAddress = nextSReloc->r_address();
4853 nextRelocValue = nextSReloc->r_value();
4856 switch (sreloc->r_type()) {
4857 case GENERIC_RELOC_VANILLA:
4858 betterDstAddr = LittleEndian::get32(*fixUpPtr);
4859 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
4860 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4861 if ( sreloc->r_pcrel() ) {
4862 switch ( sreloc->r_length() ) {
4864 betterDstAddr += srcAddr + 4;
4865 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
4868 betterDstAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)) + srcAddr + 2;
4869 makeReferenceWithToBase(x86::kPCRel16, srcAddr, betterDstAddr, dstAddr);
4872 betterDstAddr = *((uint8_t*)fixUpPtr) + srcAddr + 1;
4873 makeReferenceWithToBase(x86::kPCRel8, srcAddr, betterDstAddr, dstAddr);
4876 throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc");
4881 if ( sreloc->r_length() != 2 )
4882 throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
4883 if ( strcmp(sect->segname(), "__TEXT") == 0 )
4884 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
4886 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
4889 case GENERIC_RELOC_SECTDIFF:
4890 case GENERIC_RELOC_LOCAL_SECTDIFF:
4892 if ( !nextRelocIsPair ) {
4893 throw "GENERIC_RELOC_SECTDIFF missing following pair";
4895 x86::ReferenceKinds kind = x86::kPointerDiff;
4896 uint32_t contentAddr = 0;
4897 switch ( sreloc->r_length() ) {
4900 throw "bad length for GENERIC_RELOC_SECTDIFF";
4902 kind = x86::kPointerDiff16;
4903 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
4906 kind = x86::kPointerDiff;
4907 contentAddr = LittleEndian::get32(*fixUpPtr);
4910 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4911 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4912 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4913 // check for addend encoded in the section content
4914 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4915 // dstAddr, nextRelocValue, contentAddr);
4916 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4917 if ( toao.atom == srcao.atom )
4918 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4919 else if ( fromao.atom == srcao.atom )
4920 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4922 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4924 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4925 // srcao.atom->getDisplayName(), srcao.offset,
4926 // fromao.atom->getDisplayName(), fromao.offset,
4927 // toao.atom->getDisplayName(), toao.offset);
4928 new Reference<x86>(kind, srcao, fromao, toao);
4931 case GENERIC_RELOC_PAIR:
4932 // do nothing, already used via a look ahead
4935 warning("unknown scattered relocation type %d", sreloc->r_type());
4942 bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
4945 uint64_t dstAddr = 0;
4948 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
4949 bool result = false;
4950 const macho_nlist<P>* targetSymbol = NULL;
4951 const char* targetName = NULL;
4952 srcAddr = sect->addr() + reloc->r_address();
4953 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4954 //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address());
4955 if ( reloc->r_extern() ) {
4956 targetSymbol = &fSymbols[reloc->r_symbolnum()];
4957 targetName = &fStrings[targetSymbol->n_strx()];
4959 switch ( reloc->r_type() ) {
4960 case X86_64_RELOC_UNSIGNED:
4961 if ( reloc->r_pcrel() )
4962 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
4963 switch ( reloc->r_length() ) {
4966 throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
4968 kind = x86_64::kPointer32;
4971 if ( reloc->r_extern() && isWeakImportSymbol(targetSymbol) )
4972 kind = x86_64::kPointerWeakImport;
4974 kind = x86_64::kPointer;
4977 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
4978 if ( reloc->r_extern() ) {
4979 makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
4982 makeReference(kind, srcAddr, dstAddr);
4983 // verify that dstAddr is in the section being targeted
4984 int sectNum = reloc->r_symbolnum();
4985 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
4986 const macho_section<P>* const targetSection = §ionsStart[sectNum-1];
4987 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
4988 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4989 srcAddr, sect->sectname(), targetSection->sectname());
4993 case X86_64_RELOC_SIGNED:
4994 case X86_64_RELOC_SIGNED_1:
4995 case X86_64_RELOC_SIGNED_2:
4996 case X86_64_RELOC_SIGNED_4:
4997 if ( ! reloc->r_pcrel() )
4998 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
4999 if ( reloc->r_length() != 2 )
5000 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
5001 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5002 if ( reloc->r_extern() ) {
5003 switch ( reloc->r_type() ) {
5004 case X86_64_RELOC_SIGNED:
5005 kind = x86_64::kPCRel32;
5006 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
5007 if ( addend == (uint64_t)(-1) ) {
5009 kind = x86_64::kPCRel32_1;
5011 else if ( addend == (uint64_t)(-2) ) {
5013 kind = x86_64::kPCRel32_2;
5015 else if ( addend == (uint64_t)(-4) ) {
5017 kind = x86_64::kPCRel32_4;
5020 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
5021 case X86_64_RELOC_SIGNED_1:
5022 kind = x86_64::kPCRel32_1;
5025 case X86_64_RELOC_SIGNED_2:
5026 kind = x86_64::kPCRel32_2;
5029 case X86_64_RELOC_SIGNED_4:
5030 kind = x86_64::kPCRel32_4;
5034 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
5037 uint64_t ripRelativeOffset = addend;
5038 switch ( reloc->r_type() ) {
5039 case X86_64_RELOC_SIGNED:
5040 dstAddr = srcAddr + 4 + ripRelativeOffset;
5041 kind = x86_64::kPCRel32;
5043 case X86_64_RELOC_SIGNED_1:
5044 dstAddr = srcAddr + 5 + ripRelativeOffset;
5045 kind = x86_64::kPCRel32_1;
5047 case X86_64_RELOC_SIGNED_2:
5048 dstAddr = srcAddr + 6 + ripRelativeOffset;
5049 kind = x86_64::kPCRel32_2;
5051 case X86_64_RELOC_SIGNED_4:
5052 dstAddr = srcAddr + 8 + ripRelativeOffset;
5053 kind = x86_64::kPCRel32_4;
5056 makeReference(kind, srcAddr, dstAddr);
5057 // verify that dstAddr is in the section being targeted
5058 int sectNum = reloc->r_symbolnum();
5059 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
5060 const macho_section<P>* const targetSection = §ionsStart[sectNum-1];
5061 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
5062 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
5063 srcAddr, sect->sectname(), targetSection->sectname());
5067 case X86_64_RELOC_BRANCH:
5068 if ( ! reloc->r_pcrel() )
5069 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
5070 if ( reloc->r_length() == 2 ) {
5071 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5072 if ( reloc->r_extern() ) {
5073 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5074 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
5075 addDtraceExtraInfos(srcAddr, &targetName[16]);
5077 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5078 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5079 addDtraceExtraInfos(srcAddr, &targetName[16]);
5081 else if ( isWeakImportSymbol(targetSymbol) )
5082 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
5084 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
5087 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
5090 else if ( reloc->r_length() == 0 ) {
5091 dstAddr = *((int8_t*)fixUpPtr);
5092 if ( reloc->r_extern() ) {
5093 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
5096 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
5100 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
5103 case X86_64_RELOC_GOT:
5104 if ( ! reloc->r_extern() )
5105 throw "not extern and X86_64_RELOC_GOT not supported";
5106 if ( ! reloc->r_pcrel() )
5107 throw "not pcrel and X86_64_RELOC_GOT not supported";
5108 if ( reloc->r_length() != 2 )
5109 throw "length != 2 and X86_64_RELOC_GOT not supported";
5110 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5111 if ( isWeakImportSymbol(targetSymbol) )
5112 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
5114 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
5116 case X86_64_RELOC_GOT_LOAD:
5117 if ( ! reloc->r_extern() )
5118 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
5119 if ( ! reloc->r_pcrel() )
5120 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
5121 if ( reloc->r_length() != 2 )
5122 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
5123 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5124 if ( isWeakImportSymbol(targetSymbol) )
5125 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
5127 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
5129 case X86_64_RELOC_SUBTRACTOR:
5131 if ( reloc->r_pcrel() )
5132 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
5133 if ( reloc->r_length() < 2 )
5134 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
5135 if ( !reloc->r_extern() )
5136 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
5137 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
5138 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
5139 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
5141 if ( nextReloc->r_pcrel() )
5142 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
5143 if ( nextReloc->r_length() != reloc->r_length() )
5144 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
5145 Reference<x86_64>* ref;
5146 bool negativeAddend;
5147 if ( reloc->r_length() == 2 ) {
5148 kind = x86_64::kPointerDiff32;
5149 dstAddr = E::get32(*fixUpPtr); // addend is in content
5150 negativeAddend = ((dstAddr & 0x80000000) != 0);
5153 kind = x86_64::kPointerDiff;
5154 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
5155 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
5157 AtomAndOffset inAtomAndOffset = this->findAtomAndOffset(srcAddr);
5158 ObjectFile::Atom* inAtom = inAtomAndOffset.atom;
5159 // create reference with "to" target
5160 if ( nextReloc->r_extern() ) {
5161 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
5162 const char* targetName = &fStrings[targetSymbol->n_strx()];
5163 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
5164 // if "to" is in this atom, change by-name to a direct reference
5165 if ( strcmp(targetName, inAtom->getName()) == 0 )
5166 ref->setTarget(*inAtom, 0);
5169 ref = makeReference(kind, srcAddr, dstAddr);
5171 // add in "from" target
5172 if ( reloc->r_extern() ) {
5173 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
5174 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
5175 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
5176 // from target is translation unit scoped, so use a direct reference
5177 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
5179 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
5180 // if "from" is in this atom, change by-name to a direct reference
5181 ref->setFromTarget(*inAtom);
5184 // some non-static other atom
5185 ref->setFromTargetName(fromTargetName);
5189 throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0";
5191 // addend goes in from side iff negative
5192 if ( negativeAddend )
5193 ref->setFromTargetOffset(-dstAddr);
5195 ref->setToTargetOffset(dstAddr);
5199 warning("unknown relocation type %d", reloc->r_type());
5205 /// Reader<arm>::addRelocReference -
5206 /// turns arm relocation entries into references. Returns true if the next
5207 /// relocation should be skipped, false otherwise.
5209 bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
5210 const macho_relocation_info<arm::P>* reloc)
5212 uint32_t * fixUpPtr;
5213 int32_t displacement;
5214 uint32_t instruction = 0;
5215 bool result = false;
5218 uint32_t pointerValue;
5219 arm::ReferenceKinds kind = arm::kNoFixUp;
5221 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
5222 // non-scattered relocation
5223 const char* targetName = NULL;
5224 bool weakImport = false;
5226 srcAddr = sect->addr() + reloc->r_address();
5227 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
5228 if ( reloc->r_type() != ARM_RELOC_PAIR )
5229 instruction = LittleEndian::get32(*fixUpPtr);
5231 if ( reloc->r_extern() ) {
5232 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
5233 targetName = &fStrings[targetSymbol->n_strx()];
5234 weakImport = this->isWeakImportSymbol(targetSymbol);
5237 switch ( reloc->r_type() ) {
5238 case ARM_RELOC_BR24:
5239 // Sign-extend displacement
5240 displacement = (instruction & 0x00FFFFFF) << 2;
5241 if ( (displacement & 0x02000000) != 0 )
5242 displacement |= 0xFC000000;
5243 // The pc added will be +8 from the pc
5245 // If this is BLX add H << 1
5246 if ((instruction & 0xFE000000) == 0xFA000000)
5247 displacement += ((instruction & 0x01000000) >> 23);
5249 if ( reloc->r_extern() ) {
5250 uint32_t offsetInTarget = srcAddr + displacement;
5251 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5252 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5253 addDtraceExtraInfos(srcAddr, &targetName[16]);
5255 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5256 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5257 addDtraceExtraInfos(srcAddr, &targetName[20]);
5259 else if ( weakImport )
5260 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
5262 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
5265 dstAddr = srcAddr + displacement;
5266 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5267 // check for dtrace probes and weak_import stubs
5268 const char* targetName = atom->getName();
5269 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5270 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5271 addDtraceExtraInfos(srcAddr, &targetName[16]);
5273 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5274 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5275 addDtraceExtraInfos(srcAddr, &targetName[20]);
5277 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5278 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5279 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
5280 else if ( reloc->r_symbolnum() != R_ABS )
5281 makeReference(arm::kBranch24, srcAddr, dstAddr);
5283 // find absolute symbol that corresponds to pointerValue
5284 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5285 if ( pos != fAddrToAbsoluteAtom.end() )
5286 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
5288 throwf("R_ABS reloc but no absolute symbol at target address");
5293 case ARM_THUMB_RELOC_BR22:
5294 // thumb2 added two more bits to displacement, complicating the displacement decoding
5296 uint32_t s = (instruction >> 10) & 0x1;
5297 uint32_t j1 = (instruction >> 29) & 0x1;
5298 uint32_t j2 = (instruction >> 27) & 0x1;
5299 uint32_t imm10 = instruction & 0x3FF;
5300 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5301 uint32_t i1 = (j1 == s);
5302 uint32_t i2 = (j2 == s);
5303 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5307 displacement = sdis;
5309 // The pc added will be +4 from the pc
5311 // If the instruction was blx, force the low 2 bits to be clear
5312 dstAddr = srcAddr + displacement;
5313 if ((instruction & 0xF8000000) == 0xE8000000)
5314 dstAddr &= 0xFFFFFFFC;
5316 if ( reloc->r_extern() ) {
5317 uint32_t offsetInTarget = dstAddr;
5318 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5319 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5320 addDtraceExtraInfos(srcAddr, &targetName[16]);
5322 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5323 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5324 addDtraceExtraInfos(srcAddr, &targetName[20]);
5326 else if ( weakImport )
5327 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
5329 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
5332 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5333 // check for dtrace probes and weak_import stubs
5334 const char* targetName = atom->getName();
5335 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5336 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5337 addDtraceExtraInfos(srcAddr, &targetName[16]);
5339 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5340 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5341 addDtraceExtraInfos(srcAddr, &targetName[20]);
5343 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5344 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5345 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
5346 else if ( reloc->r_symbolnum() != R_ABS )
5347 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
5349 // find absolute symbol that corresponds to pointerValue
5350 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5351 if ( pos != fAddrToAbsoluteAtom.end() )
5352 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
5354 throwf("R_ABS reloc but no absolute symbol at target address");
5359 case ARM_RELOC_VANILLA:
5360 if ( reloc->r_length() != 2 )
5361 throw "bad length for ARM_RELOC_VANILLA";
5363 pointerValue = instruction;
5364 kind = arm::kPointer;
5365 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5366 kind = arm::kReadOnlyPointer;
5368 kind = arm::kPointerWeakImport;
5369 if ( reloc->r_extern() ) {
5370 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
5371 if ( (targetSymbol->n_desc() & N_ARM_THUMB_DEF) && (pointerValue == 1) )
5373 makeByNameReference(kind, srcAddr, targetName, pointerValue);
5376 AtomAndOffset at = findAtomAndOffset(srcAddr);
5377 AtomAndOffset to = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
5378 if ( to.atom->isThumb() )
5380 new Reference<arm>(kind, at, to);
5384 case ARM_THUMB_32BIT_BRANCH:
5385 // ignore old unnecessary relocs
5389 warning("unexpected relocation type %u", reloc->r_type());
5394 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
5395 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
5397 srcAddr = sect->addr() + sreloc->r_address();
5398 dstAddr = sreloc->r_value();
5399 uint32_t betterDstAddr;
5400 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
5401 instruction = LittleEndian::get32(*fixUpPtr);
5403 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
5404 // relocation types, and it is an error to see one otherwise.
5405 bool nextRelocIsPair = false;
5406 uint32_t nextRelocAddress = 0;
5407 uint32_t nextRelocValue = 0;
5408 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
5409 nextRelocIsPair = true;
5410 nextRelocAddress = nextSReloc->r_address();
5411 nextRelocValue = nextSReloc->r_value();
5415 switch (sreloc->r_type()) {
5416 case ARM_RELOC_VANILLA:
5417 if ( sreloc->r_length() != 2 )
5418 throw "bad length for ARM_RELOC_VANILLA";
5420 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
5421 betterDstAddr = LittleEndian::get32(*fixUpPtr);
5422 kind = arm::kPointer;
5423 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5424 kind = arm::kReadOnlyPointer;
5425 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
5426 makeReferenceWithToBase(kind, srcAddr, betterDstAddr, dstAddr);
5429 case ARM_RELOC_BR24:
5430 // Sign-extend displacement
5431 displacement = (instruction & 0x00FFFFFF) << 2;
5432 if ( (displacement & 0x02000000) != 0 )
5433 displacement |= 0xFC000000;
5434 // The pc added will be +8 from the pc
5436 // If this is BLX add H << 1
5437 if ((instruction & 0xFE000000) == 0xFA000000)
5438 displacement += ((instruction & 0x01000000) >> 23);
5439 betterDstAddr = srcAddr+displacement;
5440 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
5443 case ARM_THUMB_RELOC_BR22:
5444 // thumb2 added two more bits to displacement, complicating the displacement decoding
5446 uint32_t s = (instruction >> 10) & 0x1;
5447 uint32_t j1 = (instruction >> 29) & 0x1;
5448 uint32_t j2 = (instruction >> 27) & 0x1;
5449 uint32_t imm10 = instruction & 0x3FF;
5450 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5451 uint32_t i1 = (j1 == s);
5452 uint32_t i2 = (j2 == s);
5453 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5457 displacement = sdis;
5459 // The pc added will be +4 from the pc
5461 betterDstAddr = srcAddr+displacement;
5462 // If the instruction was blx, force the low 2 bits to be clear
5463 if ((instruction & 0xF8000000) == 0xE8000000)
5464 betterDstAddr &= 0xFFFFFFFC;
5465 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
5468 case ARM_RELOC_SECTDIFF:
5469 case ARM_RELOC_LOCAL_SECTDIFF:
5470 if ( !nextRelocIsPair ) {
5471 throw "ARM_RELOC_SECTDIFF missing following pair";
5473 if ( sreloc->r_length() != 2 )
5474 throw "bad length for ARM_RELOC_SECTDIFF";
5476 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
5477 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
5478 AtomAndOffset toao = findAtomAndOffset(dstAddr);
5479 // check for addend encoded in the section content
5480 pointerValue = LittleEndian::get32(*fixUpPtr);
5481 addend = pointerValue - (dstAddr - nextRelocValue);
5482 if ( toao.atom->isThumb() && (addend & 1) )
5483 addend &= -2; // remove thumb bit
5484 if ( (dstAddr - nextRelocValue) != pointerValue ) {
5485 if ( fromao.atom == srcao.atom ) {
5486 if ( ((const macho_section<P>*)(((BaseAtom*)(srcao.atom))->getSectionRecord()))->flags() & S_ATTR_PURE_INSTRUCTIONS ) {
5487 int pcBaseOffset = srcao.atom->isThumb() ? 4 : 8;
5488 if ( addend == -pcBaseOffset ) {
5489 fromao.offset -= addend;
5492 toao.offset += addend;
5496 toao.offset += addend;
5499 else if ( toao.atom == srcao.atom )
5500 toao.offset += addend;
5502 fromao.offset -= addend;
5504 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
5509 warning("unexpected srelocation type %u", sreloc->r_type());
5516 template <typename A>
5517 void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
5519 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
5520 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
5521 switch ( sect->flags() & SECTION_TYPE ) {
5522 case S_SYMBOL_STUBS:
5523 case S_LAZY_SYMBOL_POINTERS:
5524 // we ignore compiler generated stubs, so ignore those relocs too
5527 // ignore all relocations in __eh_frame section
5528 if ( sect == fehFrameSection )
5530 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
5531 const uint32_t relocCount = sect->nreloc();
5532 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
5533 for (uint32_t r = 0; r < relocCount; ++r) {
5535 if ( addRelocReference(sect, &relocs[r]) )
5538 catch (const char* msg) {
5539 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
5548 const char* Reference<x86>::getDescription() const
5550 static char temp[2048];
5553 sprintf(temp, "reference to ");
5555 case x86::kFollowOn:
5556 sprintf(temp, "followed by ");
5558 case x86::kGroupSubordinate:
5559 sprintf(temp, "group subordinate ");
5561 case x86::kPointerWeakImport:
5562 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5565 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5567 case x86::kPointerDiff:
5569 // by-name references have quoted names
5570 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5571 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5572 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5573 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5574 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5578 case x86::kPointerDiff16:
5580 // by-name references have quoted names
5581 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5582 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5583 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5584 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5585 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5589 case x86::kPCRel32WeakImport:
5590 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
5593 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
5596 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
5599 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
5601 case x86::kAbsolute32:
5602 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
5604 case x86::kImageOffset32:
5605 sprintf(temp, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc);
5607 case x86::kPointerDiff24:
5608 sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5609 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5610 this->getFromTargetDisplayName(), fFromTarget.offset );
5613 case x86::kSectionOffset24:
5614 sprintf(temp, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc);
5616 case x86::kDtraceProbe:
5617 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5619 case x86::kDtraceProbeSite:
5620 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5622 case x86::kDtraceIsEnabledSite:
5623 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5625 case x86::kDtraceTypeReference:
5626 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5629 // always quote by-name references
5630 if ( fToTargetName != NULL ) {
5632 strcat(temp, fToTargetName);
5635 else if ( fToTarget.atom != NULL ) {
5636 strcat(temp, fToTarget.atom->getDisplayName());
5639 strcat(temp, "NULL target");
5641 if ( fToTarget.offset != 0 )
5642 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5649 const char* Reference<ppc>::getDescription() const
5651 static char temp[2048];
5654 sprintf(temp, "reference to ");
5656 case ppc::kFollowOn:
5657 sprintf(temp, "followed by ");
5659 case ppc::kGroupSubordinate:
5660 sprintf(temp, "group subordinate ");
5662 case ppc::kPointerWeakImport:
5663 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5666 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5668 case ppc::kPointerDiff16:
5670 // by-name references have quoted names
5671 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5672 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5673 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5674 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5675 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5678 case ppc::kPointerDiff32:
5680 // by-name references have quoted names
5681 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5682 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5683 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5684 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5685 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5688 case ppc::kPointerDiff64:
5689 throw "unsupported refrence kind";
5691 case ppc::kBranch24WeakImport:
5692 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5694 case ppc::kBranch24:
5695 case ppc::kBranch14:
5696 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5698 case ppc::kPICBaseLow16:
5699 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5701 case ppc::kPICBaseLow14:
5702 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5704 case ppc::kPICBaseHigh16:
5705 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5707 case ppc::kAbsLow16:
5708 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5710 case ppc::kAbsLow14:
5711 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5713 case ppc::kAbsHigh16:
5714 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
5716 case ppc::kAbsHigh16AddLow:
5717 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5719 case ppc::kDtraceProbe:
5720 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5722 case ppc::kDtraceProbeSite:
5723 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5725 case ppc::kDtraceIsEnabledSite:
5726 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5728 case ppc::kDtraceTypeReference:
5729 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5732 // always quote by-name references
5733 if ( fToTargetName != NULL ) {
5735 strcat(temp, fToTargetName);
5738 else if ( fToTarget.atom != NULL ) {
5739 strcat(temp, fToTarget.atom->getDisplayName());
5742 strcat(temp, "NULL target");
5744 if ( fToTarget.offset != 0 )
5745 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5751 const char* Reference<ppc64>::getDescription() const
5753 static char temp[2048];
5755 case ppc64::kNoFixUp:
5756 sprintf(temp, "reference to ");
5758 case ppc64::kFollowOn:
5759 sprintf(temp, "followed by ");
5761 case ppc64::kGroupSubordinate:
5762 sprintf(temp, "group subordinate ");
5764 case ppc64::kPointerWeakImport:
5765 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5767 case ppc64::kPointer:
5768 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5770 case ppc64::kPointerDiff64:
5772 // by-name references have quoted names
5773 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5774 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5775 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5776 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5777 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5780 case ppc64::kPointerDiff32:
5782 // by-name references have quoted names
5783 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5784 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5785 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5786 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5787 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5790 case ppc64::kPointerDiff16:
5792 // by-name references have quoted names
5793 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5794 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5795 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5796 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5797 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5800 case ppc64::kBranch24WeakImport:
5801 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5803 case ppc64::kBranch24:
5804 case ppc64::kBranch14:
5805 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5807 case ppc64::kPICBaseLow16:
5808 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5810 case ppc64::kPICBaseLow14:
5811 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5813 case ppc64::kPICBaseHigh16:
5814 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5816 case ppc64::kAbsLow16:
5817 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5819 case ppc64::kAbsLow14:
5820 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5822 case ppc64::kAbsHigh16:
5823 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
5825 case ppc64::kAbsHigh16AddLow:
5826 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5828 case ppc64::kDtraceProbe:
5829 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5831 case ppc64::kDtraceProbeSite:
5832 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5834 case ppc64::kDtraceIsEnabledSite:
5835 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5837 case ppc64::kDtraceTypeReference:
5838 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5841 // always quote by-name references
5842 if ( fToTargetName != NULL ) {
5844 strcat(temp, fToTargetName);
5847 else if ( fToTarget.atom != NULL ) {
5848 strcat(temp, fToTarget.atom->getDisplayName());
5851 strcat(temp, "NULL target");
5853 if ( fToTarget.offset != 0 )
5854 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5861 const char* Reference<x86_64>::getDescription() const
5863 static char temp[2048];
5865 case x86_64::kNoFixUp:
5866 sprintf(temp, "reference to ");
5868 case x86_64::kFollowOn:
5869 sprintf(temp, "followed by ");
5871 case x86_64::kGroupSubordinate:
5872 sprintf(temp, "group subordinate ");
5874 case x86_64::kPointerWeakImport:
5875 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5877 case x86_64::kPointer:
5878 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5880 case x86_64::kPointer32:
5881 sprintf(temp, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc);
5883 case x86_64::kPointerDiff32:
5884 case x86_64::kPointerDiff:
5886 // by-name references have quoted names
5887 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5888 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5889 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
5890 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5891 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5892 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5896 case x86_64::kPCRel32:
5897 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
5899 case x86_64::kPCRel32_1:
5900 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
5902 case x86_64::kPCRel32_2:
5903 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
5905 case x86_64::kPCRel32_4:
5906 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
5908 case x86_64::kBranchPCRel32:
5909 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
5911 case x86_64::kBranchPCRel32WeakImport:
5912 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
5914 case x86_64::kPCRel32GOT:
5915 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5917 case x86_64::kPCRel32GOTWeakImport:
5918 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5920 case x86_64::kPCRel32GOTLoad:
5921 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5923 case x86_64::kPCRel32GOTLoadWeakImport:
5924 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5926 case x86_64::kGOTNoFixUp:
5927 sprintf(temp, "reference to GOT entry for ");
5929 case x86_64::kBranchPCRel8:
5930 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
5932 case x86_64::kPointerDiff24:
5933 sprintf(temp, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5934 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5935 this->getFromTargetDisplayName(), fFromTarget.offset );
5937 case x86_64::kImageOffset32:
5938 sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc);
5940 case x86_64::kSectionOffset24:
5941 sprintf(temp, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc);
5943 case x86_64::kDtraceProbe:
5944 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5946 case x86_64::kDtraceProbeSite:
5947 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5949 case x86_64::kDtraceIsEnabledSite:
5950 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5952 case x86_64::kDtraceTypeReference:
5953 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5956 // always quote by-name references
5957 if ( fToTargetName != NULL ) {
5959 strcat(temp, fToTargetName);
5962 else if ( fToTarget.atom != NULL ) {
5963 strcat(temp, fToTarget.atom->getDisplayName());
5966 strcat(temp, "NULL target");
5968 if ( fToTarget.offset != 0 )
5969 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5976 const char* Reference<arm>::getDescription() const
5978 static char temp[2048];
5981 sprintf(temp, "reference to ");
5983 case arm::kFollowOn:
5984 sprintf(temp, "followed by ");
5986 case arm::kGroupSubordinate:
5987 sprintf(temp, "group subordinate ");
5990 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5992 case arm::kPointerWeakImport:
5993 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5995 case arm::kPointerDiff:
5997 // by-name references have quoted names
5998 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5999 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
6000 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
6001 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
6002 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
6005 case arm::kPointerDiff12:
6007 // by-name references have quoted names
6008 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
6009 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
6010 sprintf(temp, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
6011 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
6012 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
6015 case arm::kReadOnlyPointer:
6016 sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc);
6018 case arm::kBranch24:
6019 case arm::kThumbBranch22:
6020 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
6022 case arm::kBranch24WeakImport:
6023 case arm::kThumbBranch22WeakImport:
6024 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
6026 case arm::kDtraceProbe:
6027 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
6029 case arm::kDtraceProbeSite:
6030 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
6032 case arm::kDtraceIsEnabledSite:
6033 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
6035 case arm::kDtraceTypeReference:
6036 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
6039 // always quote by-name references
6040 if ( fToTargetName != NULL ) {
6042 strcat(temp, fToTargetName);
6045 else if ( fToTarget.atom != NULL ) {
6046 strcat(temp, fToTarget.atom->getDisplayName());
6049 strcat(temp, "NULL target");
6051 if ( fToTarget.offset != 0 )
6052 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
6059 bool Reference<x86>::isBranch() const
6063 case x86::kPCRel32WeakImport:
6071 bool Reference<x86_64>::isBranch() const
6074 case x86_64::kBranchPCRel32:
6075 case x86_64::kBranchPCRel32WeakImport:
6083 bool Reference<ppc>::isBranch() const
6086 case ppc::kBranch24:
6087 case ppc::kBranch24WeakImport:
6095 bool Reference<ppc64>::isBranch() const
6098 case ppc64::kBranch24:
6099 case ppc64::kBranch24WeakImport:
6107 bool Reference<arm>::isBranch() const
6110 case arm::kBranch24:
6111 case arm::kBranch24WeakImport:
6112 case arm::kThumbBranch22:
6113 case arm::kThumbBranch22WeakImport:
6122 }; // namespace relocatable
6123 }; // namespace mach_o
6125 #endif // __OBJECT_FILE_MACH_O__