96-5
[darwin-xtools.git] / ld64 / src / ld / MachOReaderRelocatable.hpp
blobe6a182c0aa056f0cb246d4d5c40d920eec970822
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
12 * file.
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__
28 #include <stdint.h>
29 #include <math.h>
30 #include <unistd.h>
31 #include <sys/param.h>
33 #include <vector>
34 #include <set>
35 #include <algorithm>
37 #include "MachOFileAbstraction.hpp"
38 #include "Architectures.hpp"
39 #include "ObjectFile.h"
40 #include "dwarf2.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, ...);
62 namespace mach_o {
63 namespace relocatable {
67 class ReferenceSorter
69 public:
70 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
72 return ( left->getFixUpOffset() < right->getFixUpOffset() );
77 // forward reference
78 template <typename A> class Reader;
80 struct AtomAndOffset
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;
85 uint32_t offset;
89 template <typename A>
90 class Reference : public ObjectFile::Reference
92 public:
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 = &target; fToTarget.offset = offset; }
114 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
115 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = &target; }
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;
126 private:
127 pint_t fFixUpOffsetInSrc;
128 AtomAndOffset fToTarget;
129 AtomAndOffset fFromTarget;
130 const char* fToTargetName;
131 const char* fFromTargetName;
132 Kinds fKind;
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),
142 fKind(kind)
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;
198 else
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;
208 else
209 return ObjectFile::Reference::kUnboundByName;
211 else {
212 if ( fFromTargetName == NULL )
213 return ObjectFile::Reference::kBoundDirectly;
214 else
215 return ObjectFile::Reference::kBoundByName;
221 template <typename A>
222 class Segment : public ObjectFile::Segment
224 public:
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; }
230 private:
231 const macho_section<typename A::P>* fSection;
232 bool fWritable;
233 bool fExecutable;
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 ) {
241 fWritable = false;
242 fExecutable = true;
244 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
245 fWritable = true;
246 fExecutable = true;
251 class DataSegment : public ObjectFile::Segment
253 public:
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
266 public:
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
279 public:
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;
305 uint32_t fOrdinal;
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) ) {
318 return ref;
321 return NULL;
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) ) {
331 return ref;
334 return NULL;
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();
350 return NULL;
354 void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress)
356 fSingleUnwindInfo[0].unwindInfo = this->getCompactUnwindEncoding(ehAtomAddress);
357 fHasCompactUnwindInfo = true;
361 class BaseAtomSorter
363 public:
364 bool operator()(const class BaseAtom* left, const class BaseAtom* right) {
365 if ( left == right )
366 return false;
367 uint64_t leftAddr = left->getObjectAddress();
368 uint64_t rightAddr = right->getObjectAddress();
369 if ( leftAddr < rightAddr ) {
370 return true;
372 else if ( leftAddr > rightAddr ) {
373 return false;
375 else {
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 ) {
396 return true;
398 else if ( rightAlias ) {
399 return false;
401 // one might be a section start or end label
402 switch ( left->getContentType() ) {
403 case ObjectFile::Atom::kSectionStart:
404 return true;
405 case ObjectFile::Atom::kSectionEnd:
406 return false;
407 default:
408 break;
410 switch ( right->getContentType() ) {
411 case ObjectFile::Atom::kSectionStart:
412 return false;
413 case ObjectFile::Atom::kSectionEnd:
414 return true;
415 default:
416 break;
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 );
426 default:
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());
430 break;
433 return false;
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
446 public:
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);
482 protected:
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() {}
495 Reader<A>& fOwner;
496 const macho_nlist<P>* fSymbol;
497 pint_t fAddress;
498 pint_t fSize;
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;
521 else
522 fScope = ObjectFile::Atom::scopeGlobal;
523 if ( (type & N_TYPE) == N_SECT ) {
524 // real definition
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) );
535 else {
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 ) {
553 fSymbol = s;
554 break;
559 // support for labeled stubs
560 switch ( section->flags() & SECTION_TYPE ) {
561 case S_SYMBOL_STUBS:
562 setSize(section->reserved2());
563 break;
564 case S_LAZY_SYMBOL_POINTERS:
565 case S_NON_LAZY_SYMBOL_POINTERS:
566 setSize(sizeof(pint_t));
567 break;
568 case S_4BYTE_LITERALS:
569 setSize(4);
570 break;
571 case S_8BYTE_LITERALS:
572 setSize(8);
573 break;
574 case S_16BYTE_LITERALS:
575 setSize(16);
576 break;
577 case S_CSTRING_LITERALS:
578 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
579 fType = ObjectFile::Atom::kCStringType;
580 break;
581 case S_REGULAR:
582 case S_ZEROFILL:
583 case S_COALESCED:
584 // size calculate later after next atom is found
585 break;
588 // compute alignment
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;
600 else {
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 )
616 return true;
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 )
627 return "__text";
628 else if ( strcmp(fSection->sectname(), "__const_coal") == 0 )
629 return "__const";
630 else if ( strcmp(fSection->sectname(), "__datacoal_nt") == 0 )
631 return "__data";
632 else if ( fOwner.fOptions.fAutoOrderInitializers && (strcmp(fSection->sectname(), "__StaticInit") == 0) )
633 return "__text";
634 else {
635 switch ( fSection->flags() & SECTION_TYPE ) {
636 case S_4BYTE_LITERALS:
637 case S_8BYTE_LITERALS:
638 case S_16BYTE_LITERALS:
639 return "__const";
644 if ( strlen(fSection->sectname()) > 15 ) {
645 static char temp[18];
646 strncpy(temp, fSection->sectname(), 16);
647 temp[17] = '\0';
648 return temp;
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 );
671 class Beyond
673 public:
674 Beyond(uint64_t offset) : fOffset(offset) {}
675 bool operator()(ObjectFile::Reference* ref) const {
676 return ( ref->getFixUpOffset() >= fOffset );
678 private:
679 uint64_t 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());
689 // set new size
690 fSize = size;
693 template <typename A>
694 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
696 // copy base bytes
697 if ( isZeroFill() )
698 bzero(buffer, fSize);
699 else {
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
715 public:
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; }
747 protected:
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() {}
757 const char* fName;
758 const BaseAtom& fAliasOf;
759 ObjectFile::Atom::Scope fScope;
760 bool fDontDeadStrip;
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;
776 else
777 fScope = ObjectFile::Atom::scopeGlobal;
778 fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
780 else {
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
798 public:
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; }
830 protected:
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() {}
840 Reader<A>& fOwner;
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;
858 else
859 fScope = ObjectFile::Atom::scopeGlobal;
860 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
861 // tentative definition
863 else {
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) )
882 ++alignment;
884 // limit alignment of extremely large commons to 2^15 bytes (8-page)
885 if ( alignment < 12 )
886 return ObjectFile::Alignment(alignment);
887 else
888 return ObjectFile::Alignment(12);
891 template <typename A>
892 const char* TentativeAtom<A>::getSectionName() const
894 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
895 return "__common";
896 else
897 return "._tentdef";
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
916 public:
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; }
948 void resolveName();
949 virtual uint8_t getLSDAReferenceKind() const;
950 virtual uint8_t getPersonalityReferenceKind() const;
951 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
953 protected:
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();
967 Reader<A>& fOwner;
968 const char* fSynthesizedName;
969 const char* fDisplayName;
970 const macho_section<P>* fSection;
971 pint_t fAddress;
972 pint_t fSize;
973 Segment<A>* fSegment;
974 ReferenceVector fReferences;
975 BaseAtom* fRedirect;
976 bool fDontDeadStrip;
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);
993 fRedirect = this;
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());
996 switch ( type ) {
997 case S_ZEROFILL:
999 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
1001 break;
1002 case S_COALESCED:
1003 case S_REGULAR:
1004 if ( section == owner.fehFrameSection ) {
1005 if ( fSize == 1 ) {
1006 // is CIE
1007 fSize = 0;
1008 fDontDeadStrip = false;
1009 if ( fOwner.fOptions.fForFinalLinkedImage )
1010 fSynthesizedName = "CIE";
1011 else
1012 fSynthesizedName = "EH_frame1";
1014 else {
1015 // is FDE
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;
1032 else
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 ( section == owner.fUTF16Section ) {
1062 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1063 fDontDeadStrip = false;
1064 fScope = ObjectFile::Atom::scopeLinkageUnit;
1065 fKind = ObjectFile::Atom::kWeakDefinition;
1066 char* name = new char[16+5*size];
1067 strcpy(name, "utf16-string=");
1068 char* s = &name[13];
1069 const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr());
1070 unsigned int wordCount = size/2;
1071 // note, the compiler sometimes puts trailing zeros on the end of the data
1072 if ( E::get32(words[wordCount-1]) == 0 )
1073 --wordCount;
1074 bool needSeperator = false;
1075 for(unsigned int i=0; i < wordCount; ++i) {
1076 if ( needSeperator )
1077 strcpy(s++, ".");
1078 sprintf(s, "%04X", E::get32(words[i]));
1079 s += 4;
1080 needSeperator = true;
1082 fSynthesizedName = name;
1084 else {
1085 asprintf((char**)&fSynthesizedName, "lutf16-0x%X", addr);
1088 break;
1089 case S_CSTRING_LITERALS:
1091 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
1092 if ( (strcmp(fSection->sectname(), "__cstring") == 0) && (strcmp(section->segname(), "__TEXT") == 0) )
1093 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
1094 else
1095 asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str);
1096 fScope = ObjectFile::Atom::scopeLinkageUnit;
1097 fKind = ObjectFile::Atom::kWeakDefinition;
1098 fType = ObjectFile::Atom::kCStringType;
1099 fDontDeadStrip = false;
1100 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
1101 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1103 break;
1104 case S_4BYTE_LITERALS:
1106 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1107 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
1108 fScope = ObjectFile::Atom::scopeLinkageUnit;
1109 fKind = ObjectFile::Atom::kWeakDefinition;
1110 fDontDeadStrip = false;
1112 break;
1113 case S_8BYTE_LITERALS:
1115 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1116 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
1117 fScope = ObjectFile::Atom::scopeLinkageUnit;
1118 fKind = ObjectFile::Atom::kWeakDefinition;
1119 fDontDeadStrip = false;
1121 break;
1122 case S_16BYTE_LITERALS:
1124 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1125 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
1126 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
1127 fScope = ObjectFile::Atom::scopeLinkageUnit;
1128 fKind = ObjectFile::Atom::kWeakDefinition;
1129 fDontDeadStrip = false;
1131 break;
1132 case S_LITERAL_POINTERS:
1134 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1135 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
1136 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
1137 fSynthesizedName = "literal-pointer-name-PENDING";
1138 fScope = ObjectFile::Atom::scopeLinkageUnit;
1139 fKind = ObjectFile::Atom::kWeakDefinition;
1140 fDontDeadStrip = false;
1141 owner.fAtomsPendingAName.push_back(this);
1142 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1144 break;
1145 case S_MOD_INIT_FUNC_POINTERS:
1146 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1147 break;
1148 case S_MOD_TERM_FUNC_POINTERS:
1149 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1150 break;
1151 case S_SYMBOL_STUBS:
1153 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
1154 index += fSection->reserved1();
1155 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1156 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
1157 uint32_t strOffset = sym->n_strx();
1158 // want name to not have $stub suffix, this is what automatic stub generation expects
1159 fSynthesizedName = &fOwner.fStrings[strOffset];
1160 // check for weak import
1161 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
1162 // sometimes the compiler gets confused and generates a stub to a static function
1163 // if so, we should redirect any call to the stub to be calls to the real static function atom
1164 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
1165 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
1166 if ( staticAtom != NULL )
1167 fRedirect = staticAtom;
1169 fKind = ObjectFile::Atom::kWeakDefinition;
1170 // might be a spurious stub for a static function, make stub static too
1171 if ( (sym->n_type() & N_EXT) == 0 )
1172 fScope = ObjectFile::Atom::scopeTranslationUnit;
1173 else
1174 fScope = ObjectFile::Atom::scopeLinkageUnit;
1176 break;
1177 case S_LAZY_SYMBOL_POINTERS:
1178 case S_NON_LAZY_SYMBOL_POINTERS:
1180 // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when
1181 // generating the new compressed LINKEDIT format
1182 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) && fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
1183 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1184 dummySection->set_segname("__DATA");
1185 dummySection->set_sectname("__nl_symbol_ptr");
1186 fSection = dummySection;
1187 fSegment = new Segment<A>(fSection);
1190 fDontDeadStrip = false;
1191 fScope = ObjectFile::Atom::scopeLinkageUnit;
1192 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
1193 index += fSection->reserved1();
1194 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1195 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1196 // Silly codegen with non-lazy pointer to a local symbol
1197 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1198 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
1199 // All atoms not created yet, so we need to scan symbol table
1200 const macho_nlist<P>* closestSym = NULL;
1201 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1202 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
1203 if ( ((sym->n_type() & N_TYPE) == N_SECT)
1204 && ((sym->n_type() & N_STAB) == 0) ) {
1205 if ( sym->n_value() == nonLazyPtrValue ) {
1206 const char* name = &fOwner.fStrings[sym->n_strx()];
1207 char* str = new char[strlen(name)+16];
1208 strcpy(str, name);
1209 strcat(str, "$non_lazy_ptr");
1210 fSynthesizedName = str;
1211 // add direct reference to target later, because its atom may not be constructed yet
1212 fOwner.fLocalNonLazys.push_back(this);
1213 fScope = ObjectFile::Atom::scopeTranslationUnit;
1214 fType = ObjectFile::Atom::kNonLazyPointer;
1215 return;
1217 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1218 closestSym = sym;
1222 // add direct reference to target later, because its atom may not be constructed yet
1223 if ( closestSym != NULL ) {
1224 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1225 char* str;
1226 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1227 fSynthesizedName = str;
1229 else {
1230 fSynthesizedName = "$interior$non_lazy_ptr";
1232 fScope = ObjectFile::Atom::scopeTranslationUnit;
1233 fOwner.fLocalNonLazys.push_back(this);
1234 fType = ObjectFile::Atom::kNonLazyPointer;
1235 return;
1237 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1238 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1239 char* str = new char[strlen(name)+16];
1240 strcpy(str, name);
1241 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1242 strcat(str, "$lazy_ptr");
1243 fType = ObjectFile::Atom::kLazyPointer;
1245 else {
1246 strcat(str, "$non_lazy_ptr");
1247 fType = ObjectFile::Atom::kNonLazyPointer;
1249 fSynthesizedName = str;
1251 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1252 fKind = ObjectFile::Atom::kWeakDefinition;
1254 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1255 // target is translation unit scoped, so add direct reference to target
1256 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1257 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1259 else {
1260 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1261 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1262 else
1263 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1266 break;
1267 default:
1268 throwf("section type %d not supported with address=0x%08llX", type, (uint64_t)addr);
1270 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1273 // x86_64 uses L labels on cstrings to allow relocs with addends
1274 template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1275 template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1277 template <typename A>
1278 void AnonymousAtom<A>::addLineInfo(const ObjectFile::LineInfo& info)
1280 // <rdar://problem/6545406> don't warn if line table has entries for stubs
1281 if ( (fSection->flags() & SECTION_TYPE) != S_SYMBOL_STUBS )
1282 warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath());
1285 template <typename A>
1286 void AnonymousAtom<A>::resolveName()
1288 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1289 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1290 // references are not yet sorted, so scan the vector
1291 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1292 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1293 const char* superStr = (*rit)->getTargetName();
1294 if ( strncmp(superStr, "cstring", 7) == 0 ) {
1295 const char* superClassName;
1296 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1297 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1299 break;
1302 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1303 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1304 const char* classStr = (*rit)->getTargetName();
1305 if ( strncmp(classStr, "cstring", 7) == 0 ) {
1306 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1308 break;
1312 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
1313 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1314 if ( references.size() < 1 )
1315 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1316 ObjectFile::Reference* ref = references[0];
1317 const char* str = ref->getTargetName();
1318 if ( strncmp(str, "cstring", 7) == 0 ) {
1319 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1322 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1323 // references are not yet sorted, so scan the vector
1324 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1325 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1326 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1327 const char* superStr = (*rit)->getTargetName();
1328 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1329 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1331 else if ( (superStr != NULL) && (strncmp(superStr, "utf16-string=", 13) == 0) ) {
1332 asprintf((char**)&fSynthesizedName, "cfstring-utf16=%s", &superStr[13]);
1334 else {
1335 // compiled with -fwritable-strings or a non-ASCII string
1336 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1337 fScope = ObjectFile::Atom::scopeTranslationUnit;
1338 fSynthesizedName = "cfstring-not-coalesable";
1339 if ( (*rit)->getTargetOffset() != 0 )
1340 warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner.getPath());
1342 break;
1346 else if ( fSection == fOwner.fehFrameSection ) {
1347 // give name to FDE
1348 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromFDEAddress(fAddress);
1349 if ( funcAtom != NULL )
1350 asprintf((char**)&fSynthesizedName, "%s.eh", funcAtom->getDisplayName());
1352 else if ( fOwner.fLSDAAtoms.count(this) != 0) {
1353 // give name to LSDA
1354 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromLSDAAddress(fAddress);
1355 if ( funcAtom != NULL )
1356 asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
1361 template <typename A>
1362 const char* AnonymousAtom<A>::getDisplayName() const
1364 if ( fSynthesizedName != NULL )
1365 return fSynthesizedName;
1367 if ( fDisplayName != NULL )
1368 return fDisplayName;
1370 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1371 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1372 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
1374 else {
1375 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
1377 return fDisplayName;
1381 template <typename A>
1382 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1384 return fScope;
1388 template <typename A>
1389 bool AnonymousAtom<A>::isZeroFill() const
1391 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
1395 template <typename A>
1396 const char* AnonymousAtom<A>::getSectionName() const
1398 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1399 switch ( fSection->flags() & SECTION_TYPE ) {
1400 case S_4BYTE_LITERALS:
1401 case S_8BYTE_LITERALS:
1402 case S_16BYTE_LITERALS:
1403 return "__const";
1407 if ( strlen(fSection->sectname()) > 15 ) {
1408 static char temp[18];
1409 strncpy(temp, fSection->sectname(), 16);
1410 temp[17] = '\0';
1411 return temp;
1413 return fSection->sectname();
1416 template <typename A>
1417 ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
1419 // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
1420 if ( fType == ObjectFile::Atom::kCFIType )
1421 return ObjectFile::Alignment(0);
1423 switch ( fSection->flags() & SECTION_TYPE ) {
1424 case S_4BYTE_LITERALS:
1425 return ObjectFile::Alignment(2);
1426 case S_8BYTE_LITERALS:
1427 return ObjectFile::Alignment(3);
1428 case S_16BYTE_LITERALS:
1429 return ObjectFile::Alignment(4);
1430 case S_NON_LAZY_SYMBOL_POINTERS:
1431 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
1432 case S_CSTRING_LITERALS:
1433 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1434 return ObjectFile::Alignment(fSection->align());
1435 default:
1436 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
1441 template <typename A>
1442 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1444 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1445 Reference<A>* ref = *it;
1446 if ( ref->getKind() == A::kFollowOn )
1447 return ref->getTarget();
1449 return *((ObjectFile::Atom*)NULL);
1452 template <typename A>
1453 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1455 // copy base bytes
1456 if ( isZeroFill() )
1457 bzero(buffer, fSize);
1458 else {
1459 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1460 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1465 // An AbsoluteAtom represents an N_ABS symbol which can only be created in
1466 // assembly language and usable by static executables such as the kernel/
1468 template <typename A>
1469 class AbsoluteAtom : public BaseAtom
1471 public:
1472 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1473 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1474 { return fOwner.getTranslationUnitSource(dir, name); }
1475 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1476 virtual const char* getDisplayName() const { return getName(); }
1477 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1478 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1479 virtual bool isZeroFill() const { return false; }
1480 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
1481 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1482 virtual bool dontDeadStrip() const { return false; }
1483 virtual uint64_t getSize() const { return 0; }
1484 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1485 virtual bool mustRemainInSection() const { return true; }
1486 virtual const char* getSectionName() const { return "._absolute"; }
1487 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1488 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1489 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1490 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1491 virtual void copyRawContent(uint8_t buffer[]) const { }
1492 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1493 virtual void setSize(uint64_t size) { }
1494 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1495 virtual void sortReferences() { }
1496 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1497 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1498 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1499 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1500 virtual const void* getSectionRecord() const { return NULL; }
1501 virtual unsigned int getSectionIndex() const { return 0; }
1503 protected:
1504 typedef typename A::P P;
1505 typedef typename A::P::E E;
1506 typedef typename A::P::uint_t pint_t;
1507 typedef typename A::ReferenceKinds Kinds;
1508 friend class Reader<A>;
1510 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1511 virtual ~AbsoluteAtom() {}
1513 Reader<A>& fOwner;
1514 const macho_nlist<P>* fSymbol;
1515 ObjectFile::Atom::Scope fScope;
1516 static std::vector<ObjectFile::Reference*> fgNoReferences;
1519 template <typename A>
1520 std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1522 template <typename A>
1523 AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1524 : fOwner(owner), fSymbol(symbol)
1526 // store absolute adress in fSectionOffset
1527 fSectionOffset = symbol->n_value();
1528 // compute scope
1529 uint8_t type = symbol->n_type();
1530 if ( (type & N_EXT) == 0 )
1531 fScope = ObjectFile::Atom::scopeTranslationUnit;
1532 else if ( (type & N_PEXT) != 0 )
1533 fScope = ObjectFile::Atom::scopeLinkageUnit;
1534 else
1535 fScope = ObjectFile::Atom::scopeGlobal;
1536 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1541 // An SectionBoundaryAtom represent the start or end of a section
1543 template <typename A>
1544 class SectionBoundaryAtom : public BaseAtom
1546 public:
1547 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1548 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1549 { return fOwner.getTranslationUnitSource(dir, name); }
1550 virtual const char* getName() const { return fSymbolName; }
1551 virtual const char* getDisplayName() const { return fDisplayName; }
1552 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1553 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition; }
1554 virtual ObjectFile::Atom::ContentType getContentType() const { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
1555 virtual bool isZeroFill() const { return false; }
1556 virtual bool isThumb() const { return false; }
1557 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
1558 virtual bool dontDeadStrip() const { return false; }
1559 virtual uint64_t getSize() const { return 0; }
1560 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1561 virtual bool mustRemainInSection() const { return true; }
1562 virtual const char* getSectionName() const { return fSectionName; }
1563 virtual ObjectFile::Segment& getSegment() const { return *fSegment; }
1564 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1565 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1566 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1567 virtual void copyRawContent(uint8_t buffer[]) const { }
1568 virtual void setScope(ObjectFile::Atom::Scope newScope) { }
1569 virtual void setSize(uint64_t size) { }
1570 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1571 virtual void sortReferences() { }
1572 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1573 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1574 virtual uint64_t getObjectAddress() const { return 0; }
1575 virtual const void* getSectionRecord() const { return NULL; }
1576 virtual unsigned int getSectionIndex() const { return 0; }
1578 protected:
1579 typedef typename A::P P;
1580 typedef typename A::P::E E;
1581 typedef typename A::P::uint_t pint_t;
1582 typedef typename A::ReferenceKinds Kinds;
1583 friend class Reader<A>;
1586 class Segment : public ObjectFile::Segment
1588 public:
1589 Segment(const char* name, bool r, bool w, bool x):
1590 fName(name), fReadable(r), fWritable(w), fExecutable(x) {}
1592 virtual const char* getName() const { return fName; }
1593 virtual bool isContentReadable() const { return fReadable; }
1594 virtual bool isContentWritable() const { return fWritable; }
1595 virtual bool isContentExecutable() const { return fExecutable; }
1596 private:
1597 const char* fName;
1598 bool fReadable;
1599 bool fWritable;
1600 bool fExecutable;
1603 SectionBoundaryAtom(Reader<A>&, bool start, const char* symbolName, const char* segSectName);
1604 virtual ~SectionBoundaryAtom() {}
1606 Reader<A>& fOwner;
1607 class Segment* fSegment;
1608 const char* fSymbolName;
1609 const char* fSectionName;
1610 const char* fDisplayName;
1611 bool fStart;
1612 static std::vector<ObjectFile::Reference*> fgNoReferences;
1615 template <typename A>
1616 std::vector<ObjectFile::Reference*> SectionBoundaryAtom<A>::fgNoReferences;
1618 // examples:
1619 // section$start$__DATA$__my
1620 // section$end$__DATA$__my
1621 template <typename A>
1622 SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
1623 : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start)
1625 const char* segSectDividor = strrchr(segSectName, '$');
1626 if ( segSectDividor == NULL )
1627 throwf("malformed section reference name: %s", symbolName);
1628 fSectionName = segSectDividor + 1;
1629 int segNameLen = segSectDividor - segSectName;
1630 if ( segNameLen > 16 )
1631 throwf("malformed section reference name: %s", symbolName);
1632 char segName[18];
1633 strlcpy(segName, segSectName, segNameLen+1);
1634 if ( strcmp(segName, "__TEXT") == 0 )
1635 fSegment = new Segment("__TEXT", true, false, true);
1636 else if ( strcmp(segName, "__DATA") == 0 )
1637 fSegment = new Segment("__DATA", true, true, false);
1638 else
1639 fSegment = new Segment(strdup(segName), true, true, false);
1641 asprintf((char**)&fDisplayName, "%s of section '%s' in segment '%s'", (start ? "start" : "end"), fSectionName, segName);
1647 /// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
1648 /// dwarf CFI information in an object file.
1650 template <typename A>
1651 class ObjectFileAddressSpace
1653 public:
1654 ObjectFileAddressSpace(Reader<A>& reader);
1656 typedef typename A::P::uint_t pint_t;
1657 typedef typename A::P P;
1658 typedef typename A::P::uint_t sint_t;
1660 uint8_t get8(pint_t addr);
1661 uint16_t get16(pint_t addr);
1662 uint32_t get32(pint_t addr);
1663 uint64_t get64(pint_t addr);
1664 pint_t getP(pint_t addr);
1665 uint64_t getULEB128(pint_t& addr, pint_t end);
1666 int64_t getSLEB128(pint_t& addr, pint_t end);
1667 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
1668 private:
1669 const void* mappedAddress(pint_t addr, pint_t* relocTarget=NULL);
1670 pint_t relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount);
1671 void buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map);
1673 Reader<A>& fReader;
1674 const uint8_t* fMappingStart;
1675 const macho_section<P>* fSectionsStart;
1676 const macho_section<P>* fSectionsEnd;
1677 std::map<uint32_t,uint64_t> fEHFrameOffsetToTargetMap;
1681 template <typename A>
1682 ObjectFileAddressSpace<A>::ObjectFileAddressSpace(Reader<A>& reader)
1683 : fReader(reader), fMappingStart(NULL), fSectionsStart(NULL), fSectionsEnd(NULL)
1689 template <typename A>
1690 const void* ObjectFileAddressSpace<A>::mappedAddress(pint_t addr, pint_t* relocTarget)
1692 if ( fMappingStart == NULL ) {
1693 // delay initialization until now when fReader.fSegment is set up
1694 fMappingStart = (uint8_t*)fReader.fHeader;
1695 fSectionsStart = (macho_section<P>*)((char*)fReader.fSegment + sizeof(macho_segment_command<P>));
1696 fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()];
1697 // find __eh_frame section and build map of relocations for performance
1698 buildRelocatedMap(fReader.fehFrameSection, fEHFrameOffsetToTargetMap);
1700 // special case lookups in __eh_frame section to be fast
1701 const macho_section<P>* ehSect = fReader.fehFrameSection;
1702 if ( (ehSect->addr() <= addr) && (addr < (ehSect->addr()+ehSect->size())) ) {
1703 pint_t offsetOfAddrInSection = addr - ehSect->addr();
1704 if ( relocTarget != NULL ) {
1705 std::map<uint32_t,uint64_t>::iterator pos = fEHFrameOffsetToTargetMap.find(offsetOfAddrInSection);
1706 if ( pos != fEHFrameOffsetToTargetMap.end() )
1707 *relocTarget = pos->second;
1708 else
1709 *relocTarget = 0;
1711 return fMappingStart + ehSect->offset() + offsetOfAddrInSection;
1713 else {
1714 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
1715 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
1716 pint_t offsetOfAddrInSection = addr - sect->addr();
1717 if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
1718 const uint32_t indirectTableOffset = sect->reserved1();
1719 const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t);
1720 const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]);
1721 // return pointer to symbol name which this non-lazy-pointer will point to
1722 if ( relocTarget != NULL )
1723 *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()];
1725 else {
1726 if ( relocTarget != NULL )
1727 *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc());
1729 return fMappingStart + sect->offset() + offsetOfAddrInSection;
1732 throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr);
1739 template <typename A>
1740 uint8_t ObjectFileAddressSpace<A>::get8(pint_t logicalAddr)
1742 return *((uint8_t*)mappedAddress(logicalAddr));
1745 template <typename A>
1746 uint16_t ObjectFileAddressSpace<A>::get16(pint_t logicalAddr)
1748 return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr)));
1751 template <typename A>
1752 uint32_t ObjectFileAddressSpace<A>::get32(pint_t logicalAddr)
1754 pint_t relocTarget;
1755 return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1758 template <typename A>
1759 uint64_t ObjectFileAddressSpace<A>::get64(pint_t logicalAddr)
1761 pint_t relocTarget;
1762 return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1765 template <typename A>
1766 typename A::P::uint_t ObjectFileAddressSpace<A>::getP(pint_t logicalAddr)
1768 pint_t relocTarget;
1769 return P::getP(*((pint_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1772 template <typename A>
1773 uint64_t ObjectFileAddressSpace<A>::getULEB128(pint_t& logicalAddr, pint_t end)
1775 uintptr_t size = (end - logicalAddr);
1776 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1777 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1778 uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
1779 logicalAddr += (laddr-sladdr);
1780 return result;
1783 template <typename A>
1784 int64_t ObjectFileAddressSpace<A>::getSLEB128(pint_t& logicalAddr, pint_t end)
1786 uintptr_t size = (end - logicalAddr);
1787 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1788 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1789 int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
1790 logicalAddr += (laddr-sladdr);
1791 return result;
1799 template <typename A>
1800 class Reader : public ObjectFile::Reader
1802 public:
1803 static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
1804 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1805 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
1806 virtual ~Reader() {}
1808 virtual const char* getPath() { return fPath; }
1809 virtual time_t getModificationTime() { return fModTime; }
1810 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1811 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1812 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1813 virtual std::vector<Stab>* getStabs() { return &fStabs; }
1814 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
1815 virtual uint32_t updateCpuConstraint(uint32_t current);
1816 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1817 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
1818 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
1820 bool getTranslationUnitSource(const char** dir, const char** name) const;
1822 private:
1823 typedef typename A::P P;
1824 typedef typename A::P::E E;
1825 typedef typename A::P::uint_t pint_t;
1826 //typedef typename std::vector<Atom<A>*> AtomVector;
1827 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1828 typedef typename A::ReferenceKinds Kinds;
1829 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::FDE_Atom_Info FDE_Atom_Info;
1830 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::CIE_Atom_Info CIE_Atom_Info;
1831 typedef class ObjectFileAddressSpace<A> OAS;
1832 friend class ObjectFileAddressSpace<A>;
1833 friend class AnonymousAtom<A>;
1834 friend class TentativeAtom<A>;
1835 friend class AbsoluteAtom<A>;
1836 friend class SectionBoundaryAtom<A>;
1837 friend class SymbolAtom<A>;
1838 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
1840 void addReferencesForSection(const macho_section<P>* sect);
1841 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1842 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1843 const char* getDwarfString(uint64_t form, const uint8_t* p);
1844 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1845 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1846 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1847 static const char* assureFullPath(const char* path);
1848 AtomAndOffset findAtomAndOffset(pint_t addr);
1849 AtomAndOffset findAtomAndOffsetForSection(pint_t addr, unsigned int sectionIndex);
1850 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1851 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1852 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1853 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1854 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1855 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
1856 BaseAtom* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
1857 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
1858 void validSectionType(uint8_t type);
1859 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1860 void setCpuConstraint(uint32_t cpusubtype);
1861 const macho_section<P>* getSectionForAddress(pint_t);
1862 ObjectFile::Atom* getFunctionAtomFromFDEAddress(pint_t);
1863 ObjectFile::Atom* getFunctionAtomFromLSDAAddress(pint_t);
1864 void addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target);
1865 void addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding);
1866 bool isSectDiffReloc(uint8_t r_type);
1869 BaseAtom* findAtomByName(const char*);
1871 const char* fPath;
1872 time_t fModTime;
1873 uint32_t fOrdinalBase;
1874 const ObjectFile::ReaderOptions& fOptions;
1875 const macho_header<P>* fHeader;
1876 const char* fStrings;
1877 const macho_nlist<P>* fSymbols;
1878 uint32_t fSymbolCount;
1879 const macho_segment_command<P>* fSegment;
1880 const uint32_t* fIndirectTable;
1881 std::vector<BaseAtom*> fAtoms;
1882 AddrToAtomMap fAddrToAtom;
1883 AddrToAtomMap fAddrToAbsoluteAtom;
1884 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
1885 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1886 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1887 std::vector<const char*> fDtraceProviderInfo;
1888 ObjectFile::Reader::DebugInfoKind fDebugInfo;
1889 bool fHasUUID;
1890 const macho_section<P>* fehFrameSection;
1891 const macho_section<P>* fUTF16Section;
1892 std::set<BaseAtom*> fLSDAAtoms;
1893 const macho_section<P>* fDwarfDebugInfoSect;
1894 const macho_section<P>* fDwarfDebugAbbrevSect;
1895 const macho_section<P>* fDwarfDebugLineSect;
1896 const macho_section<P>* fDwarfDebugStringSect;
1897 const char* fDwarfTranslationUnitDir;
1898 const char* fDwarfTranslationUnitFile;
1899 std::map<uint32_t,const char*> fDwarfIndexToFile;
1900 std::vector<Stab> fStabs;
1901 std::vector<FDE_Atom_Info> fFDEInfos;
1902 std::vector<CIE_Atom_Info> fCIEInfos;
1903 bool fAppleObjc;
1904 bool fHasDTraceProbes;
1905 bool fHaveIndirectSymbols;
1906 bool fReplacementClasses;
1907 bool fHasLongBranchStubs;
1908 ObjectFile::Reader::ObjcConstraint fObjConstraint;
1909 uint32_t fCpuConstraint;
1910 const macho_section<P>* fSectionsStart;
1911 const macho_section<P>* fSectionsEnd;
1912 OAS fObjectAddressSpace;
1915 template <typename A>
1916 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1917 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
1918 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
1919 fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), fUTF16Section(NULL),
1920 fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
1921 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
1922 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
1923 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny),
1924 fSectionsStart(NULL), fSectionsEnd(NULL), fObjectAddressSpace(*this)
1926 // sanity check
1927 if ( ! validFile(fileContent, false, 0) )
1928 throw "not a valid mach-o object file";
1930 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1932 // write out path for -t or -whatsloaded option
1933 if ( options.fLogObjectFiles || options.fLogAllFiles )
1934 printf("%s\n", path);
1936 // cache intersting pointers
1937 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1938 this->setCpuConstraint(header->cpusubtype());
1939 const uint32_t cmd_count = header->ncmds();
1940 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
1941 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
1942 const macho_load_command<P>* cmd = cmds;
1943 uint32_t undefinedStartIndex = 0;
1944 uint32_t undefinedEndIndex = 0;
1945 for (uint32_t i = 0; i < cmd_count; ++i) {
1946 switch (cmd->cmd()) {
1947 case LC_SYMTAB:
1949 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1950 fSymbolCount = symtab->nsyms();
1951 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1952 fStrings = (char*)header + symtab->stroff();
1953 if ( undefinedEndIndex == 0 ) {
1954 undefinedStartIndex = 0;
1955 undefinedEndIndex = symtab->nsyms();
1958 break;
1959 case LC_DYSYMTAB:
1961 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1962 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
1963 undefinedStartIndex = dsymtab->iundefsym();
1964 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
1966 break;
1967 case LC_UUID:
1968 fHasUUID = true;
1969 break;
1971 default:
1972 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1973 fSegment = (macho_segment_command<P>*)cmd;
1975 break;
1977 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
1978 if ( cmd > cmdsEnd )
1979 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
1982 // if there are no load commands, then this file has no content, so no atoms
1983 if ( header->ncmds() < 1 )
1984 return;
1986 fSectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1987 fSectionsEnd = &fSectionsStart[fSegment->nsects()];
1989 // inital guess for number of atoms
1990 fAtoms.reserve(fSymbolCount);
1992 // if there is an __eh_frame section, decode it into chunks to get atoms in that
1993 // section as well as division points for functions in __text
1994 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
1995 if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
1996 fehFrameSection = sect;
1997 const char* msg = libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::getCFIs(fObjectAddressSpace, sect->addr(),
1998 sect->size(), fFDEInfos, fCIEInfos);
1999 if ( msg != NULL ) {
2000 throwf("malformed __eh_frame section: %s", msg);
2002 else {
2003 //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size());
2004 // add anonymous atoms for each CIE
2005 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2006 AnonymousAtom<A>* cieAtom = new AnonymousAtom<A>(*this, sect, it->cieAddress, 1);
2007 fAtoms.push_back(cieAtom);
2008 fAddrToAtom[it->cieAddress] = cieAtom;
2010 // add anonymous atoms for each FDE and LSDA
2011 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2012 //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);
2013 AnonymousAtom<A>* fdeAtom = new AnonymousAtom<A>(*this, sect, it->fdeAddress, 0);
2014 fAtoms.push_back(fdeAtom);
2015 fAddrToAtom[it->fdeAddress] = fdeAtom;
2016 if ( it->lsda.address != 0 ) {
2017 AnonymousAtom<A>* lsdaAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->lsda.address), it->lsda.address, 0);
2018 fAtoms.push_back(lsdaAtom);
2019 fAddrToAtom[it->lsda.address] = lsdaAtom;
2020 fLSDAAtoms.insert(lsdaAtom);
2025 else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
2026 // if there is a __ustring section parse it into AnonymousAtoms based on labels
2027 fUTF16Section = sect;
2028 std::vector<pint_t> utf16Addreses;
2029 for (int i=fSymbolCount-1; i >= 0 ; --i) {
2030 const macho_nlist<P>& sym = fSymbols[i];
2031 if ( (sym.n_type() & N_STAB) == 0 ) {
2032 uint8_t type = (sym.n_type() & N_TYPE);
2033 if ( type == N_SECT ) {
2034 if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) {
2035 utf16Addreses.push_back(sym.n_value());
2040 utf16Addreses.push_back(fUTF16Section->addr()+fUTF16Section->size());
2041 std::sort(utf16Addreses.begin(), utf16Addreses.end());
2042 for(int i=utf16Addreses.size()-2; i >=0 ; --i) {
2043 pint_t size = utf16Addreses[i+1] - utf16Addreses[i];
2044 AnonymousAtom<A>* strAtom = new AnonymousAtom<A>(*this, fUTF16Section, utf16Addreses[i], size);
2045 fAtoms.push_back(strAtom);
2046 fAddrToAtom[utf16Addreses[i]] = strAtom;
2052 // add all atoms that have entries in symbol table
2053 BaseAtom* sectionEndAtoms[fSegment->nsects()];
2054 for (unsigned int i=0; i < fSegment->nsects(); ++i)
2055 sectionEndAtoms[i] = NULL;
2056 for (int i=fSymbolCount-1; i >= 0 ; --i) {
2057 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name
2058 const macho_nlist<P>& sym = fSymbols[i];
2059 if ( (sym.n_type() & N_STAB) == 0 ) {
2060 uint8_t type = (sym.n_type() & N_TYPE);
2061 if ( type == N_SECT ) {
2062 const macho_section<P>* section = &fSectionsStart[sym.n_sect()-1];
2063 const pint_t sectionStartAddr = section->addr();
2064 const pint_t sectionEndAddr = sectionStartAddr + section->size();
2065 bool suppress = false;
2066 // ignore atoms in debugger sections
2067 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
2068 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
2069 // ignore dtrace probe labels
2070 fHasDTraceProbes = true;
2072 else if ( fStrings[sym.n_strx()] == 'L' ) {
2073 // ignore L labels, <rdar://problem/3962731>
2075 else if ( section == fehFrameSection ) {
2076 // ignore labels in __eh_frame section
2078 else if ( section == fUTF16Section ) {
2079 // ignore labels in __ustring section
2081 else {
2082 // ignore labels for atoms in other sections
2083 switch ( section->flags() & SECTION_TYPE ) {
2084 case S_REGULAR:
2085 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
2086 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
2087 case S_ZEROFILL:
2088 case S_COALESCED:
2089 case S_4BYTE_LITERALS:
2090 case S_8BYTE_LITERALS:
2091 case S_16BYTE_LITERALS:
2092 case S_CSTRING_LITERALS:
2094 BaseAtom* newAtom;
2095 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
2096 if ( (pos != fAddrToAtom.end()) && (pos->second->getSectionRecord() == section) ) {
2097 if ( fLSDAAtoms.count(pos->second) != 0 ) {
2098 // already have LSDA atom from for this address, ignore compiler's label
2099 suppress = true;
2100 break;
2102 else {
2103 // another label to an existing address in the same section, make this an alias
2104 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
2107 else {
2108 if ( sym.n_value() == sectionEndAddr ) {
2109 // Symbol address is at end of section. This can interfere
2110 // with a symbol at the start of the next section, so don't
2111 // add to fAddrToAtom. But do track in sectionEndAtoms so we
2112 // still make aliases if there are duplicates.
2113 if ( sectionEndAtoms[sym.n_sect()-1] == NULL ) {
2114 newAtom = new SymbolAtom<A>(*this, &sym, section);
2115 sectionEndAtoms[sym.n_sect()-1] = newAtom;
2116 // if this is a zero length section, so add to fAddrToAtom
2117 if ( sym.n_value() == sectionStartAddr )
2118 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2120 else {
2121 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *sectionEndAtoms[sym.n_sect()-1]);
2124 else {
2125 // make SymbolAtom atom for this address
2126 newAtom = new SymbolAtom<A>(*this, &sym, section);
2127 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2130 if ( ! suppress )
2131 fAtoms.push_back(newAtom);
2133 break;
2134 case S_SYMBOL_STUBS:
2135 case S_LAZY_SYMBOL_POINTERS:
2136 case S_NON_LAZY_SYMBOL_POINTERS:
2137 // ignore symboled stubs produces by old ld64
2138 break;
2139 default:
2140 warning("symbol %s found in unsupported section in %s",
2141 &fStrings[sym.n_strx()], this->getPath());
2146 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
2147 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
2149 else if ( (type == N_UNDF) && (sym.n_value() == 0) ) {
2150 const char* symName = &fStrings[sym.n_strx()];
2151 if ( strncmp(symName, "section$start$", 14) == 0)
2152 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, true, symName, &symName[14]));
2153 else if ( strncmp(symName, "section$end$", 12) == 0)
2154 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, false, symName, &symName[12]));
2156 else if ( type == N_ABS ) {
2157 const char* symName = &fStrings[sym.n_strx()];
2158 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
2159 // ignore .objc_class_name_* symbols
2160 fAppleObjc = true;
2162 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
2163 // ignore empty *.eh symbols
2165 else {
2166 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
2167 fAtoms.push_back(abAtom);
2168 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
2171 else if ( type == N_INDR ) {
2172 fHaveIndirectSymbols = true;
2177 // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names
2178 if ( fehFrameSection != NULL ) {
2179 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2180 // add if not already an atom at that address
2181 if ( fAddrToAtom.find(it->function.address) == fAddrToAtom.end() ) {
2182 AnonymousAtom<A>* funcAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->function.address), it->function.address, 0);
2183 fAtoms.push_back(funcAtom);
2184 fAddrToAtom[it->function.address] = funcAtom;
2185 // even though we've made a new atom, be conservative and make sure they lay out together
2186 if ( canScatterAtoms() ) {
2187 AtomAndOffset prev = findAtomAndOffset(it->function.address-1);
2188 if ( prev.atom != NULL ) {
2189 if ( ((BaseAtom*)(prev.atom))->getSectionRecord() == funcAtom->getSectionRecord() )
2190 new Reference<A>(A::kFollowOn, prev, AtomAndOffset(funcAtom));
2198 // add all fixed size anonymous atoms from special sections
2199 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2200 pint_t atomSize = 0;
2201 uint8_t type (sect->flags() & SECTION_TYPE);
2202 validSectionType(type);
2203 bool suppress = false;
2204 switch ( type ) {
2205 case S_SYMBOL_STUBS:
2206 suppress = true;
2207 atomSize = sect->reserved2();
2208 break;
2209 case S_LAZY_SYMBOL_POINTERS:
2210 suppress = true;
2211 atomSize = sizeof(pint_t);
2212 break;
2213 case S_NON_LAZY_SYMBOL_POINTERS:
2214 case S_LITERAL_POINTERS:
2215 case S_MOD_INIT_FUNC_POINTERS:
2216 case S_MOD_TERM_FUNC_POINTERS:
2217 atomSize = sizeof(pint_t);
2218 break;
2219 case S_INTERPOSING:
2220 atomSize = sizeof(pint_t)*2;
2221 break;
2222 case S_4BYTE_LITERALS:
2223 atomSize = 4;
2224 break;
2225 case S_8BYTE_LITERALS:
2226 atomSize = 8;
2227 break;
2228 case S_16BYTE_LITERALS:
2229 atomSize = 16;
2230 break;
2231 case S_REGULAR:
2232 // special case ObjC classes to synthesize .objc_class_name_* symbols
2233 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
2234 // gcc sometimes over aligns class structure
2235 uint32_t align = 1 << sect->align();
2236 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
2238 // get objc Garbage Collection info
2239 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
2240 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
2241 // struct objc_image_info {
2242 // uint32_t version; // initially 0
2243 // uint32_t flags;
2244 // };
2245 // #define OBJC_IMAGE_SUPPORTS_GC 2
2246 // #define OBJC_IMAGE_GC_ONLY 4
2248 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
2249 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
2250 uint32_t flags = E::get32(contents[1]);
2251 if ( (flags & 4) == 4 )
2252 fObjConstraint = ObjectFile::Reader::kObjcGC;
2253 else if ( (flags & 2) == 2 )
2254 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
2255 else
2256 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
2257 if ( (flags & 1) == 1 )
2258 fReplacementClasses = true;
2259 // don't make atom for this section
2260 atomSize = sect->size();
2261 suppress = true;
2263 else {
2264 warning("can't parse __OBJC/__image_info section in %s", fPath);
2267 // special case constant NS/CFString literals and make an atom out of each one
2268 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
2269 atomSize = 4 * sizeof(pint_t);
2271 break;
2273 if ( atomSize != 0 ) {
2274 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
2275 pint_t atomAddr = sect->addr() + sectOffset;
2276 // add if not already an atom at that address
2277 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
2278 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
2279 if ( !suppress )
2280 fAtoms.push_back(newAtom);
2281 fAddrToAtom[atomAddr] = newAtom->redirectTo();
2287 // add all c-string anonymous atoms
2288 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2289 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
2290 uint32_t stringLen;
2291 pint_t stringAddr;
2292 BaseAtom* mostAlignedEmptyString = NULL;
2293 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
2294 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
2295 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
2296 stringAddr = sect->addr() + sectOffset;
2297 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
2298 // add if not already a non-zero length atom at that address
2299 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(stringAddr);
2300 if ( (pos == fAddrToAtom.end()) || (pos->second->getSize() == 0) ) {
2301 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
2302 if ( stringLen == 1 ) {
2303 // because of padding it may look like there are lots of empty strings, keep track of all
2304 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
2305 // record empty string with greatest alignment requirement
2306 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
2307 if ( (mostAlignedEmptyString == NULL)
2308 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
2309 mostAlignedEmptyString = newAtom;
2310 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
2313 else {
2314 fAtoms.push_back(newAtom);
2315 fAddrToAtom[stringAddr] = newAtom;
2319 // map all uses of empty strings to the most aligned one
2320 if ( mostAlignedEmptyString != NULL ) {
2321 // make most aligned atom a real atom
2322 fAtoms.push_back(mostAlignedEmptyString);
2323 // map all other empty atoms to this one
2324 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
2325 fAddrToAtom[it->first] = mostAlignedEmptyString;
2331 // sort all atoms so far by address and section
2332 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2334 //fprintf(stderr, "sorted atoms:\n");
2335 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
2336 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
2338 // create atoms to cover any non-debug ranges not handled above
2339 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2340 pint_t sectionStartAddr = sect->addr();
2341 pint_t sectionEndAddr = sect->addr() + sect->size();
2342 // don't set follow-on atoms in __eh_frame section
2343 const bool setFollowOnAtom = !canScatterAtoms() && (sect != fehFrameSection);
2344 if ( sect->size() != 0 ) {
2345 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
2346 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
2347 fDebugInfo = kDebugInfoDwarf;
2348 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
2349 fDwarfDebugInfoSect = sect;
2350 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
2351 fDwarfDebugAbbrevSect = sect;
2352 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
2353 fDwarfDebugLineSect = sect;
2354 else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
2355 fDwarfDebugStringSect = sect;
2357 else {
2358 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
2359 throw "object file contains old DWARF debug info - rebuild with newer compiler";
2361 uint8_t type (sect->flags() & SECTION_TYPE);
2362 switch ( type ) {
2363 case S_REGULAR:
2364 case S_ZEROFILL:
2365 case S_COALESCED:
2366 // if there is not an atom already at the start of this section, add an anonymous one
2367 pint_t previousAtomAddr = 0;
2368 BaseAtom* previousAtom = NULL;
2369 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
2370 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
2371 fAddrToAtom[sect->addr()] = newAtom;
2372 fAtoms.push_back(newAtom);
2373 previousAtomAddr = sectionStartAddr;
2374 previousAtom = newAtom;
2375 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2377 // calculate size of all atoms in this section and add follow-on references
2378 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2379 BaseAtom* atom = (BaseAtom*)(*it);
2380 pint_t atomAddr = atom->getObjectAddress();
2381 if ( atom->getSectionRecord() == sect ) {
2382 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
2383 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
2384 previousAtom->setSize(atomAddr - previousAtomAddr);
2385 if ( setFollowOnAtom && (atom != previousAtom) )
2386 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
2388 previousAtomAddr = atomAddr;
2389 previousAtom = atom;
2392 if ( previousAtom != NULL ) {
2393 // set last atom in section
2394 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
2396 break;
2402 // check for object file that defines no objc classes, but uses objc classes
2403 // check for dtrace provider info
2404 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
2405 const macho_nlist<P>& sym = fSymbols[i];
2406 if ( (sym.n_type() & N_STAB) == 0 ) {
2407 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
2408 const char* undefinedName = &fStrings[sym.n_strx()];
2409 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
2410 fAppleObjc = true;
2412 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
2413 if ( strchr(undefinedName, '$') != NULL ) {
2414 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
2415 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
2416 // is extra provider info
2417 fDtraceProviderInfo.push_back(undefinedName);
2425 // add relocation based references to sections that have atoms with pending names
2426 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2427 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
2428 addReferencesForSection(sect);
2431 // update any anonymous atoms that need references built in order to name themselves
2432 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
2433 (*it)->resolveName();
2436 // add relocation based references to other sections
2437 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2438 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
2439 addReferencesForSection(sect);
2442 // add objective-c references
2443 if ( fAppleObjc ) {
2444 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2445 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
2446 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
2447 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
2448 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
2449 if ( classRef->getFixUpOffset() == 0 ) {
2450 const char* classStr = classRef->getTargetName();
2451 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
2452 const char* className;
2453 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
2454 new Reference<A>(A::kNoFixUp, ao, className, 0);
2462 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
2463 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
2464 AnonymousAtom<A>* localNonLazy = *it;
2465 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
2466 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
2467 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
2471 // add personality references to CIEs
2472 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2473 if ( it->personality.offsetInFDE != 0 )
2474 addCiePersonalityReference(fAddrToAtom[it->cieAddress], it->personality.offsetInFDE, it->personality.encodingOfAddress);
2477 // add all references for FDEs, including implicit group references
2478 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2479 AtomAndOffset funcAO = this->findAtomAndOffset(it->function.address);
2480 if ( funcAO.offset != 0 )
2481 warning("FDE does not point to start of function %s\n", funcAO.atom->getDisplayName());
2482 AtomAndOffset fdeAO = this->findAtomAndOffset(it->fdeAddress);
2483 if ( fdeAO.offset != 0 )
2484 warning("FDE does start its own atom %s\n", funcAO.atom->getDisplayName());
2485 AtomAndOffset cieAO = this->findAtomAndOffset(it->cie.address);
2486 if ( cieAO.offset != 0 )
2487 warning("CIE does start its own atom %s\n", cieAO.atom->getDisplayName());
2488 AtomAndOffset lsdaAO;
2489 if ( it->lsda.address != 0 ) {
2490 lsdaAO = this->findAtomAndOffset(it->lsda.address);
2491 if ( lsdaAO.offset != 0 )
2492 warning("LSDA does start its own atom %s\n", lsdaAO.atom->getDisplayName());
2495 // add reference from FDE to CIE
2496 AtomAndOffset cieInfdeAO = AtomAndOffset(fdeAO.atom, it->cie.offsetInFDE);
2497 new Reference<A>(A::kPointerDiff32, cieInfdeAO, cieAO, cieInfdeAO);
2499 // add reference from FDE to function
2500 addFdeReference(it->function.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->function.offsetInFDE), funcAO);
2502 // add reference from FDE to LSDA
2503 if ( it->lsda.address != 0 ) {
2504 addFdeReference(it->lsda.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->lsda.offsetInFDE), lsdaAO);
2507 // FDE is in group lead by function atom
2508 new Reference<A>(A::kGroupSubordinate, funcAO, fdeAO);
2510 // LSDA is in group lead by function atom
2511 if ( it->lsda.address != 0 ) {
2512 new Reference<A>(A::kGroupSubordinate, funcAO, lsdaAO);
2513 // add back reference from LSDA to owning function
2514 new Reference<A>(A::kNoFixUp, lsdaAO, funcAO);
2517 // compute compact encoding for this FDE
2518 if ( fOptions.fAddCompactUnwindEncoding ) {
2519 ((BaseAtom*)(funcAO.atom))->setCompactUnwindEncoding(it->fdeAddress);
2520 // add reference from function atom to personality function
2521 // the only reference a CIE can have is the reference to the personality function
2522 std::vector<class ObjectFile::Reference*>& cieRefs = cieAO.atom->getReferences();
2523 if ( cieRefs.size() == 1 ) {
2524 new Reference<A>((typename A::ReferenceKinds)((BaseAtom*)(funcAO.atom))->getPersonalityReferenceKind(),
2525 funcAO, cieRefs[0]->getTargetName(), 0);
2530 // add command line aliases
2531 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
2532 BaseAtom* target = this->findAtomByName(it->realName);
2533 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
2534 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
2537 // add dtrace probe locations
2538 if ( fHasDTraceProbes ) {
2539 for (uint32_t i=0; i < fSymbolCount; ++i) {
2540 const macho_nlist<P>& sym = fSymbols[i];
2541 if ( (sym.n_type() & N_STAB) == 0 ) {
2542 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
2543 const char* symbolName = &fStrings[sym.n_strx()];
2544 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
2545 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
2546 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
2553 // turn indirect symbols into SymbolAliasAtom
2554 if ( fHaveIndirectSymbols ) {
2555 for (uint32_t i=0; i < fSymbolCount; ++i) {
2556 const macho_nlist<P>& sym = fSymbols[i];
2557 if ( (sym.n_type() & N_STAB) == 0 ) {
2558 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
2559 const char* aliasName = &fStrings[sym.n_strx()];
2560 const char* targetName = &fStrings[sym.n_value()];
2561 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
2562 BaseAtom* target = this->findAtomByName(targetName);
2563 // only currently support N_INDR based aliases to something in the same .o file
2564 if ( target != NULL ) {
2565 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
2566 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
2573 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
2574 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
2577 // add translation unit info from dwarf
2578 uint64_t stmtList;
2579 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2580 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
2581 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2582 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
2583 // if can't parse dwarf, warn and give up
2584 fDwarfTranslationUnitFile = NULL;
2585 fDwarfTranslationUnitDir = NULL;
2586 warning("can't parse dwarf compilation unit info in %s", this->getPath());
2587 fDebugInfo = kDebugInfoNone;
2592 // add line number info to atoms from dwarf
2593 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2594 // file with just data will have no __debug_line info
2595 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
2596 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2597 // validate stmt_list
2598 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
2599 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
2600 if ( debug_line != NULL ) {
2601 struct line_reader_data* lines = line_open(&debug_line[stmtList],
2602 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
2603 struct line_info result;
2604 ObjectFile::Atom* curAtom = NULL;
2605 uint32_t curAtomOffset = 0;
2606 uint32_t curAtomAddress = 0;
2607 uint32_t curAtomSize = 0;
2608 if ( lines != NULL ) {
2609 while ( line_next (lines, &result, line_stop_pc) ) {
2610 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
2611 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
2612 // work around weird debug line table compiler generates if no functions in __text section
2613 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
2614 continue;
2615 // for performance, see if in next pc is in current atom
2616 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
2617 curAtomOffset = result.pc - curAtomAddress;
2619 // or pc at end of current atom
2620 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
2621 curAtomOffset = result.pc - curAtomAddress;
2623 else {
2624 // do slow look up of atom by address
2625 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
2626 curAtom = ao.atom;
2627 if ( curAtom == NULL )
2628 break; // file has line info but no functions
2629 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
2630 // a one line function can be returned by line_next() as one entry with pc at end of blob
2631 // look for alt atom starting at end of previous atom
2632 uint32_t previousEnd = curAtomAddress+curAtomSize;
2633 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
2634 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
2635 curAtom = alt.atom;
2636 curAtomOffset = alt.offset;
2637 curAtomAddress = previousEnd - alt.offset;
2638 curAtomSize = curAtom->getSize();
2640 else {
2641 curAtomOffset = ao.offset;
2642 curAtomAddress = result.pc - ao.offset;
2643 curAtomSize = curAtom->getSize();
2646 else {
2647 curAtomOffset = ao.offset;
2648 curAtomAddress = result.pc - ao.offset;
2649 curAtomSize = curAtom->getSize();
2652 const char* filename;
2653 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2654 if ( pos == fDwarfIndexToFile.end() ) {
2655 filename = line_file(lines, result.file);
2656 fDwarfIndexToFile[result.file] = filename;
2658 else {
2659 filename = pos->second;
2661 ObjectFile::LineInfo info;
2662 info.atomOffset = curAtomOffset;
2663 info.fileName = filename;
2664 info.lineNumber = result.line;
2665 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2666 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2667 ((BaseAtom*)curAtom)->addLineInfo(info);
2668 if ( result.end_of_sequence ) {
2669 curAtom = NULL;
2672 line_free(lines);
2675 else {
2676 warning("could not parse dwarf line number info in %s", this->getPath());
2682 // if no dwarf, try processing stabs debugging info
2683 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2684 // scan symbol table for stabs entries
2685 fStabs.reserve(fSymbolCount); // reduce re-allocations
2686 BaseAtom* currentAtom = NULL;
2687 pint_t currentAtomAddress = 0;
2688 enum { start, inBeginEnd, inFun } state = start;
2689 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2690 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2691 bool useStab = true;
2692 uint8_t type = sym->n_type();
2693 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2694 if ( (type & N_STAB) != 0 ) {
2695 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
2696 Stab stab;
2697 stab.atom = NULL;
2698 stab.type = type;
2699 stab.other = sym->n_sect();
2700 stab.desc = sym->n_desc();
2701 stab.value = sym->n_value();
2702 stab.string = NULL;
2703 switch (state) {
2704 case start:
2705 switch (type) {
2706 case N_BNSYM:
2707 // beginning of function block
2708 state = inBeginEnd;
2709 // fall into case to lookup atom by addresss
2710 case N_LCSYM:
2711 case N_STSYM:
2712 currentAtomAddress = sym->n_value();
2713 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2714 if ( currentAtom != NULL ) {
2715 stab.atom = currentAtom;
2716 stab.string = symString;
2718 else {
2719 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
2720 (uint64_t)sym->n_value(), path);
2722 break;
2723 case N_SO:
2724 case N_OSO:
2725 case N_OPT:
2726 case N_LSYM:
2727 case N_RSYM:
2728 case N_PSYM:
2729 // not associated with an atom, just copy
2730 stab.string = symString;
2731 break;
2732 case N_GSYM:
2734 // n_value field is NOT atom address ;-(
2735 // need to find atom by name match
2736 const char* colon = strchr(symString, ':');
2737 if ( colon != NULL ) {
2738 // build underscore leading name
2739 int nameLen = colon - symString;
2740 char symName[nameLen+2];
2741 strlcpy(&symName[1], symString, nameLen+1);
2742 symName[0] = '_';
2743 symName[nameLen+1] = '\0';
2744 currentAtom = findAtomByName(symName);
2745 if ( currentAtom != NULL ) {
2746 stab.atom = currentAtom;
2747 stab.string = symString;
2750 else {
2751 // might be a debug-note without trailing :G()
2752 currentAtom = findAtomByName(symString);
2753 if ( currentAtom != NULL ) {
2754 stab.atom = currentAtom;
2755 stab.string = symString;
2758 if ( stab.atom == NULL ) {
2759 // ld_classic added bogus GSYM stabs for old style dtrace probes
2760 if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
2761 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
2762 useStab = false;
2764 break;
2766 case N_FUN:
2767 // old style stabs without BNSYM
2768 state = inFun;
2769 currentAtomAddress = sym->n_value();
2770 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2771 if ( currentAtom != NULL ) {
2772 stab.atom = currentAtom;
2773 stab.string = symString;
2775 else {
2776 warning("can't find atom for stabs FUN at %08llX in %s",
2777 (uint64_t)currentAtomAddress, path);
2779 break;
2780 case N_SOL:
2781 case N_SLINE:
2782 stab.string = symString;
2783 // old stabs
2784 break;
2785 case N_BINCL:
2786 case N_EINCL:
2787 case N_EXCL:
2788 stab.string = symString;
2789 // -gfull built .o file
2790 break;
2791 default:
2792 warning("unknown stabs type 0x%X in %s", type, path);
2794 break;
2795 case inBeginEnd:
2796 stab.atom = currentAtom;
2797 switch (type) {
2798 case N_ENSYM:
2799 state = start;
2800 currentAtom = NULL;
2801 break;
2802 case N_LCSYM:
2803 case N_STSYM:
2805 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2806 if ( nestedAtom != NULL ) {
2807 stab.atom = nestedAtom;
2808 stab.string = symString;
2810 else {
2811 warning("can't find atom for stabs 0x%X at %08llX in %s",
2812 type, (uint64_t)sym->n_value(), path);
2814 break;
2816 case N_LBRAC:
2817 case N_RBRAC:
2818 case N_SLINE:
2819 // adjust value to be offset in atom
2820 stab.value -= currentAtomAddress;
2821 default:
2822 stab.string = symString;
2823 break;
2825 break;
2826 case inFun:
2827 switch (type) {
2828 case N_FUN:
2829 if ( sym->n_sect() != 0 ) {
2830 // found another start stab, must be really old stabs...
2831 currentAtomAddress = sym->n_value();
2832 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2833 if ( currentAtom != NULL ) {
2834 stab.atom = currentAtom;
2835 stab.string = symString;
2837 else {
2838 warning("can't find atom for stabs FUN at %08llX in %s",
2839 (uint64_t)currentAtomAddress, path);
2842 else {
2843 // found ending stab, switch back to start state
2844 stab.string = symString;
2845 stab.atom = currentAtom;
2846 state = start;
2847 currentAtom = NULL;
2849 break;
2850 case N_LBRAC:
2851 case N_RBRAC:
2852 case N_SLINE:
2853 // adjust value to be offset in atom
2854 stab.value -= currentAtomAddress;
2855 stab.atom = currentAtom;
2856 break;
2857 case N_SO:
2858 stab.string = symString;
2859 state = start;
2860 break;
2861 default:
2862 stab.atom = currentAtom;
2863 stab.string = symString;
2864 break;
2866 break;
2868 // add to list of stabs for this .o file
2869 if ( useStab )
2870 fStabs.push_back(stab);
2875 #if 0
2876 // special case precompiled header .o file (which has no content) to have one empty atom
2877 if ( fAtoms.size() == 0 ) {
2878 int pathLen = strlen(path);
2879 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2880 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2881 //phony->fSynthesizedName = ".gch.o";
2882 fAtoms.push_back(phony);
2885 #endif
2887 // sort all atoms by address
2888 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2890 // set ordinal and sort references in each atom
2891 uint32_t index = fOrdinalBase;
2892 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2893 BaseAtom* atom = (BaseAtom*)(*it);
2894 atom->setOrdinal(index++);
2895 atom->sortReferences();
2900 template <typename A>
2901 const macho_section<typename A::P>* Reader<A>::getSectionForAddress(pint_t addr)
2903 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2904 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) )
2905 return sect;
2907 throwf("section not found for address 0x%08llX", (uint64_t)addr);
2910 template <typename A>
2911 ObjectFile::Atom* Reader<A>::getFunctionAtomFromFDEAddress(pint_t addr)
2913 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2914 if ( it->fdeAddress == addr ) {
2915 return findAtomAndOffset(it->function.address).atom;
2918 // CIEs won't be in fFDEInfos
2919 return NULL;
2922 template <typename A>
2923 ObjectFile::Atom* Reader<A>::getFunctionAtomFromLSDAAddress(pint_t addr)
2925 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2926 if ( it->lsda.address == addr ) {
2927 return findAtomAndOffset(it->function.address).atom;
2930 return NULL;
2934 template <>
2935 void ObjectFileAddressSpace<x86_64>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
2937 // mach-o x86_64 is different, the content of a section with a relocation is the addend
2938 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + sect->reloff());
2939 const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
2940 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2941 std::map<uint32_t,uint64_t>::iterator pos;
2942 switch ( reloc->r_type() ) {
2943 case X86_64_RELOC_UNSIGNED:
2944 pos = map.find(reloc->r_address());
2945 if ( pos != map.end() )
2946 pos->second += fReader.fSymbols[reloc->r_symbolnum()].n_value();
2947 else
2948 map[reloc->r_address()] = fReader.fSymbols[reloc->r_symbolnum()].n_value();
2949 break;
2950 case X86_64_RELOC_SUBTRACTOR:
2951 map[reloc->r_address()] = -fReader.fSymbols[reloc->r_symbolnum()].n_value();
2952 break;
2953 case X86_64_RELOC_GOT:
2954 // there is no good address to return here.
2955 // GOT slots are synthsized by the linker
2956 // this is used for the reference to the personality function in CIEs
2957 map[reloc->r_address()] = 0;
2958 break;
2959 default:
2960 fprintf(stderr, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc->r_address());
2961 break;
2966 template <typename A>
2967 void ObjectFileAddressSpace<A>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
2969 // in all architectures except x86_64, the section contents are already fixed up to point
2970 // to content in the same object file.
2973 template <>
2974 uint64_t ObjectFileAddressSpace<x86_64>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
2976 // mach-o x86_64 is different, the content of a section with a relocation is the addend
2977 uint64_t result = 0;
2978 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + relocsOffset);
2979 const macho_relocation_info<P>* relocsEnd = &relocs[relocsCount];
2980 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2981 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address());
2982 if ( reloc->r_address() == sectOffset ) {
2983 switch ( reloc->r_type() ) {
2984 case X86_64_RELOC_UNSIGNED:
2985 result += fReader.fSymbols[reloc->r_symbolnum()].n_value();
2986 break;
2987 case X86_64_RELOC_SUBTRACTOR:
2988 result -= fReader.fSymbols[reloc->r_symbolnum()].n_value();
2989 break;
2990 case X86_64_RELOC_GOT:
2991 // there is no good address to return here.
2992 // GOT slots are synthsized by the linker
2993 // this is used for the reference to the personality function in CIEs
2994 result = 0;
2995 break;
2996 default:
2997 fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset, reloc->r_type(), reloc->r_symbolnum());
2998 break;
3002 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result);
3003 return result;
3006 template <typename A>
3007 typename A::P::uint_t ObjectFileAddressSpace<A>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
3009 // in all architectures except x86_64, the section contents are already fixed up to point
3010 // to content in the same object file.
3011 return 0;
3016 // FSF exception handling Pointer-Encoding constants
3017 // Used in CFI augmentation by gcc compiler
3018 enum {
3019 DW_EH_PE_ptr = 0x00,
3020 DW_EH_PE_uleb128 = 0x01,
3021 DW_EH_PE_udata2 = 0x02,
3022 DW_EH_PE_udata4 = 0x03,
3023 DW_EH_PE_udata8 = 0x04,
3024 DW_EH_PE_signed = 0x08,
3025 DW_EH_PE_sleb128 = 0x09,
3026 DW_EH_PE_sdata2 = 0x0A,
3027 DW_EH_PE_sdata4 = 0x0B,
3028 DW_EH_PE_sdata8 = 0x0C,
3029 DW_EH_PE_absptr = 0x00,
3030 DW_EH_PE_pcrel = 0x10,
3031 DW_EH_PE_textrel = 0x20,
3032 DW_EH_PE_datarel = 0x30,
3033 DW_EH_PE_funcrel = 0x40,
3034 DW_EH_PE_aligned = 0x50,
3035 DW_EH_PE_indirect = 0x80,
3036 DW_EH_PE_omit = 0xFF
3039 template <>
3040 void Reader<x86_64>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
3042 if ( encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4) )
3043 throw "unexpected personality encoding in CIE";
3045 // walk relocs looking for reloc in this CIE
3046 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
3047 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
3048 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
3049 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3050 if ( reloc->r_address() == sectOffset ) {
3051 switch ( reloc->r_type() ) {
3052 case X86_64_RELOC_GOT:
3053 if ( !reloc->r_extern() )
3054 throw "GOT reloc not extern for personality function";
3055 new Reference<x86_64>(x86_64::kPCRel32GOT, AtomAndOffset(cieAtom, offsetInCIE), &fStrings[fSymbols[reloc->r_symbolnum()].n_strx()], 4);
3056 return;
3057 default:
3058 throw "expected GOT reloc for personality function";
3062 throw "personality function not found for CIE";
3065 template <>
3066 bool Reader<ppc>::isSectDiffReloc(uint8_t r_type)
3068 switch ( r_type ) {
3069 case PPC_RELOC_LOCAL_SECTDIFF:
3070 case PPC_RELOC_SECTDIFF:
3071 return true;
3073 return false;
3076 template <>
3077 bool Reader<ppc64>::isSectDiffReloc(uint8_t r_type)
3079 switch ( r_type ) {
3080 case PPC_RELOC_LOCAL_SECTDIFF:
3081 case PPC_RELOC_SECTDIFF:
3082 return true;
3084 return false;
3087 template <>
3088 bool Reader<x86>::isSectDiffReloc(uint8_t r_type)
3090 switch ( r_type ) {
3091 case GENERIC_RELOC_LOCAL_SECTDIFF:
3092 case GENERIC_RELOC_SECTDIFF:
3093 return true;
3095 return false;
3098 template <>
3099 bool Reader<arm>::isSectDiffReloc(uint8_t r_type)
3101 switch ( r_type ) {
3102 case ARM_RELOC_LOCAL_SECTDIFF:
3103 case ARM_RELOC_SECTDIFF:
3104 return true;
3106 return false;
3109 template <typename A>
3110 void Reader<A>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
3112 if ( (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4)) && (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel)) )
3113 throw "unexpected personality encoding in CIE";
3115 // walk relocs looking for personality reloc in this CIE
3116 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
3117 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
3118 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
3119 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3120 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3121 // ignore
3123 else {
3124 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3125 if ( sreloc->r_address() == sectOffset ) {
3126 if ( isSectDiffReloc(sreloc->r_type()) ) {
3127 // r_value is address of non-lazy-pointer to personality function
3128 new Reference<A>(A::kPointerDiff32, AtomAndOffset(cieAtom, offsetInCIE), AtomAndOffset(cieAtom, offsetInCIE),
3129 findAtomAndOffset(sreloc->r_value()));
3130 return;
3135 throw "can't find relocation for personality in CIE";
3138 template <typename A>
3139 void Reader<A>::addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target)
3141 if ( (encoding & 0xF0) != DW_EH_PE_pcrel )
3142 throw "unsupported encoding in FDE";
3143 Kinds kind = A::kNoFixUp;
3144 switch ( encoding & 0xF ) {
3145 case DW_EH_PE_ptr:
3146 kind = A::kPointerDiff;
3147 break;
3148 case DW_EH_PE_sdata4:
3149 kind = A::kPointerDiff32;
3150 break;
3151 default:
3152 throw "unsupported encoding in FDE";
3154 new Reference<A>(kind, inFDE, inFDE, target);
3157 template <typename A>
3158 typename A::P::uint_t ObjectFileAddressSpace<A>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
3160 pint_t startAddr = addr;
3161 pint_t p = addr;
3162 pint_t result;
3164 // first get value
3165 switch (encoding & 0x0F) {
3166 case DW_EH_PE_ptr:
3167 result = getP(addr);
3168 p += sizeof(pint_t);
3169 addr = (pint_t)p;
3170 break;
3171 case DW_EH_PE_uleb128:
3172 result = getULEB128(addr, end);
3173 break;
3174 case DW_EH_PE_udata2:
3175 result = get16(addr);
3176 p += 2;
3177 addr = (pint_t)p;
3178 break;
3179 case DW_EH_PE_udata4:
3180 result = get32(addr);
3181 p += 4;
3182 addr = (pint_t)p;
3183 break;
3184 case DW_EH_PE_udata8:
3185 result = get64(addr);
3186 p += 8;
3187 addr = (pint_t)p;
3188 break;
3189 case DW_EH_PE_sleb128:
3190 result = getSLEB128(addr, end);
3191 break;
3192 case DW_EH_PE_sdata2:
3193 result = (int16_t)get16(addr);
3194 p += 2;
3195 addr = (pint_t)p;
3196 break;
3197 case DW_EH_PE_sdata4:
3198 result = (int32_t)get32(addr);
3199 p += 4;
3200 addr = (pint_t)p;
3201 break;
3202 case DW_EH_PE_sdata8:
3203 result = get64(addr);
3204 p += 8;
3205 addr = (pint_t)p;
3206 break;
3207 default:
3208 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3211 // then add relative offset
3212 switch ( encoding & 0x70 ) {
3213 case DW_EH_PE_absptr:
3214 // do nothing
3215 break;
3216 case DW_EH_PE_pcrel:
3217 result += startAddr;
3218 break;
3219 case DW_EH_PE_textrel:
3220 throw "DW_EH_PE_textrel pointer encoding not supported";
3221 break;
3222 case DW_EH_PE_datarel:
3223 throw "DW_EH_PE_datarel pointer encoding not supported";
3224 break;
3225 case DW_EH_PE_funcrel:
3226 throw "DW_EH_PE_funcrel pointer encoding not supported";
3227 break;
3228 case DW_EH_PE_aligned:
3229 throw "DW_EH_PE_aligned pointer encoding not supported";
3230 break;
3231 default:
3232 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3233 break;
3236 if ( encoding & DW_EH_PE_indirect )
3237 result = getP(result);
3239 return result;
3242 template <>
3243 uint32_t SymbolAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3245 pint_t lsda;
3246 pint_t personality;
3247 char warningBuffer[1024];
3248 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
3249 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3250 if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
3251 //if ( fOwner.fOptions.fForDyld )
3252 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3253 //else
3254 if ( fOwner.fOptions.fWarnCompactUnwind )
3255 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
3257 return result;
3260 template <>
3261 uint32_t SymbolAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3263 pint_t lsda;
3264 pint_t personality;
3265 char warningBuffer[1024];
3266 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
3267 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3268 if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
3269 //if ( fOwner.fOptions.fForDyld )
3270 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3271 //else
3272 if ( fOwner.fOptions.fWarnCompactUnwind )
3273 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
3275 return result;
3278 template <>
3279 uint32_t SymbolAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3281 // compact encoding not supported for ppc
3282 return 0;
3285 template <>
3286 uint32_t SymbolAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3288 // compact encoding not supported for ppc64
3289 return 0;
3292 template <>
3293 uint32_t SymbolAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3295 // compact encoding not supported for arm
3296 return 0;
3300 template <typename A>
3301 uint8_t SymbolAtom<A>::getLSDAReferenceKind() const
3303 return A::kGroupSubordinate;
3306 template <>
3307 uint8_t SymbolAtom<x86_64>::getPersonalityReferenceKind() const
3309 return x86_64::kGOTNoFixUp;
3312 template <>
3313 uint8_t SymbolAtom<x86>::getPersonalityReferenceKind() const
3315 return x86::kNoFixUp;
3318 template <typename A>
3319 uint8_t SymbolAtom<A>::getPersonalityReferenceKind() const
3321 // only used with architectures that support compact unwinding
3322 return 0;
3326 template <>
3327 uint32_t AnonymousAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3329 pint_t lsda;
3330 pint_t personality;
3331 char warningBuffer[1024];
3332 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
3333 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3334 if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
3335 //if ( fOwner.fOptions.fForDyld )
3336 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3337 //else
3338 if ( fOwner.fOptions.fWarnCompactUnwind )
3339 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3341 return result;
3344 template <>
3345 uint32_t AnonymousAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3347 pint_t lsda;
3348 pint_t personality;
3349 char warningBuffer[1024];
3350 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
3351 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3352 if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
3353 //if ( fOwner.fOptions.fForDyld )
3354 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3355 //else
3356 if ( fOwner.fOptions.fWarnCompactUnwind )
3357 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3359 return result;
3362 template <>
3363 uint32_t AnonymousAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3365 // compact encoding not supported for ppc
3366 return 0;
3369 template <>
3370 uint32_t AnonymousAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3372 // compact encoding not supported for ppc64
3373 return 0;
3376 template <>
3377 uint32_t AnonymousAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3379 // compact encoding not supported for arm
3380 return 0;
3384 template <typename A>
3385 uint8_t AnonymousAtom<A>::getLSDAReferenceKind() const
3387 return A::kGroupSubordinate;
3390 template <>
3391 uint8_t AnonymousAtom<x86_64>::getPersonalityReferenceKind() const
3393 return x86_64::kGOTNoFixUp;
3396 template <>
3397 uint8_t AnonymousAtom<x86>::getPersonalityReferenceKind() const
3399 return x86::kNoFixUp;
3402 template <typename A>
3403 uint8_t AnonymousAtom<A>::getPersonalityReferenceKind() const
3405 // only used with architectures that support compact unwinding
3406 return 0;
3415 template <>
3416 void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
3418 switch (cpusubtype) {
3419 case CPU_SUBTYPE_POWERPC_ALL:
3420 case CPU_SUBTYPE_POWERPC_750:
3421 case CPU_SUBTYPE_POWERPC_7400:
3422 case CPU_SUBTYPE_POWERPC_7450:
3423 case CPU_SUBTYPE_POWERPC_970:
3424 fCpuConstraint = cpusubtype;
3425 break;
3426 default:
3427 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3428 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
3429 break;
3433 template <>
3434 void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
3436 switch (cpusubtype) {
3437 case CPU_SUBTYPE_ARM_ALL:
3438 case CPU_SUBTYPE_ARM_V4T:
3439 case CPU_SUBTYPE_ARM_V5TEJ:
3440 case CPU_SUBTYPE_ARM_V6:
3441 case CPU_SUBTYPE_ARM_XSCALE:
3442 case CPU_SUBTYPE_ARM_V7:
3443 fCpuConstraint = cpusubtype;
3444 break;
3445 default:
3446 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3447 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
3448 break;
3452 template <typename A>
3453 void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
3455 // no cpu sub types for this architecture
3458 template <>
3459 uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
3461 switch ( previous ) {
3462 case CPU_SUBTYPE_POWERPC_ALL:
3463 return fCpuConstraint;
3464 break;
3465 case CPU_SUBTYPE_POWERPC_750:
3466 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
3467 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
3468 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3469 return fCpuConstraint;
3470 break;
3471 case CPU_SUBTYPE_POWERPC_7400:
3472 case CPU_SUBTYPE_POWERPC_7450:
3473 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3474 return fCpuConstraint;
3475 break;
3476 case CPU_SUBTYPE_POWERPC_970:
3477 // G5 can run everything
3478 break;
3479 default:
3480 throw "Unhandled PPC cpu subtype!";
3481 break;
3483 return previous;
3488 template <>
3489 uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
3491 switch (previous) {
3492 case CPU_SUBTYPE_ARM_ALL:
3493 return fCpuConstraint;
3494 break;
3495 case CPU_SUBTYPE_ARM_V5TEJ:
3496 // v6, v7, and xscale are more constrained than previous file (v5), so use it
3497 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
3498 || (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3499 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3500 return fCpuConstraint;
3501 break;
3502 case CPU_SUBTYPE_ARM_V4T:
3503 // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
3504 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3505 || (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
3506 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
3507 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3508 return fCpuConstraint;
3509 break;
3510 case CPU_SUBTYPE_ARM_V6:
3511 // v6 can run everything except xscale and v7
3512 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3513 throw "can't mix xscale and v6 code";
3514 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3515 return fCpuConstraint;
3516 break;
3517 case CPU_SUBTYPE_ARM_XSCALE:
3518 // xscale can run everything except v6 and v7
3519 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
3520 throw "can't mix xscale and v6 code";
3521 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3522 throw "can't mix xscale and v7 code";
3523 break;
3524 case CPU_SUBTYPE_ARM_V7:
3525 // v7 can run everything except xscale
3526 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3527 throw "can't mix xscale and v7 code";
3528 break;
3529 default:
3530 throw "Unhandled ARM cpu subtype!";
3532 return previous;
3535 template <typename A>
3536 uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
3538 // no cpu sub types for this architecture
3539 return current;
3542 template <typename A>
3543 void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
3545 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
3546 // a matching provider name, add a by-name kDtraceTypeReference at probe site
3547 const char* dollar = strchr(providerName, '$');
3548 if ( dollar != NULL ) {
3549 int providerNameLen = dollar-providerName+1;
3550 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
3551 const char* typeDollar = strchr(*it, '$');
3552 if ( typeDollar != NULL ) {
3553 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
3554 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
3562 template <>
3563 void Reader<x86_64>::validSectionType(uint8_t type)
3565 switch ( type ) {
3566 case S_SYMBOL_STUBS:
3567 throw "symbol_stub sections not valid in x86_64 object files";
3568 case S_LAZY_SYMBOL_POINTERS:
3569 throw "lazy pointer sections not valid in x86_64 object files";
3570 case S_NON_LAZY_SYMBOL_POINTERS:
3571 throw "non lazy pointer sections not valid in x86_64 object files";
3575 template <typename A>
3576 void Reader<A>::validSectionType(uint8_t type)
3580 template <typename A>
3581 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
3583 if ( fDebugInfo == kDebugInfoDwarf ) {
3584 *dir = fDwarfTranslationUnitDir;
3585 *name = fDwarfTranslationUnitFile;
3586 return (fDwarfTranslationUnitFile != NULL);
3588 return false;
3591 template <typename A>
3592 BaseAtom* Reader<A>::findAtomByName(const char* name)
3594 // first search the more important atoms
3595 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
3596 const char* atomName = it->second->getName();
3597 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3598 return it->second;
3601 // try all atoms, because this might have been a tentative definition
3602 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
3603 BaseAtom* atom = (BaseAtom*)(*it);
3604 const char* atomName = atom->getName();
3605 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3606 return atom;
3609 return NULL;
3612 template <typename A>
3613 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
3615 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
3618 template <typename A>
3619 Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
3621 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
3624 template <typename A>
3625 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
3627 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
3630 template <typename A>
3631 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
3633 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
3636 template <typename A>
3637 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
3639 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3642 template <typename A>
3643 BaseAtom* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
3645 // add a group subordinate reference from function atom to its eh frame atom
3646 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
3647 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
3648 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
3649 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3650 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3651 new Reference<A>(A::kGroupSubordinate, funcAtom, ehAtom);
3652 return (BaseAtom*)funcAtom;
3656 template <>
3657 Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
3659 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3660 // instead check scope of target
3661 BaseAtom* target = findAtomByName(toName);
3662 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
3663 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
3664 else
3665 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3668 template <>
3669 Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
3671 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3672 // instead check scope of target
3673 const char* symbolName = &fStrings[toSymbol->n_strx()];
3674 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) {
3675 AtomAndOffset targetAO = findAtomAndOffsetForSection(toSymbol->n_value(), toSymbol->n_sect());
3676 targetAO.offset = toOffset;
3677 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), targetAO);
3679 else
3680 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
3684 template <>
3685 BaseAtom* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
3687 // add a group subordinate reference from function atom to its eh frame atom
3688 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
3689 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
3690 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
3691 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
3692 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3693 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
3694 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
3695 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3696 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3697 new Reference<x86_64>(x86_64::kGroupSubordinate, funcAtom, ehAtom);
3698 return (BaseAtom*)funcAtom;
3701 warning("can't find matching function for eh symbol %s", ehName);
3702 return NULL;
3705 template <typename A>
3706 AtomAndOffset Reader<A>::findAtomAndOffsetForSection(pint_t addr, unsigned int expectedSectionIndex)
3708 AtomAndOffset ao = findAtomAndOffset(addr);
3709 if ( ao.atom != NULL ) {
3710 if ( ((BaseAtom*)(ao.atom))->getSectionIndex() == expectedSectionIndex )
3711 return ao;
3713 // The atom found is not in the section expected.
3714 // This probably means there was a label at the end of the section.
3715 // Do a slow sequential lookup
3716 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); ++it) {
3717 BaseAtom* atom = *it;
3718 if ( atom->getSectionIndex() == expectedSectionIndex ) {
3719 pint_t objAddr = atom->getObjectAddress();
3720 if ( (objAddr == addr) || ((objAddr < addr) && (objAddr+atom->getSize() > addr)) ) {
3721 return AtomAndOffset(atom, addr-atom->getObjectAddress());
3725 // no atom found that matched section, fall back to one orginally found
3726 return ao;
3729 template <typename A>
3730 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
3732 // STL has no built-in for "find largest key that is same or less than"
3733 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
3734 // if no atoms up to this address return none found
3735 if ( it == fAddrToAtom.begin() )
3736 return AtomAndOffset(NULL);
3737 // otherwise upper_bound gets us next key, so we back up one
3738 --it;
3739 AtomAndOffset result;
3740 result.atom = it->second;
3741 result.offset = addr - it->first;
3742 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
3743 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
3744 return result;
3747 // "scattered" relocations enable you to offset into an atom past the end of it
3748 // baseAddr is the address of the target atom,
3749 // realAddr is the points into it
3750 template <typename A>
3751 AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
3753 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
3754 if ( it != fAddrToAtom.end() ) {
3755 AtomAndOffset result;
3756 result.atom = it->second;
3757 result.offset = realAddr - it->first;
3758 if ( result.atom->isThumb() )
3759 result.offset &= -2;
3760 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
3761 return result;
3763 // getting here means we have a scattered relocation to an address without a label
3764 // so, find the atom that contains the baseAddr, and offset from that to the readAddr
3765 AtomAndOffset result = findAtomAndOffset(baseAddr);
3766 result.offset += (realAddr-baseAddr);
3767 return result;
3771 /* Skip over a LEB128 value (signed or unsigned). */
3772 static void
3773 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
3775 while (*offset != end && **offset >= 0x80)
3776 (*offset)++;
3777 if (*offset != end)
3778 (*offset)++;
3781 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
3782 or error. On overflow, skip past the rest of the uleb128. */
3783 static uint64_t
3784 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
3786 uint64_t result = 0;
3787 int bit = 0;
3789 do {
3790 uint64_t b;
3792 if (*offset == end)
3793 return (uint64_t) -1;
3795 b = **offset & 0x7f;
3797 if (bit >= 64 || b << bit >> bit != b)
3798 result = (uint64_t) -1;
3799 else
3800 result |= b << bit, bit += 7;
3801 } while (*(*offset)++ >= 0x80);
3802 return result;
3806 /* Skip over a DWARF attribute of form FORM. */
3807 template <typename A>
3808 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
3809 uint8_t addr_size, bool dwarf64)
3811 int64_t sz=0;
3813 switch (form)
3815 case DW_FORM_addr:
3816 sz = addr_size;
3817 break;
3819 case DW_FORM_block2:
3820 if (end - *offset < 2)
3821 return false;
3822 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
3823 break;
3825 case DW_FORM_block4:
3826 if (end - *offset < 4)
3827 return false;
3828 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
3829 break;
3831 case DW_FORM_data2:
3832 case DW_FORM_ref2:
3833 sz = 2;
3834 break;
3836 case DW_FORM_data4:
3837 case DW_FORM_ref4:
3838 sz = 4;
3839 break;
3841 case DW_FORM_data8:
3842 case DW_FORM_ref8:
3843 sz = 8;
3844 break;
3846 case DW_FORM_string:
3847 while (*offset != end && **offset)
3848 ++*offset;
3849 case DW_FORM_data1:
3850 case DW_FORM_flag:
3851 case DW_FORM_ref1:
3852 sz = 1;
3853 break;
3855 case DW_FORM_block:
3856 sz = read_uleb128 (offset, end);
3857 break;
3859 case DW_FORM_block1:
3860 if (*offset == end)
3861 return false;
3862 sz = 1 + **offset;
3863 break;
3865 case DW_FORM_sdata:
3866 case DW_FORM_udata:
3867 case DW_FORM_ref_udata:
3868 skip_leb128 (offset, end);
3869 return true;
3871 case DW_FORM_strp:
3872 case DW_FORM_ref_addr:
3873 sz = 4;
3874 break;
3876 default:
3877 return false;
3879 if (end - *offset < sz)
3880 return false;
3881 *offset += sz;
3882 return true;
3885 template <typename A>
3886 const char* Reader<A>::getDwarfString(uint64_t form, const uint8_t* p)
3888 if ( form == DW_FORM_string )
3889 return (const char*)p;
3890 else if ( form == DW_FORM_strp ) {
3891 uint32_t offset = E::get32(*((uint32_t*)p));
3892 const char* dwarfStrings = (char*)(fHeader) + fDwarfDebugStringSect->offset();
3893 if ( offset > fDwarfDebugStringSect->size() ) {
3894 warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->getPath());
3895 return NULL;
3897 return &dwarfStrings[offset];
3899 warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->getPath());
3900 return NULL;
3904 // Look at the compilation unit DIE and determine
3905 // its NAME, compilation directory (in COMP_DIR) and its
3906 // line number information offset (in STMT_LIST). NAME and COMP_DIR
3907 // may be NULL (especially COMP_DIR) if they are not in the .o file;
3908 // STMT_LIST will be (uint64_t) -1.
3910 // At present this assumes that there's only one compilation unit DIE.
3912 template <typename A>
3913 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
3914 uint64_t *stmt_list)
3916 const uint8_t * debug_info;
3917 const uint8_t * debug_abbrev;
3918 const uint8_t * di;
3919 const uint8_t * da;
3920 const uint8_t * end;
3921 const uint8_t * enda;
3922 uint64_t sz;
3923 uint16_t vers;
3924 uint64_t abbrev_base;
3925 uint64_t abbrev;
3926 uint8_t address_size;
3927 bool dwarf64;
3929 *name = NULL;
3930 *comp_dir = NULL;
3931 *stmt_list = (uint64_t) -1;
3933 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
3934 return false;
3936 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
3937 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
3938 di = debug_info;
3940 if (fDwarfDebugInfoSect->size() < 12)
3941 /* Too small to be a real debug_info section. */
3942 return false;
3943 sz = A::P::E::get32(*(uint32_t*)di);
3944 di += 4;
3945 dwarf64 = sz == 0xffffffff;
3946 if (dwarf64)
3947 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
3948 else if (sz > 0xffffff00)
3949 /* Unknown dwarf format. */
3950 return false;
3952 /* Verify claimed size. */
3953 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
3954 return false;
3956 vers = A::P::E::get16(*(uint16_t*)di);
3957 if (vers < 2 || vers > 3)
3958 /* DWARF version wrong for this code.
3959 Chances are we could continue anyway, but we don't know for sure. */
3960 return false;
3961 di += 2;
3963 /* Find the debug_abbrev section. */
3964 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
3965 di += dwarf64 ? 8 : 4;
3967 if (abbrev_base > fDwarfDebugAbbrevSect->size())
3968 return false;
3969 da = debug_abbrev + abbrev_base;
3970 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
3972 address_size = *di++;
3974 /* Find the abbrev number we're looking for. */
3975 end = di + sz;
3976 abbrev = read_uleb128 (&di, end);
3977 if (abbrev == (uint64_t) -1)
3978 return false;
3980 /* Skip through the debug_abbrev section looking for that abbrev. */
3981 for (;;)
3983 uint64_t this_abbrev = read_uleb128 (&da, enda);
3984 uint64_t attr;
3986 if (this_abbrev == abbrev)
3987 /* This is almost always taken. */
3988 break;
3989 skip_leb128 (&da, enda); /* Skip the tag. */
3990 if (da == enda)
3991 return false;
3992 da++; /* Skip the DW_CHILDREN_* value. */
3994 do {
3995 attr = read_uleb128 (&da, enda);
3996 skip_leb128 (&da, enda);
3997 } while (attr != 0 && attr != (uint64_t) -1);
3998 if (attr != 0)
3999 return false;
4002 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
4003 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
4004 return false;
4005 if (da == enda)
4006 return false;
4007 da++; /* Skip the DW_CHILDREN_* value. */
4009 /* Now, go through the DIE looking for DW_AT_name,
4010 DW_AT_comp_dir, and DW_AT_stmt_list. */
4011 for (;;)
4013 uint64_t attr = read_uleb128 (&da, enda);
4014 uint64_t form = read_uleb128 (&da, enda);
4016 if (attr == (uint64_t) -1)
4017 return false;
4018 else if (attr == 0)
4019 return true;
4021 if (form == DW_FORM_indirect)
4022 form = read_uleb128 (&di, end);
4024 if (attr == DW_AT_name)
4025 *name = getDwarfString(form, di);
4026 else if (attr == DW_AT_comp_dir)
4027 *comp_dir = getDwarfString(form, di);
4028 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
4029 *stmt_list = A::P::E::get32(*(uint32_t*)di);
4030 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
4031 *stmt_list = A::P::E::get64(*(uint64_t*)di);
4032 if (! skip_form (&di, end, form, address_size, dwarf64))
4033 return false;
4037 template <typename A>
4038 const char* Reader<A>::assureFullPath(const char* path)
4040 if ( path[0] == '/' )
4041 return path;
4042 char cwdbuff[MAXPATHLEN];
4043 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
4044 char* result;
4045 asprintf(&result, "%s/%s", cwdbuff, path);
4046 if ( result != NULL )
4047 return result;
4049 return path;
4055 // To implement architecture xxx, you must write template specializations for the following six methods:
4056 // Reader<xxx>::validFile()
4057 // Reader<xxx>::addRelocReference()
4058 // Reference<xxx>::getDescription()
4063 template <>
4064 bool Reader<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4066 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4067 if ( header->magic() != MH_MAGIC )
4068 return false;
4069 if ( header->cputype() != CPU_TYPE_POWERPC )
4070 return false;
4071 if ( header->filetype() != MH_OBJECT )
4072 return false;
4073 return true;
4076 template <>
4077 bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4079 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4080 if ( header->magic() != MH_MAGIC_64 )
4081 return false;
4082 if ( header->cputype() != CPU_TYPE_POWERPC64 )
4083 return false;
4084 if ( header->filetype() != MH_OBJECT )
4085 return false;
4086 return true;
4089 template <>
4090 bool Reader<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4092 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4093 if ( header->magic() != MH_MAGIC )
4094 return false;
4095 if ( header->cputype() != CPU_TYPE_I386 )
4096 return false;
4097 if ( header->filetype() != MH_OBJECT )
4098 return false;
4099 return true;
4102 template <>
4103 bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
4105 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4106 if ( header->magic() != MH_MAGIC_64 )
4107 return false;
4108 if ( header->cputype() != CPU_TYPE_X86_64 )
4109 return false;
4110 if ( header->filetype() != MH_OBJECT )
4111 return false;
4112 return true;
4115 template <>
4116 bool Reader<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
4118 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4119 if ( header->magic() != MH_MAGIC )
4120 return false;
4121 if ( header->cputype() != CPU_TYPE_ARM )
4122 return false;
4123 if ( header->filetype() != MH_OBJECT )
4124 return false;
4125 if ( subtypeMustMatch && ((cpu_subtype_t)header->cpusubtype() != subtype) )
4126 return false;
4127 return true;
4130 template <typename A>
4131 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
4133 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
4136 template <>
4137 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
4139 return addRelocReference_powerpc(sect, reloc);
4142 template <>
4143 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
4145 return addRelocReference_powerpc(sect, reloc);
4150 // ppc and ppc64 both use the same relocations, so process them in one common routine
4152 template <typename A>
4153 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
4154 const macho_relocation_info<typename A::P>* reloc)
4156 uint32_t srcAddr;
4157 uint32_t dstAddr;
4158 uint32_t* fixUpPtr;
4159 int32_t displacement = 0;
4160 uint32_t instruction = 0;
4161 uint32_t offsetInTarget;
4162 int16_t lowBits;
4163 bool result = false;
4164 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4165 const macho_relocation_info<P>* nextReloc = &reloc[1];
4166 const char* targetName = NULL;
4167 bool weakImport = false;
4168 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4169 if ( reloc->r_type() != PPC_RELOC_PAIR )
4170 instruction = BigEndian::get32(*fixUpPtr);
4171 srcAddr = sect->addr() + reloc->r_address();
4172 if ( reloc->r_extern() ) {
4173 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4174 targetName = &fStrings[targetSymbol->n_strx()];
4175 weakImport = this->isWeakImportSymbol(targetSymbol);
4177 switch ( reloc->r_type() ) {
4178 case PPC_RELOC_BR24:
4180 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4181 displacement = (instruction & 0x03FFFFFC);
4182 if ( (displacement & 0x02000000) != 0 )
4183 displacement |= 0xFC000000;
4185 else {
4186 printf("bad instruction for BR24 reloc");
4188 if ( reloc->r_extern() ) {
4189 offsetInTarget = srcAddr + displacement;
4190 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4191 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4192 addDtraceExtraInfos(srcAddr, &targetName[16]);
4194 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4195 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4196 addDtraceExtraInfos(srcAddr, &targetName[20]);
4198 else if ( weakImport )
4199 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
4200 else
4201 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
4203 else {
4204 dstAddr = srcAddr + displacement;
4205 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
4206 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
4207 targetName = atom->getName();
4208 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4209 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4210 addDtraceExtraInfos(srcAddr, &targetName[16]);
4212 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4213 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4214 addDtraceExtraInfos(srcAddr, &targetName[20]);
4216 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4217 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
4218 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
4219 else
4220 makeReference(A::kBranch24, srcAddr, dstAddr);
4223 break;
4224 case PPC_RELOC_BR14:
4226 displacement = (instruction & 0x0000FFFC);
4227 if ( (displacement & 0x00008000) != 0 )
4228 displacement |= 0xFFFF0000;
4229 if ( reloc->r_extern() ) {
4230 offsetInTarget = srcAddr + displacement;
4231 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
4233 else {
4234 dstAddr = srcAddr + displacement;
4235 makeReference(A::kBranch14, srcAddr, dstAddr);
4238 break;
4239 case PPC_RELOC_PAIR:
4240 // skip, processed by a previous look ahead
4241 break;
4242 case PPC_RELOC_LO16:
4244 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4245 throw "PPC_RELOC_LO16 missing following pair";
4247 result = true;
4248 lowBits = (instruction & 0xFFFF);
4249 if ( reloc->r_extern() ) {
4250 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4251 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
4253 else {
4254 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4255 if ( reloc->r_symbolnum() == R_ABS ) {
4256 // find absolute symbol that corresponds to pointerValue
4257 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4258 if ( pos != fAddrToAbsoluteAtom.end() )
4259 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
4260 else
4261 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4263 else {
4264 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4268 break;
4269 case PPC_RELOC_LO14:
4271 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4272 throw "PPC_RELOC_LO14 missing following pair";
4274 result = true;
4275 lowBits = (instruction & 0xFFFC);
4276 if ( reloc->r_extern() ) {
4277 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4278 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
4280 else {
4281 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4282 if ( reloc->r_symbolnum() == R_ABS ) {
4283 // find absolute symbol that corresponds to pointerValue
4284 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4285 if ( pos != fAddrToAbsoluteAtom.end() )
4286 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
4287 else
4288 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4290 else {
4291 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4295 break;
4296 case PPC_RELOC_HI16:
4298 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4299 throw "PPC_RELOC_HI16 missing following pair";
4301 result = true;
4302 if ( reloc->r_extern() ) {
4303 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4304 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
4306 else {
4307 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4308 if ( reloc->r_symbolnum() == R_ABS ) {
4309 // find absolute symbol that corresponds to pointerValue
4310 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4311 if ( pos != fAddrToAbsoluteAtom.end() )
4312 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
4313 else
4314 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4316 else {
4317 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4321 break;
4322 case PPC_RELOC_HA16:
4324 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4325 throw "PPC_RELOC_HA16 missing following pair";
4327 result = true;
4328 lowBits = (nextReloc->r_address() & 0x0000FFFF);
4329 if ( reloc->r_extern() ) {
4330 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4331 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
4333 else {
4334 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4335 if ( reloc->r_symbolnum() == R_ABS ) {
4336 // find absolute symbol that corresponds to pointerValue
4337 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
4338 if ( pos != fAddrToAbsoluteAtom.end() )
4339 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
4340 else
4341 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4343 else {
4344 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4348 break;
4349 case PPC_RELOC_VANILLA:
4351 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
4352 if ( reloc->r_extern() ) {
4353 if ( weakImport )
4354 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
4355 else
4356 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
4358 else {
4359 new Reference<A>(A::kPointer, findAtomAndOffset(srcAddr), findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()));
4362 break;
4363 case PPC_RELOC_JBSR:
4364 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
4365 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
4366 throw "PPC_RELOC_JBSR missing following pair";
4368 if ( !fHasLongBranchStubs )
4369 warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath);
4370 fHasLongBranchStubs = true;
4371 result = true;
4372 if ( reloc->r_extern() ) {
4373 throw "PPC_RELOC_JBSR should not be using an external relocation";
4375 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
4376 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4377 displacement = (instruction & 0x03FFFFFC);
4378 if ( (displacement & 0x02000000) != 0 )
4379 displacement |= 0xFC000000;
4381 else {
4382 fprintf(stderr, "bad instruction for BR24 reloc");
4384 break;
4385 default:
4386 warning("unknown relocation type %d", reloc->r_type());
4389 else {
4390 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4391 srcAddr = sect->addr() + sreloc->r_address();
4392 dstAddr = sreloc->r_value();
4393 uint32_t betterDstAddr;
4394 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4395 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4396 const macho_relocation_info<P>* nextReloc = &reloc[1];
4397 // file format allows pair to be scattered or not
4398 bool nextRelocIsPair = false;
4399 uint32_t nextRelocAddress = 0;
4400 uint32_t nextRelocValue = 0;
4401 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4402 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
4403 nextRelocIsPair = true;
4404 nextRelocAddress = nextReloc->r_address();
4405 result = true;
4408 else {
4409 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
4410 nextRelocIsPair = true;
4411 nextRelocAddress = nextSReloc->r_address();
4412 nextRelocValue = nextSReloc->r_value();
4413 result = true;
4416 switch (sreloc->r_type()) {
4417 case PPC_RELOC_VANILLA:
4419 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
4420 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
4421 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4422 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
4424 break;
4425 case PPC_RELOC_BR14:
4427 instruction = BigEndian::get32(*fixUpPtr);
4428 displacement = (instruction & 0x0000FFFC);
4429 if ( (displacement & 0x00008000) != 0 )
4430 displacement |= 0xFFFF0000;
4431 betterDstAddr = srcAddr+displacement;
4432 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
4433 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
4435 break;
4436 case PPC_RELOC_BR24:
4438 instruction = BigEndian::get32(*fixUpPtr);
4439 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4440 displacement = (instruction & 0x03FFFFFC);
4441 if ( (displacement & 0x02000000) != 0 )
4442 displacement |= 0xFC000000;
4443 betterDstAddr = srcAddr+displacement;
4444 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
4447 break;
4448 case PPC_RELOC_LO16_SECTDIFF:
4450 if ( ! nextRelocIsPair ) {
4451 throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
4453 instruction = BigEndian::get32(*fixUpPtr);
4454 lowBits = (instruction & 0xFFFF);
4455 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4456 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4458 break;
4459 case PPC_RELOC_LO14_SECTDIFF:
4461 if ( ! nextRelocIsPair ) {
4462 throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
4464 instruction = BigEndian::get32(*fixUpPtr);
4465 lowBits = (instruction & 0xFFFC);
4466 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4467 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4469 break;
4470 case PPC_RELOC_HA16_SECTDIFF:
4472 if ( ! nextRelocIsPair ) {
4473 throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
4475 instruction = BigEndian::get32(*fixUpPtr);
4476 lowBits = (nextRelocAddress & 0x0000FFFF);
4477 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4478 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4480 break;
4481 case PPC_RELOC_LO14:
4483 if ( ! nextRelocIsPair ) {
4484 throw "PPC_RELOC_LO14 missing following pair";
4486 instruction = BigEndian::get32(*fixUpPtr);
4487 lowBits = (instruction & 0xFFFC);
4488 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4489 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
4491 break;
4492 case PPC_RELOC_LO16:
4494 if ( ! nextRelocIsPair ) {
4495 throw "PPC_RELOC_LO16 missing following pair";
4497 instruction = BigEndian::get32(*fixUpPtr);
4498 lowBits = (instruction & 0xFFFF);
4499 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4500 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
4502 break;
4503 case PPC_RELOC_HA16:
4505 if ( ! nextRelocIsPair ) {
4506 throw "PPC_RELOC_HA16 missing following pair";
4508 instruction = BigEndian::get32(*fixUpPtr);
4509 lowBits = (nextRelocAddress & 0xFFFF);
4510 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
4511 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
4513 break;
4514 case PPC_RELOC_HI16:
4516 if ( ! nextRelocIsPair ) {
4517 throw "PPC_RELOC_HI16 missing following pair";
4519 instruction = BigEndian::get32(*fixUpPtr);
4520 lowBits = (nextRelocAddress & 0xFFFF);
4521 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
4522 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
4524 break;
4525 case PPC_RELOC_SECTDIFF:
4526 case PPC_RELOC_LOCAL_SECTDIFF:
4528 if ( ! nextRelocIsPair ) {
4529 throw "PPC_RELOC_SECTDIFF missing following pair";
4531 Kinds kind = A::kPointerDiff32;;
4532 uint32_t contentAddr = 0;
4533 switch ( sreloc->r_length() ) {
4534 case 0:
4535 throw "bad diff relocations r_length (0) for ppc architecture";
4536 case 1:
4537 kind = A::kPointerDiff16;
4538 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
4539 break;
4540 case 2:
4541 kind = A::kPointerDiff32;
4542 contentAddr = BigEndian::get32(*fixUpPtr);
4543 break;
4544 case 3:
4545 kind = A::kPointerDiff64;
4546 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
4547 break;
4549 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4550 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4551 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4552 // check for addend encoded in the section content
4553 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4554 // dstAddr, nextRelocValue, contentAddr);
4555 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4556 if ( toao.atom == srcao.atom )
4557 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4558 else if ( fromao.atom == srcao.atom )
4559 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4560 else
4561 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4563 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4564 // srcao.atom->getDisplayName(), srcao.offset,
4565 // fromao.atom->getDisplayName(), fromao.offset,
4566 // toao.atom->getDisplayName(), toao.offset);
4567 new Reference<A>(kind, srcao, fromao, toao);
4569 break;
4570 case PPC_RELOC_PAIR:
4571 break;
4572 case PPC_RELOC_HI16_SECTDIFF:
4573 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
4574 break;
4575 default:
4576 warning("unknown scattered relocation type %d", sreloc->r_type());
4579 return result;
4583 template <>
4584 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
4586 uint32_t srcAddr;
4587 uint32_t dstAddr;
4588 uint32_t* fixUpPtr;
4589 bool result = false;
4590 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4591 srcAddr = sect->addr() + reloc->r_address();
4592 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4593 switch ( reloc->r_type() ) {
4594 case GENERIC_RELOC_VANILLA:
4596 x86::ReferenceKinds kind = x86::kPointer;
4597 uint32_t pointerValue = E::get32(*fixUpPtr);
4598 if ( reloc->r_pcrel() ) {
4599 switch( reloc->r_length() ) {
4600 case 0:
4601 kind = x86::kPCRel8;
4602 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
4603 break;
4604 case 1:
4605 kind = x86::kPCRel16;
4606 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
4607 break;
4608 case 2:
4609 kind = x86::kPCRel32;
4610 pointerValue += srcAddr + sizeof(uint32_t);
4611 break;
4612 case 3:
4613 throw "bad pc-rel vanilla relocation length";
4616 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
4617 kind = x86::kAbsolute32;
4618 if ( reloc->r_length() != 2 )
4619 throw "bad vanilla relocation length";
4621 else {
4622 kind = x86::kPointer;
4623 if ( reloc->r_length() != 2 )
4624 throw "bad vanilla relocation length";
4626 if ( reloc->r_extern() ) {
4627 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4628 if ( this->isWeakImportSymbol(targetSymbol) ) {
4629 if ( reloc->r_pcrel() )
4630 kind = x86::kPCRel32WeakImport;
4631 else
4632 kind = x86::kPointerWeakImport;
4634 const char* targetName = &fStrings[targetSymbol->n_strx()];
4635 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4636 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4637 addDtraceExtraInfos(srcAddr, &targetName[16]);
4639 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4640 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4641 addDtraceExtraInfos(srcAddr, &targetName[20]);
4643 else
4644 makeByNameReference(kind, srcAddr, targetName, pointerValue);
4646 else {
4647 AtomAndOffset targetAO = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
4648 const char* targetName = targetAO.atom->getName();
4649 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4650 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4651 addDtraceExtraInfos(srcAddr, &targetName[16]);
4653 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4654 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4655 addDtraceExtraInfos(srcAddr, &targetName[20]);
4657 // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol
4658 else if ( reloc->r_pcrel() && (targetAO.atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4659 && ((AnonymousAtom<x86>*)targetAO.atom)->isWeakImportStub() )
4660 new Reference<x86>(x86::kPCRel32WeakImport, findAtomAndOffset(srcAddr), targetAO);
4661 else if ( reloc->r_symbolnum() != R_ABS )
4662 new Reference<x86>(kind, findAtomAndOffset(srcAddr), targetAO);
4663 else {
4664 // find absolute symbol that corresponds to pointerValue
4665 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
4666 if ( pos != fAddrToAbsoluteAtom.end() )
4667 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
4668 else
4669 throwf("R_ABS reloc but no absolute symbol at target address");
4673 break;
4674 default:
4675 warning("unknown relocation type %d", reloc->r_type());
4678 else {
4679 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4680 srcAddr = sect->addr() + sreloc->r_address();
4681 dstAddr = sreloc->r_value();
4682 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4683 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4684 const macho_relocation_info<P>* nextReloc = &reloc[1];
4685 pint_t betterDstAddr;
4686 // file format allows pair to be scattered or not
4687 bool nextRelocIsPair = false;
4688 uint32_t nextRelocAddress = 0;
4689 uint32_t nextRelocValue = 0;
4690 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4691 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
4692 nextRelocIsPair = true;
4693 nextRelocAddress = nextReloc->r_address();
4694 result = true;
4697 else {
4698 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
4699 nextRelocIsPair = true;
4700 nextRelocAddress = nextSReloc->r_address();
4701 nextRelocValue = nextSReloc->r_value();
4704 switch (sreloc->r_type()) {
4705 case GENERIC_RELOC_VANILLA:
4706 betterDstAddr = LittleEndian::get32(*fixUpPtr);
4707 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
4708 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4709 if ( sreloc->r_pcrel() ) {
4710 switch ( sreloc->r_length() ) {
4711 case 2:
4712 betterDstAddr += srcAddr + 4;
4713 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
4714 break;
4715 case 1:
4716 betterDstAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)) + srcAddr + 2;
4717 makeReferenceWithToBase(x86::kPCRel16, srcAddr, betterDstAddr, dstAddr);
4718 break;
4719 case 0:
4720 betterDstAddr = *((uint8_t*)fixUpPtr) + srcAddr + 1;
4721 makeReferenceWithToBase(x86::kPCRel8, srcAddr, betterDstAddr, dstAddr);
4722 break;
4723 case 3:
4724 throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc");
4725 break;
4728 else {
4729 if ( sreloc->r_length() != 2 )
4730 throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
4731 if ( strcmp(sect->segname(), "__TEXT") == 0 )
4732 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
4733 else
4734 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
4736 break;
4737 case GENERIC_RELOC_SECTDIFF:
4738 case GENERIC_RELOC_LOCAL_SECTDIFF:
4740 if ( !nextRelocIsPair ) {
4741 throw "GENERIC_RELOC_SECTDIFF missing following pair";
4743 x86::ReferenceKinds kind = x86::kPointerDiff;
4744 uint32_t contentAddr = 0;
4745 switch ( sreloc->r_length() ) {
4746 case 0:
4747 case 3:
4748 throw "bad length for GENERIC_RELOC_SECTDIFF";
4749 case 1:
4750 kind = x86::kPointerDiff16;
4751 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
4752 break;
4753 case 2:
4754 kind = x86::kPointerDiff;
4755 contentAddr = LittleEndian::get32(*fixUpPtr);
4756 break;
4758 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4759 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4760 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4761 // check for addend encoded in the section content
4762 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4763 // dstAddr, nextRelocValue, contentAddr);
4764 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4765 if ( toao.atom == srcao.atom )
4766 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4767 else if ( fromao.atom == srcao.atom )
4768 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4769 else
4770 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4772 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4773 // srcao.atom->getDisplayName(), srcao.offset,
4774 // fromao.atom->getDisplayName(), fromao.offset,
4775 // toao.atom->getDisplayName(), toao.offset);
4776 new Reference<x86>(kind, srcao, fromao, toao);
4778 break;
4779 case GENERIC_RELOC_PAIR:
4780 // do nothing, already used via a look ahead
4781 break;
4782 default:
4783 warning("unknown scattered relocation type %d", sreloc->r_type());
4786 return result;
4789 template <>
4790 bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
4792 uint64_t srcAddr;
4793 uint64_t dstAddr = 0;
4794 uint64_t addend;
4795 uint32_t* fixUpPtr;
4796 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
4797 bool result = false;
4798 const macho_nlist<P>* targetSymbol = NULL;
4799 const char* targetName = NULL;
4800 srcAddr = sect->addr() + reloc->r_address();
4801 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4802 //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address());
4803 if ( reloc->r_extern() ) {
4804 targetSymbol = &fSymbols[reloc->r_symbolnum()];
4805 targetName = &fStrings[targetSymbol->n_strx()];
4807 switch ( reloc->r_type() ) {
4808 case X86_64_RELOC_UNSIGNED:
4809 if ( reloc->r_pcrel() )
4810 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
4811 switch ( reloc->r_length() ) {
4812 case 0:
4813 case 1:
4814 throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
4815 case 2:
4816 kind = x86_64::kPointer32;
4817 break;
4818 case 3:
4819 if ( reloc->r_extern() && isWeakImportSymbol(targetSymbol) )
4820 kind = x86_64::kPointerWeakImport;
4821 else
4822 kind = x86_64::kPointer;
4823 break;
4825 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
4826 if ( reloc->r_extern() ) {
4827 makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
4829 else {
4830 makeReference(kind, srcAddr, dstAddr);
4831 // verify that dstAddr is in the section being targeted
4832 int sectNum = reloc->r_symbolnum();
4833 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
4834 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
4835 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
4836 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4837 srcAddr, sect->sectname(), targetSection->sectname());
4840 break;
4841 case X86_64_RELOC_SIGNED:
4842 case X86_64_RELOC_SIGNED_1:
4843 case X86_64_RELOC_SIGNED_2:
4844 case X86_64_RELOC_SIGNED_4:
4845 if ( ! reloc->r_pcrel() )
4846 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
4847 if ( reloc->r_length() != 2 )
4848 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
4849 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4850 if ( reloc->r_extern() ) {
4851 switch ( reloc->r_type() ) {
4852 case X86_64_RELOC_SIGNED:
4853 kind = x86_64::kPCRel32;
4854 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
4855 if ( addend == (uint64_t)(-1) ) {
4856 addend = 0;
4857 kind = x86_64::kPCRel32_1;
4859 else if ( addend == (uint64_t)(-2) ) {
4860 addend = 0;
4861 kind = x86_64::kPCRel32_2;
4863 else if ( addend == (uint64_t)(-4) ) {
4864 addend = 0;
4865 kind = x86_64::kPCRel32_4;
4867 break;
4868 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
4869 case X86_64_RELOC_SIGNED_1:
4870 kind = x86_64::kPCRel32_1;
4871 addend += 1;
4872 break;
4873 case X86_64_RELOC_SIGNED_2:
4874 kind = x86_64::kPCRel32_2;
4875 addend += 2;
4876 break;
4877 case X86_64_RELOC_SIGNED_4:
4878 kind = x86_64::kPCRel32_4;
4879 addend += 4;
4880 break;
4882 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
4884 else {
4885 uint64_t ripRelativeOffset = addend;
4886 switch ( reloc->r_type() ) {
4887 case X86_64_RELOC_SIGNED:
4888 dstAddr = srcAddr + 4 + ripRelativeOffset;
4889 kind = x86_64::kPCRel32;
4890 break;
4891 case X86_64_RELOC_SIGNED_1:
4892 dstAddr = srcAddr + 5 + ripRelativeOffset;
4893 kind = x86_64::kPCRel32_1;
4894 break;
4895 case X86_64_RELOC_SIGNED_2:
4896 dstAddr = srcAddr + 6 + ripRelativeOffset;
4897 kind = x86_64::kPCRel32_2;
4898 break;
4899 case X86_64_RELOC_SIGNED_4:
4900 dstAddr = srcAddr + 8 + ripRelativeOffset;
4901 kind = x86_64::kPCRel32_4;
4902 break;
4904 makeReference(kind, srcAddr, dstAddr);
4905 // verify that dstAddr is in the section being targeted
4906 int sectNum = reloc->r_symbolnum();
4907 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
4908 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
4909 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
4910 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4911 srcAddr, sect->sectname(), targetSection->sectname());
4914 break;
4915 case X86_64_RELOC_BRANCH:
4916 if ( ! reloc->r_pcrel() )
4917 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
4918 if ( reloc->r_length() == 2 ) {
4919 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4920 if ( reloc->r_extern() ) {
4921 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4922 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
4923 addDtraceExtraInfos(srcAddr, &targetName[16]);
4925 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4926 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4927 addDtraceExtraInfos(srcAddr, &targetName[16]);
4929 else if ( isWeakImportSymbol(targetSymbol) )
4930 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
4931 else
4932 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
4934 else {
4935 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
4938 else if ( reloc->r_length() == 0 ) {
4939 dstAddr = *((int8_t*)fixUpPtr);
4940 if ( reloc->r_extern() ) {
4941 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
4943 else {
4944 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
4947 else {
4948 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
4950 break;
4951 case X86_64_RELOC_GOT:
4952 if ( ! reloc->r_extern() )
4953 throw "not extern and X86_64_RELOC_GOT not supported";
4954 if ( ! reloc->r_pcrel() )
4955 throw "not pcrel and X86_64_RELOC_GOT not supported";
4956 if ( reloc->r_length() != 2 )
4957 throw "length != 2 and X86_64_RELOC_GOT not supported";
4958 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4959 if ( isWeakImportSymbol(targetSymbol) )
4960 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
4961 else
4962 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
4963 break;
4964 case X86_64_RELOC_GOT_LOAD:
4965 if ( ! reloc->r_extern() )
4966 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
4967 if ( ! reloc->r_pcrel() )
4968 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
4969 if ( reloc->r_length() != 2 )
4970 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
4971 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
4972 if ( isWeakImportSymbol(targetSymbol) )
4973 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
4974 else
4975 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
4976 break;
4977 case X86_64_RELOC_SUBTRACTOR:
4979 if ( reloc->r_pcrel() )
4980 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
4981 if ( reloc->r_length() < 2 )
4982 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
4983 if ( !reloc->r_extern() )
4984 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
4985 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
4986 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
4987 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
4988 result = true;
4989 if ( nextReloc->r_pcrel() )
4990 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
4991 if ( nextReloc->r_length() != reloc->r_length() )
4992 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
4993 Reference<x86_64>* ref;
4994 bool negativeAddend;
4995 if ( reloc->r_length() == 2 ) {
4996 kind = x86_64::kPointerDiff32;
4997 dstAddr = E::get32(*fixUpPtr); // addend is in content
4998 negativeAddend = ((dstAddr & 0x80000000) != 0);
5000 else {
5001 kind = x86_64::kPointerDiff;
5002 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
5003 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
5005 AtomAndOffset inAtomAndOffset = this->findAtomAndOffset(srcAddr);
5006 ObjectFile::Atom* inAtom = inAtomAndOffset.atom;
5007 // create reference with "to" target
5008 if ( nextReloc->r_extern() ) {
5009 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
5010 const char* targetName = &fStrings[targetSymbol->n_strx()];
5011 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
5012 // if "to" is in this atom, change by-name to a direct reference
5013 if ( strcmp(targetName, inAtom->getName()) == 0 )
5014 ref->setTarget(*inAtom, 0);
5016 else {
5017 ref = makeReference(kind, srcAddr, dstAddr);
5019 // add in "from" target
5020 if ( reloc->r_extern() ) {
5021 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
5022 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
5023 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
5024 // from target is translation unit scoped, so use a direct reference
5025 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
5027 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
5028 // if "from" is in this atom, change by-name to a direct reference
5029 ref->setFromTarget(*inAtom);
5031 else {
5032 // some non-static other atom
5033 ref->setFromTargetName(fromTargetName);
5036 else {
5037 throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0";
5039 // addend goes in from side iff negative
5040 if ( negativeAddend )
5041 ref->setFromTargetOffset(-dstAddr);
5042 else
5043 ref->setToTargetOffset(dstAddr);
5044 break;
5046 default:
5047 warning("unknown relocation type %d", reloc->r_type());
5049 return result;
5053 /// Reader<arm>::addRelocReference -
5054 /// turns arm relocation entries into references. Returns true if the next
5055 /// relocation should be skipped, false otherwise.
5056 template <>
5057 bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
5058 const macho_relocation_info<arm::P>* reloc)
5060 uint32_t * fixUpPtr;
5061 int32_t displacement;
5062 uint32_t instruction = 0;
5063 bool result = false;
5064 uint32_t srcAddr;
5065 uint32_t dstAddr;
5066 uint32_t pointerValue;
5067 arm::ReferenceKinds kind = arm::kNoFixUp;
5069 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
5070 // non-scattered relocation
5071 const char* targetName = NULL;
5072 bool weakImport = false;
5074 srcAddr = sect->addr() + reloc->r_address();
5075 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
5076 if ( reloc->r_type() != ARM_RELOC_PAIR )
5077 instruction = LittleEndian::get32(*fixUpPtr);
5079 if ( reloc->r_extern() ) {
5080 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
5081 targetName = &fStrings[targetSymbol->n_strx()];
5082 weakImport = this->isWeakImportSymbol(targetSymbol);
5085 switch ( reloc->r_type() ) {
5086 case ARM_RELOC_BR24:
5087 // Sign-extend displacement
5088 displacement = (instruction & 0x00FFFFFF) << 2;
5089 if ( (displacement & 0x02000000) != 0 )
5090 displacement |= 0xFC000000;
5091 // The pc added will be +8 from the pc
5092 displacement += 8;
5093 // If this is BLX add H << 1
5094 if ((instruction & 0xFE000000) == 0xFA000000)
5095 displacement += ((instruction & 0x01000000) >> 23);
5097 if ( reloc->r_extern() ) {
5098 uint32_t offsetInTarget = srcAddr + displacement;
5099 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5100 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5101 addDtraceExtraInfos(srcAddr, &targetName[16]);
5103 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5104 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5105 addDtraceExtraInfos(srcAddr, &targetName[20]);
5107 else if ( weakImport )
5108 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
5109 else
5110 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
5112 else {
5113 dstAddr = srcAddr + displacement;
5114 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5115 // check for dtrace probes and weak_import stubs
5116 const char* targetName = atom->getName();
5117 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5118 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5119 addDtraceExtraInfos(srcAddr, &targetName[16]);
5121 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5122 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5123 addDtraceExtraInfos(srcAddr, &targetName[20]);
5125 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5126 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5127 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
5128 else if ( reloc->r_symbolnum() != R_ABS )
5129 makeReference(arm::kBranch24, srcAddr, dstAddr);
5130 else {
5131 // find absolute symbol that corresponds to pointerValue
5132 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5133 if ( pos != fAddrToAbsoluteAtom.end() )
5134 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
5135 else
5136 throwf("R_ABS reloc but no absolute symbol at target address");
5139 break;
5141 case ARM_THUMB_RELOC_BR22:
5142 // thumb2 added two more bits to displacement, complicating the displacement decoding
5144 uint32_t s = (instruction >> 10) & 0x1;
5145 uint32_t j1 = (instruction >> 29) & 0x1;
5146 uint32_t j2 = (instruction >> 27) & 0x1;
5147 uint32_t imm10 = instruction & 0x3FF;
5148 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5149 uint32_t i1 = (j1 == s);
5150 uint32_t i2 = (j2 == s);
5151 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5152 int32_t sdis = dis;
5153 if ( s )
5154 sdis |= 0xFE000000;
5155 displacement = sdis;
5157 // The pc added will be +4 from the pc
5158 displacement += 4;
5159 // If the instruction was blx, force the low 2 bits to be clear
5160 dstAddr = srcAddr + displacement;
5161 if ((instruction & 0xF8000000) == 0xE8000000)
5162 dstAddr &= 0xFFFFFFFC;
5164 if ( reloc->r_extern() ) {
5165 uint32_t offsetInTarget = dstAddr;
5166 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5167 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5168 addDtraceExtraInfos(srcAddr, &targetName[16]);
5170 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5171 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5172 addDtraceExtraInfos(srcAddr, &targetName[20]);
5174 else if ( weakImport )
5175 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
5176 else
5177 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
5179 else {
5180 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5181 // check for dtrace probes and weak_import stubs
5182 const char* targetName = atom->getName();
5183 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5184 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5185 addDtraceExtraInfos(srcAddr, &targetName[16]);
5187 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5188 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5189 addDtraceExtraInfos(srcAddr, &targetName[20]);
5191 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5192 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5193 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
5194 else if ( reloc->r_symbolnum() != R_ABS )
5195 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
5196 else {
5197 // find absolute symbol that corresponds to pointerValue
5198 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5199 if ( pos != fAddrToAbsoluteAtom.end() )
5200 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
5201 else
5202 throwf("R_ABS reloc but no absolute symbol at target address");
5205 break;
5207 case ARM_RELOC_VANILLA:
5208 if ( reloc->r_length() != 2 )
5209 throw "bad length for ARM_RELOC_VANILLA";
5211 pointerValue = instruction;
5212 kind = arm::kPointer;
5213 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5214 kind = arm::kReadOnlyPointer;
5215 if ( weakImport )
5216 kind = arm::kPointerWeakImport;
5217 if ( reloc->r_extern() ) {
5218 makeByNameReference(kind, srcAddr, targetName, pointerValue);
5220 else {
5221 AtomAndOffset at = findAtomAndOffset(srcAddr);
5222 AtomAndOffset to = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
5223 if ( to.atom->isThumb() )
5224 to.offset &= -2;
5225 new Reference<arm>(kind, at, to);
5227 break;
5229 case ARM_THUMB_32BIT_BRANCH:
5230 // ignore old unnecessary relocs
5231 break;
5233 default:
5234 warning("unexpected relocation type %u", reloc->r_type());
5235 break;
5238 else {
5239 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
5240 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
5241 srcAddr = sect->addr() + sreloc->r_address();
5242 dstAddr = sreloc->r_value();
5243 uint32_t betterDstAddr;
5244 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
5245 instruction = LittleEndian::get32(*fixUpPtr);
5247 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
5248 // relocation types, and it is an error to see one otherwise.
5249 bool nextRelocIsPair = false;
5250 uint32_t nextRelocAddress = 0;
5251 uint32_t nextRelocValue = 0;
5252 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
5253 nextRelocIsPair = true;
5254 nextRelocAddress = nextSReloc->r_address();
5255 nextRelocValue = nextSReloc->r_value();
5256 result = true;
5259 switch (sreloc->r_type()) {
5260 case ARM_RELOC_VANILLA:
5261 if ( sreloc->r_length() != 2 )
5262 throw "bad length for ARM_RELOC_VANILLA";
5264 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
5265 betterDstAddr = LittleEndian::get32(*fixUpPtr);
5266 kind = arm::kPointer;
5267 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5268 kind = arm::kReadOnlyPointer;
5269 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
5270 makeReferenceWithToBase(kind, srcAddr, betterDstAddr, dstAddr);
5271 break;
5273 case ARM_RELOC_BR24:
5274 // Sign-extend displacement
5275 displacement = (instruction & 0x00FFFFFF) << 2;
5276 if ( (displacement & 0x02000000) != 0 )
5277 displacement |= 0xFC000000;
5278 // The pc added will be +8 from the pc
5279 displacement += 8;
5280 // If this is BLX add H << 1
5281 if ((instruction & 0xFE000000) == 0xFA000000)
5282 displacement += ((instruction & 0x01000000) >> 23);
5283 betterDstAddr = srcAddr+displacement;
5284 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
5285 break;
5287 case ARM_THUMB_RELOC_BR22:
5288 // thumb2 added two more bits to displacement, complicating the displacement decoding
5290 uint32_t s = (instruction >> 10) & 0x1;
5291 uint32_t j1 = (instruction >> 29) & 0x1;
5292 uint32_t j2 = (instruction >> 27) & 0x1;
5293 uint32_t imm10 = instruction & 0x3FF;
5294 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5295 uint32_t i1 = (j1 == s);
5296 uint32_t i2 = (j2 == s);
5297 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5298 int32_t sdis = dis;
5299 if ( s )
5300 sdis |= 0xFE000000;
5301 displacement = sdis;
5303 // The pc added will be +4 from the pc
5304 displacement += 4;
5305 betterDstAddr = srcAddr+displacement;
5306 // If the instruction was blx, force the low 2 bits to be clear
5307 if ((instruction & 0xF8000000) == 0xE8000000)
5308 betterDstAddr &= 0xFFFFFFFC;
5309 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
5310 break;
5312 case ARM_RELOC_SECTDIFF:
5313 case ARM_RELOC_LOCAL_SECTDIFF:
5314 if ( !nextRelocIsPair ) {
5315 throw "ARM_RELOC_SECTDIFF missing following pair";
5317 if ( sreloc->r_length() != 2 )
5318 throw "bad length for ARM_RELOC_SECTDIFF";
5320 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
5321 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
5322 AtomAndOffset toao = findAtomAndOffset(dstAddr);
5323 // check for addend encoded in the section content
5324 pointerValue = LittleEndian::get32(*fixUpPtr);
5325 if ( (dstAddr - nextRelocValue) != pointerValue ) {
5326 if ( toao.atom == srcao.atom )
5327 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
5328 else if ( fromao.atom == srcao.atom )
5329 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
5330 else
5331 fromao.offset += (dstAddr - pointerValue) - nextRelocValue;
5333 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
5335 break;
5337 default:
5338 warning("unexpected srelocation type %u", sreloc->r_type());
5339 break;
5342 return result;
5345 template <typename A>
5346 void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
5348 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
5349 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
5350 switch ( sect->flags() & SECTION_TYPE ) {
5351 case S_SYMBOL_STUBS:
5352 case S_LAZY_SYMBOL_POINTERS:
5353 // we ignore compiler generated stubs, so ignore those relocs too
5354 break;
5355 default:
5356 // ignore all relocations in __eh_frame section
5357 if ( sect == fehFrameSection )
5358 return;
5359 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
5360 const uint32_t relocCount = sect->nreloc();
5361 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
5362 for (uint32_t r = 0; r < relocCount; ++r) {
5363 try {
5364 if ( addRelocReference(sect, &relocs[r]) )
5365 ++r; // skip next
5367 catch (const char* msg) {
5368 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
5376 template <>
5377 const char* Reference<x86>::getDescription() const
5379 static char temp[2048];
5380 switch( fKind ) {
5381 case x86::kNoFixUp:
5382 sprintf(temp, "reference to ");
5383 break;
5384 case x86::kFollowOn:
5385 sprintf(temp, "followed by ");
5386 break;
5387 case x86::kGroupSubordinate:
5388 sprintf(temp, "group subordinate ");
5389 break;
5390 case x86::kPointerWeakImport:
5391 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5392 break;
5393 case x86::kPointer:
5394 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5395 break;
5396 case x86::kPointerDiff:
5398 // by-name references have quoted names
5399 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5400 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5401 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5402 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5403 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5404 return temp;
5406 break;
5407 case x86::kPointerDiff16:
5409 // by-name references have quoted names
5410 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5411 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5412 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5413 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5414 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5415 return temp;
5417 break;
5418 case x86::kPCRel32WeakImport:
5419 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
5420 break;
5421 case x86::kPCRel32:
5422 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
5423 break;
5424 case x86::kPCRel16:
5425 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
5426 break;
5427 case x86::kPCRel8:
5428 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
5429 break;
5430 case x86::kAbsolute32:
5431 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
5432 break;
5433 case x86::kImageOffset32:
5434 sprintf(temp, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc);
5435 break;
5436 case x86::kPointerDiff24:
5437 sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5438 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5439 this->getFromTargetDisplayName(), fFromTarget.offset );
5440 return temp;
5441 break;
5442 case x86::kSectionOffset24:
5443 sprintf(temp, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc);
5444 break;
5445 case x86::kDtraceProbe:
5446 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5447 break;
5448 case x86::kDtraceProbeSite:
5449 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5450 break;
5451 case x86::kDtraceIsEnabledSite:
5452 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5453 break;
5454 case x86::kDtraceTypeReference:
5455 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5456 break;
5458 // always quote by-name references
5459 if ( fToTargetName != NULL ) {
5460 strcat(temp, "\"");
5461 strcat(temp, fToTargetName);
5462 strcat(temp, "\"");
5464 else if ( fToTarget.atom != NULL ) {
5465 strcat(temp, fToTarget.atom->getDisplayName());
5467 else {
5468 strcat(temp, "NULL target");
5470 if ( fToTarget.offset != 0 )
5471 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5473 return temp;
5477 template <>
5478 const char* Reference<ppc>::getDescription() const
5480 static char temp[2048];
5481 switch( fKind ) {
5482 case ppc::kNoFixUp:
5483 sprintf(temp, "reference to ");
5484 break;
5485 case ppc::kFollowOn:
5486 sprintf(temp, "followed by ");
5487 break;
5488 case ppc::kGroupSubordinate:
5489 sprintf(temp, "group subordinate ");
5490 break;
5491 case ppc::kPointerWeakImport:
5492 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5493 break;
5494 case ppc::kPointer:
5495 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5496 break;
5497 case ppc::kPointerDiff16:
5499 // by-name references have quoted names
5500 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5501 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5502 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5503 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5504 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5505 return temp;
5507 case ppc::kPointerDiff32:
5509 // by-name references have quoted names
5510 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5511 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5512 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5513 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5514 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5515 return temp;
5517 case ppc::kPointerDiff64:
5518 throw "unsupported refrence kind";
5519 break;
5520 case ppc::kBranch24WeakImport:
5521 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5522 break;
5523 case ppc::kBranch24:
5524 case ppc::kBranch14:
5525 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5526 break;
5527 case ppc::kPICBaseLow16:
5528 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5529 break;
5530 case ppc::kPICBaseLow14:
5531 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5532 break;
5533 case ppc::kPICBaseHigh16:
5534 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
5535 break;
5536 case ppc::kAbsLow16:
5537 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5538 break;
5539 case ppc::kAbsLow14:
5540 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5541 break;
5542 case ppc::kAbsHigh16:
5543 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
5544 break;
5545 case ppc::kAbsHigh16AddLow:
5546 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5547 break;
5548 case ppc::kDtraceProbe:
5549 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5550 break;
5551 case ppc::kDtraceProbeSite:
5552 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5553 break;
5554 case ppc::kDtraceIsEnabledSite:
5555 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5556 break;
5557 case ppc::kDtraceTypeReference:
5558 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5559 break;
5561 // always quote by-name references
5562 if ( fToTargetName != NULL ) {
5563 strcat(temp, "\"");
5564 strcat(temp, fToTargetName);
5565 strcat(temp, "\"");
5567 else if ( fToTarget.atom != NULL ) {
5568 strcat(temp, fToTarget.atom->getDisplayName());
5570 else {
5571 strcat(temp, "NULL target");
5573 if ( fToTarget.offset != 0 )
5574 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5576 return temp;
5579 template <>
5580 const char* Reference<ppc64>::getDescription() const
5582 static char temp[2048];
5583 switch( fKind ) {
5584 case ppc64::kNoFixUp:
5585 sprintf(temp, "reference to ");
5586 break;
5587 case ppc64::kFollowOn:
5588 sprintf(temp, "followed by ");
5589 break;
5590 case ppc64::kGroupSubordinate:
5591 sprintf(temp, "group subordinate ");
5592 break;
5593 case ppc64::kPointerWeakImport:
5594 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5595 break;
5596 case ppc64::kPointer:
5597 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5598 break;
5599 case ppc64::kPointerDiff64:
5601 // by-name references have quoted names
5602 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5603 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5604 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5605 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5606 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5607 return temp;
5609 case ppc64::kPointerDiff32:
5611 // by-name references have quoted names
5612 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5613 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5614 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5615 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5616 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5617 return temp;
5619 case ppc64::kPointerDiff16:
5621 // by-name references have quoted names
5622 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5623 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5624 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
5625 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5626 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5627 return temp;
5629 case ppc64::kBranch24WeakImport:
5630 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5631 break;
5632 case ppc64::kBranch24:
5633 case ppc64::kBranch14:
5634 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5635 break;
5636 case ppc64::kPICBaseLow16:
5637 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5638 break;
5639 case ppc64::kPICBaseLow14:
5640 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5641 break;
5642 case ppc64::kPICBaseHigh16:
5643 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5644 break;
5645 case ppc64::kAbsLow16:
5646 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5647 break;
5648 case ppc64::kAbsLow14:
5649 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5650 break;
5651 case ppc64::kAbsHigh16:
5652 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
5653 break;
5654 case ppc64::kAbsHigh16AddLow:
5655 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5656 break;
5657 case ppc64::kDtraceProbe:
5658 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5659 break;
5660 case ppc64::kDtraceProbeSite:
5661 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5662 break;
5663 case ppc64::kDtraceIsEnabledSite:
5664 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5665 break;
5666 case ppc64::kDtraceTypeReference:
5667 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5668 break;
5670 // always quote by-name references
5671 if ( fToTargetName != NULL ) {
5672 strcat(temp, "\"");
5673 strcat(temp, fToTargetName);
5674 strcat(temp, "\"");
5676 else if ( fToTarget.atom != NULL ) {
5677 strcat(temp, fToTarget.atom->getDisplayName());
5679 else {
5680 strcat(temp, "NULL target");
5682 if ( fToTarget.offset != 0 )
5683 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5685 return temp;
5689 template <>
5690 const char* Reference<x86_64>::getDescription() const
5692 static char temp[2048];
5693 switch( fKind ) {
5694 case x86_64::kNoFixUp:
5695 sprintf(temp, "reference to ");
5696 break;
5697 case x86_64::kFollowOn:
5698 sprintf(temp, "followed by ");
5699 break;
5700 case x86_64::kGroupSubordinate:
5701 sprintf(temp, "group subordinate ");
5702 break;
5703 case x86_64::kPointerWeakImport:
5704 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5705 break;
5706 case x86_64::kPointer:
5707 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5708 break;
5709 case x86_64::kPointer32:
5710 sprintf(temp, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc);
5711 break;
5712 case x86_64::kPointerDiff32:
5713 case x86_64::kPointerDiff:
5715 // by-name references have quoted names
5716 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5717 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5718 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
5719 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
5720 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5721 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5722 return temp;
5724 break;
5725 case x86_64::kPCRel32:
5726 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
5727 break;
5728 case x86_64::kPCRel32_1:
5729 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
5730 break;
5731 case x86_64::kPCRel32_2:
5732 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
5733 break;
5734 case x86_64::kPCRel32_4:
5735 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
5736 break;
5737 case x86_64::kBranchPCRel32:
5738 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
5739 break;
5740 case x86_64::kBranchPCRel32WeakImport:
5741 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
5742 break;
5743 case x86_64::kPCRel32GOT:
5744 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5745 break;
5746 case x86_64::kPCRel32GOTWeakImport:
5747 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5748 break;
5749 case x86_64::kPCRel32GOTLoad:
5750 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5751 break;
5752 case x86_64::kPCRel32GOTLoadWeakImport:
5753 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5754 break;
5755 case x86_64::kGOTNoFixUp:
5756 sprintf(temp, "reference to GOT entry for ");
5757 break;
5758 case x86_64::kBranchPCRel8:
5759 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
5760 break;
5761 case x86_64::kPointerDiff24:
5762 sprintf(temp, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5763 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5764 this->getFromTargetDisplayName(), fFromTarget.offset );
5765 return temp;
5766 case x86_64::kImageOffset32:
5767 sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc);
5768 break;
5769 case x86_64::kSectionOffset24:
5770 sprintf(temp, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc);
5771 break;
5772 case x86_64::kDtraceProbe:
5773 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5774 break;
5775 case x86_64::kDtraceProbeSite:
5776 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5777 break;
5778 case x86_64::kDtraceIsEnabledSite:
5779 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5780 break;
5781 case x86_64::kDtraceTypeReference:
5782 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5783 break;
5785 // always quote by-name references
5786 if ( fToTargetName != NULL ) {
5787 strcat(temp, "\"");
5788 strcat(temp, fToTargetName);
5789 strcat(temp, "\"");
5791 else if ( fToTarget.atom != NULL ) {
5792 strcat(temp, fToTarget.atom->getDisplayName());
5794 else {
5795 strcat(temp, "NULL target");
5797 if ( fToTarget.offset != 0 )
5798 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5800 return temp;
5804 template <>
5805 const char* Reference<arm>::getDescription() const
5807 static char temp[2048];
5808 switch( fKind ) {
5809 case arm::kNoFixUp:
5810 sprintf(temp, "reference to ");
5811 break;
5812 case arm::kFollowOn:
5813 sprintf(temp, "followed by ");
5814 break;
5815 case arm::kGroupSubordinate:
5816 sprintf(temp, "group subordinate ");
5817 break;
5818 case arm::kPointer:
5819 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5820 break;
5821 case arm::kPointerWeakImport:
5822 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5823 break;
5824 case arm::kPointerDiff:
5826 // by-name references have quoted names
5827 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5828 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5829 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5830 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5831 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5832 return temp;
5834 case arm::kPointerDiff12:
5836 // by-name references have quoted names
5837 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5838 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5839 sprintf(temp, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
5840 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5841 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
5842 return temp;
5844 case arm::kReadOnlyPointer:
5845 sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc);
5846 break;
5847 case arm::kBranch24:
5848 case arm::kThumbBranch22:
5849 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5850 break;
5851 case arm::kBranch24WeakImport:
5852 case arm::kThumbBranch22WeakImport:
5853 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5854 break;
5855 case arm::kDtraceProbe:
5856 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5857 break;
5858 case arm::kDtraceProbeSite:
5859 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5860 break;
5861 case arm::kDtraceIsEnabledSite:
5862 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5863 break;
5864 case arm::kDtraceTypeReference:
5865 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5866 break;
5868 // always quote by-name references
5869 if ( fToTargetName != NULL ) {
5870 strcat(temp, "\"");
5871 strcat(temp, fToTargetName);
5872 strcat(temp, "\"");
5874 else if ( fToTarget.atom != NULL ) {
5875 strcat(temp, fToTarget.atom->getDisplayName());
5877 else {
5878 strcat(temp, "NULL target");
5880 if ( fToTarget.offset != 0 )
5881 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5883 return temp;
5887 template <>
5888 bool Reference<x86>::isBranch() const
5890 switch ( fKind ) {
5891 case x86::kPCRel32:
5892 case x86::kPCRel32WeakImport:
5893 return true;
5894 default:
5895 return false;
5899 template <>
5900 bool Reference<x86_64>::isBranch() const
5902 switch ( fKind ) {
5903 case x86_64::kBranchPCRel32:
5904 case x86_64::kBranchPCRel32WeakImport:
5905 return true;
5906 default:
5907 return false;
5911 template <>
5912 bool Reference<ppc>::isBranch() const
5914 switch ( fKind ) {
5915 case ppc::kBranch24:
5916 case ppc::kBranch24WeakImport:
5917 return true;
5918 default:
5919 return false;
5923 template <>
5924 bool Reference<ppc64>::isBranch() const
5926 switch ( fKind ) {
5927 case ppc64::kBranch24:
5928 case ppc64::kBranch24WeakImport:
5929 return true;
5930 default:
5931 return false;
5935 template <>
5936 bool Reference<arm>::isBranch() const
5938 switch ( fKind ) {
5939 case arm::kBranch24:
5940 case arm::kBranch24WeakImport:
5941 case arm::kThumbBranch22:
5942 case arm::kThumbBranch22WeakImport:
5943 return true;
5944 default:
5945 return false;
5951 }; // namespace relocatable
5952 }; // namespace mach_o
5954 #endif // __OBJECT_FILE_MACH_O__