1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __OBJECT_FILE_MACH_O__
26 #define __OBJECT_FILE_MACH_O__
31 #include <sys/param.h>
32 #include <mach-o/ppc/reloc.h>
33 #include <mach-o/stab.h>
35 #define S_ATTR_DEBUG 0x02000000
42 #include "MachOFileAbstraction.hpp"
43 #include "Architectures.hpp"
44 #include "ObjectFile.h"
46 #include "debugline.h"
51 // To implement architecture xxx, you must write template specializations for the following six methods:
52 // Reader<xxx>::validFile()
53 // Reader<xxx>::validSectionType()
54 // Reader<xxx>::addRelocReference()
55 // Reference<xxx>::getDescription()
61 extern __attribute__((noreturn)) void throwf(const char* format, ...);
64 namespace relocatable {
69 template <typename A> class Reader;
70 template <typename A> class SymbolAtomSorter;
74 AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
75 AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
76 ObjectFile::Atom* atom;
82 class Reference : public ObjectFile::Reference
85 typedef typename A::P P;
86 typedef typename A::P::uint_t pint_t;
87 typedef typename A::ReferenceKinds Kinds;
89 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
90 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
91 Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
93 virtual ~Reference() {}
96 virtual bool isTargetUnbound() const { return ( fToTarget.atom == NULL ); }
97 virtual bool isFromTargetUnbound() const { return ( fFromTarget.atom == NULL ); }
98 virtual uint8_t getKind() const { return (uint8_t)fKind; }
99 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
100 virtual const char* getTargetName() const { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); }
101 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
102 virtual uint64_t getTargetOffset() const { return fToTarget.offset; }
103 virtual bool hasFromTarget() const { return ( (fFromTarget.atom != NULL) || (fFromTargetName != NULL) ); }
104 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
105 virtual const char* getFromTargetName() const { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); }
106 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = ⌖ fToTarget.offset = offset; }
107 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
108 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = ⌖ }
109 virtual void setFromTargetName(const char* name) { fFromTargetName = name; }
110 virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; }
111 virtual const char* getDescription() const;
112 virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; }
116 pint_t fFixUpOffsetInSrc;
117 AtomAndOffset fToTarget;
118 AtomAndOffset fFromTarget;
119 const char* fToTargetName;
120 const char* fFromTargetName;
125 template <typename A>
126 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
127 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
130 // make reference a by-name where needed
131 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) ) {
132 fToTargetName = toTarget.atom->getName();
133 //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d\n", toTarget.atom, fToTargetName, toTarget.atom->getScope());
134 fToTarget.atom = NULL;
136 ((class BaseAtom*)at.atom)->addReference(this);
137 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
140 template <typename A>
141 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
142 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
143 fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
145 // make reference a by-name where needed
146 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn)
147 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
148 && (toTarget.atom != at.atom) ) {
149 fToTargetName = toTarget.atom->getName();
150 fToTarget.atom = NULL;
152 ((class BaseAtom*)at.atom)->addReference(this);
153 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
154 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
157 template <typename A>
158 Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
159 : fFixUpOffsetInSrc(at.offset),
160 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
162 fToTarget.offset = toOffset;
163 ((class BaseAtom*)at.atom)->addReference(this);
167 template <typename A>
168 class Segment : public ObjectFile::Segment
171 Segment(const macho_section<typename A::P>* sect);
172 virtual const char* getName() const { return fSection->segname(); }
173 virtual bool isContentReadable() const { return true; }
174 virtual bool isContentWritable() const { return fWritable; }
175 virtual bool isContentExecutable() const { return fExecutable; }
177 const macho_section<typename A::P>* fSection;
182 template <typename A>
183 Segment<A>::Segment(const macho_section<typename A::P>* sect)
184 : fSection(sect), fWritable(false), fExecutable(false)
186 if ( strcmp(fSection->segname(), "__DATA") == 0 ) {
189 else if ( strcmp(fSection->segname(), "__OBJC") == 0 ) {
192 else if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
195 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
202 class DataSegment : public ObjectFile::Segment
205 virtual const char* getName() const { return "__DATA"; }
206 virtual bool isContentReadable() const { return true; }
207 virtual bool isContentWritable() const { return true; }
208 virtual bool isContentExecutable() const { return false; }
210 static DataSegment fgSingleton;
213 DataSegment DataSegment::fgSingleton;
216 class BaseAtom : public ObjectFile::Atom
219 BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
221 virtual void setSize(uint64_t size) = 0;
222 virtual void addReference(ObjectFile::Reference* ref) = 0;
223 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
224 virtual void alignAtLeast(uint8_t align) = 0;
226 uint32_t fStabsStartIndex;
227 uint32_t fStabsCount;
232 // A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
233 // pointing to it. A C function or global variable is represented by one of these atoms.
236 template <typename A>
237 class SymbolAtom : public BaseAtom
240 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
241 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
242 { return fOwner.getTranslationUnitSource(dir, name); }
243 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
244 virtual const char* getDisplayName() const { return getName(); }
245 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
246 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
247 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
248 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
249 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
250 virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
251 virtual uint64_t getSize() const { return fSize; }
252 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
253 virtual bool mustRemainInSection() const { return true; }
254 virtual const char* getSectionName() const;
255 virtual Segment<A>& getSegment() const { return *fSegment; }
256 virtual bool requiresFollowOnAtom() const;
257 virtual ObjectFile::Atom& getFollowOnAtom() const;
258 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
259 virtual uint8_t getAlignment() const { return fAlignment; }
260 virtual void copyRawContent(uint8_t buffer[]) const;
261 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
262 virtual void setSize(uint64_t size);
263 virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
264 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
265 virtual void alignAtLeast(uint8_t align) { fAlignment = std::max(align, fAlignment); }
268 typedef typename A::P P;
269 typedef typename A::P::E E;
270 typedef typename A::P::uint_t pint_t;
271 typedef typename A::ReferenceKinds Kinds;
272 typedef typename std::vector<Reference<A>*> ReferenceVector;
273 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
274 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
275 friend class Reader<A>;
276 friend class SymbolAtomSorter<A>;
278 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
279 virtual ~SymbolAtom() {}
282 const macho_nlist<P>* fSymbol;
285 const macho_section<P>* fSection;
286 Segment<A>* fSegment;
287 ReferenceVector fReferences;
288 std::vector<ObjectFile::LineInfo> fLineInfo;
289 ObjectFile::Atom::Scope fScope;
294 template <typename A>
295 SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
296 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fAlignment(0)
298 uint8_t type = symbol->n_type();
299 if ( (type & N_EXT) == 0 )
300 fScope = ObjectFile::Atom::scopeTranslationUnit;
301 else if ( (type & N_PEXT) != 0 )
302 fScope = ObjectFile::Atom::scopeLinkageUnit;
304 fScope = ObjectFile::Atom::scopeGlobal;
305 if ( (type & N_TYPE) == N_SECT ) {
307 fSegment = new Segment<A>(fSection);
308 fAddress = fSymbol->n_value();
309 if ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 )
310 this->setDontDeadStrip();
313 printf("unknown symbol type: %d\n", type);
315 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
316 // support for .o files built with old ld64
317 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
318 const char* name = this->getName();
319 const int nameLen = strlen(name);
320 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
321 // switch symbol to point at name that does not have trailing $stub
322 char correctName[nameLen];
323 strncpy(correctName, name, nameLen-5);
324 correctName[nameLen-5] = '\0';
325 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
326 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
327 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
328 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
335 // support for labeled stubs
336 switch ( section->flags() & SECTION_TYPE ) {
338 setSize(section->reserved2());
340 case S_LAZY_SYMBOL_POINTERS:
341 case S_NON_LAZY_SYMBOL_POINTERS:
342 setSize(sizeof(pint_t));
344 case S_4BYTE_LITERALS:
347 case S_8BYTE_LITERALS:
350 case S_CSTRING_LITERALS:
351 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
355 // size calculate later after next atom is found
361 template <typename A>
362 void SymbolAtom<A>::setSize(uint64_t size)
366 // Try to compute the alignment base on the address aligned at in object file and the size
367 uint8_t sizeAlign = __builtin_ctz(fSize);
368 uint8_t sizeAndSectAlign = std::min((uint8_t)fSection->align(), sizeAlign);
369 // If address is zero, can't figure out better alignment than section alignment and size
371 fAlignment = sizeAndSectAlign;
373 fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), sizeAndSectAlign);
377 template <typename A>
378 const char* SymbolAtom<A>::getSectionName() const
380 if ( strlen(fSection->sectname()) > 15 ) {
381 static char temp[18];
382 strncpy(temp, fSection->sectname(), 16);
386 return fSection->sectname();
389 template <typename A>
390 bool SymbolAtom<A>::requiresFollowOnAtom() const
392 // requires follow-on if built with old compiler and not the last atom
393 if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
394 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
395 Reference<A>* ref = *it;
396 if ( ref->getKind() == A::kFollowOn )
403 template <typename A>
404 ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
406 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
407 Reference<A>* ref = *it;
408 if ( ref->getKind() == A::kFollowOn )
409 return ref->getTarget();
411 return *((ObjectFile::Atom*)NULL);
417 template <typename A>
418 void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
422 bzero(buffer, fSize);
424 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
425 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
430 template <typename A>
431 class SymbolAtomSorter
434 SymbolAtomSorter(std::map<uint32_t, BaseAtom*>& map) : fMap(map) {}
436 typedef typename A::P::uint_t pint_t;
438 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
440 pint_t leftAddr = ((SymbolAtom<A>*)left)->fAddress;
441 pint_t rightAddr = ((SymbolAtom<A>*)right)->fAddress;
442 if ( leftAddr == rightAddr ) {
443 // two atoms with same address, must have been a function with multiple labels
444 // make sure we sort these so the one with real content (in map) is last
445 std::map<uint32_t, BaseAtom*>::iterator pos = fMap.find(leftAddr);
446 if ( pos != fMap.end() ) {
447 return ( pos->second == right );
452 return ( leftAddr < rightAddr );
456 std::map<uint32_t, BaseAtom*>& fMap;
461 // A TentativeAtom represents a C "common" or "tentative" defintion of data.
462 // For instance, "int foo;" is neither a declaration or a definition and
463 // is represented by a TentativeAtom.
465 template <typename A>
466 class TentativeAtom : public BaseAtom
469 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
470 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
471 { return fOwner.getTranslationUnitSource(dir, name); }
472 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
473 virtual const char* getDisplayName() const { return getName(); }
474 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
475 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
476 virtual bool isZeroFill() const { return true; }
477 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
478 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
479 virtual uint64_t getSize() const { return fSymbol->n_value(); }
480 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
481 virtual bool mustRemainInSection() const { return true; }
482 virtual const char* getSectionName() const { return "__common"; }
483 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
484 virtual bool requiresFollowOnAtom() const { return false; }
485 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
486 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
487 virtual uint8_t getAlignment() const;
488 virtual void copyRawContent(uint8_t buffer[]) const;
489 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
490 virtual void setSize(uint64_t size) { }
491 virtual void addReference(ObjectFile::Reference* ref) { throw "can't add references"; }
492 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "can't add line info to tentative definition"; }
493 virtual void alignAtLeast(uint8_t align) { }
496 typedef typename A::P P;
497 typedef typename A::P::E E;
498 typedef typename A::P::uint_t pint_t;
499 typedef typename A::ReferenceKinds Kinds;
500 friend class Reader<A>;
502 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
503 virtual ~TentativeAtom() {}
506 const macho_nlist<P>* fSymbol;
507 ObjectFile::Atom::Scope fScope;
508 static std::vector<ObjectFile::Reference*> fgNoReferences;
511 template <typename A>
512 std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
514 template <typename A>
515 TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
516 : fOwner(owner), fSymbol(symbol)
518 uint8_t type = symbol->n_type();
519 if ( (type & N_EXT) == 0 )
520 fScope = ObjectFile::Atom::scopeTranslationUnit;
521 else if ( (type & N_PEXT) != 0 )
522 fScope = ObjectFile::Atom::scopeLinkageUnit;
524 fScope = ObjectFile::Atom::scopeGlobal;
525 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
526 // tentative definition
529 printf("unknown symbol type: %d\n", type);
531 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
535 template <typename A>
536 uint8_t TentativeAtom<A>::getAlignment() const
538 // common symbols align to their size
539 // that is, a 4-byte common aligns to 4-bytes
540 // to be safe, odd size commons align to the next power-of-2 size
541 uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
542 // limit alignment of extremely large commons to 2^15 bytes (8-page)
543 if ( alignment < 15 )
549 template <typename A>
550 void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
552 bzero(buffer, getSize());
557 // An AnonymousAtom represents compiler generated data that has no name.
558 // For instance, a literal C-string or a 64-bit floating point constant
559 // is represented by an AnonymousAtom.
561 template <typename A>
562 class AnonymousAtom : public BaseAtom
565 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
566 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
567 virtual const char* getName() const { return fSynthesizedName; }
568 virtual const char* getDisplayName() const;
569 virtual ObjectFile::Atom::Scope getScope() const;
570 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const;
571 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
572 virtual bool isZeroFill() const;
573 virtual uint64_t getSize() const { return fSize; }
574 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
575 virtual bool mustRemainInSection() const { return true; }
576 virtual const char* getSectionName() const;
577 virtual Segment<A>& getSegment() const { return *fSegment; }
578 virtual bool requiresFollowOnAtom() const;
579 virtual ObjectFile::Atom& getFollowOnAtom() const;
580 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
581 virtual uint8_t getAlignment() const;
582 virtual void copyRawContent(uint8_t buffer[]) const;
583 virtual void setScope(ObjectFile::Atom::Scope newScope) { }
584 virtual void setSize(uint64_t size) { fSize = size; }
585 virtual void addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
586 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fprintf(stderr, "can't add line info to anonymous symbol %s\n", this->getDisplayName()); }
587 virtual void alignAtLeast(uint8_t align) { }
588 BaseAtom* redirectTo() { return fRedirect; }
589 bool isWeakImportStub() { return fWeakImportStub; }
592 typedef typename A::P P;
593 typedef typename A::P::E E;
594 typedef typename A::P::uint_t pint_t;
595 typedef typename A::ReferenceKinds Kinds;
596 typedef typename std::vector<Reference<A>*> ReferenceVector;
597 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
598 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
599 friend class Reader<A>;
601 AnonymousAtom(Reader<A>&, const macho_section<P>*, uint32_t addr, uint32_t size);
602 virtual ~AnonymousAtom() {}
605 const char* fSynthesizedName;
606 const macho_section<P>* fSection;
609 Segment<A>* fSegment;
610 ReferenceVector fReferences;
612 bool fWeakImportStub;
613 bool fReallyNonLazyPointer; // HACK until compiler stops emitting anonymous non-lazy pointers
616 template <typename A>
617 AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, uint32_t addr, uint32_t size)
618 : fOwner(owner), fSynthesizedName(NULL), fSection(section), fAddress(addr), fSize(size), fSegment(NULL),
619 fWeakImportStub(false), fReallyNonLazyPointer(false)
621 fSegment = new Segment<A>(fSection);
623 uint8_t type = fSection->flags() & SECTION_TYPE;
627 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
631 // handle .o files created by old ld64 -r that are missing cstring section type
632 if ( strcmp(fSection->sectname(), "__cstring") != 0 )
634 // else fall into cstring case
635 case S_CSTRING_LITERALS:
637 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
638 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
641 case S_4BYTE_LITERALS:
643 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
644 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
647 case S_8BYTE_LITERALS:
649 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
650 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
653 case S_LITERAL_POINTERS:
655 // FIX FIX, we need the name to include the name of the target so that we can coalesce them
656 asprintf((char**)&fSynthesizedName, "literal-pointer@%d", addr - (uint32_t)fSection->addr());
659 case S_MOD_INIT_FUNC_POINTERS:
660 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
662 case S_MOD_TERM_FUNC_POINTERS:
663 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
667 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
668 index += fSection->reserved1();
669 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
670 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
671 uint32_t strOffset = sym->n_strx();
672 // want name to not have $stub suffix, this is what automatic stub generation expects
673 fSynthesizedName = &fOwner.fStrings[strOffset];
674 // check for weak import
675 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
676 // sometimes the compiler gets confused and generates a stub to a static function
677 // if so, we should redirect any call to the stub to be calls to the real static function atom
678 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_desc() & N_WEAK_DEF) == 0) ) {
679 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
680 if ( staticAtom != NULL )
681 fRedirect = staticAtom;
685 case S_LAZY_SYMBOL_POINTERS:
686 case S_NON_LAZY_SYMBOL_POINTERS:
688 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
689 index += fSection->reserved1();
690 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
691 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
692 // Silly codegen with non-lazy pointer to a local symbol
693 // All atoms not created yet, so we need to scan symbol table
694 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
695 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
696 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
697 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
698 if ( ((sym->n_type() & N_TYPE) == N_SECT) && (sym->n_value() == nonLazyPtrValue) ) {
699 const char* name = &fOwner.fStrings[sym->n_strx()];
700 char* str = new char[strlen(name)+16];
702 strcat(str, "$non_lazy_ptr");
703 fSynthesizedName = str;
704 // add direct reference to target later, because its atom may not be constructed yet
705 fOwner.fLocalNonLazys.push_back(this);
709 throwf("malformed .o file: non-lazy-pointer with value 0x%08X missing symbol", nonLazyPtrValue);
711 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
712 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
713 char* str = new char[strlen(name)+16];
715 if ( type == S_LAZY_SYMBOL_POINTERS )
716 strcat(str, "$lazy_ptr");
718 strcat(str, "$non_lazy_ptr");
719 fSynthesizedName = str;
721 if ( fOwner.isWeakImportSymbol(targetSymbol) )
722 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
724 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
728 throwf("section type %d not supported with address=0x%08X", type, addr);
730 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
734 template <typename A>
735 const char* AnonymousAtom<A>::getDisplayName() const
737 if ( fSynthesizedName != NULL )
738 return fSynthesizedName;
740 static char temp[512];
741 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
742 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
743 sprintf(temp, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
746 sprintf(temp, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
751 template <typename A>
752 ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
754 if ( fReallyNonLazyPointer )
755 return ObjectFile::Atom::scopeLinkageUnit;
756 // in order for literals to be coalesced they must be scoped to linkage unit
757 switch ( fSection->flags() & SECTION_TYPE ) {
758 case S_CSTRING_LITERALS:
759 case S_4BYTE_LITERALS:
760 case S_8BYTE_LITERALS:
762 case S_NON_LAZY_SYMBOL_POINTERS:
763 return ObjectFile::Atom::scopeLinkageUnit;
765 return ObjectFile::Atom::scopeTranslationUnit;
769 template <typename A>
770 ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
772 if ( fReallyNonLazyPointer )
773 return ObjectFile::Atom::kWeakDefinition;
774 // in order for literals to be coalesced they must be weak
775 switch ( fSection->flags() & SECTION_TYPE ) {
776 case S_CSTRING_LITERALS:
777 case S_4BYTE_LITERALS:
778 case S_8BYTE_LITERALS:
779 case S_NON_LAZY_SYMBOL_POINTERS:
780 return ObjectFile::Atom::kWeakDefinition;
782 return ObjectFile::Atom::kRegularDefinition;
786 template <typename A>
787 bool AnonymousAtom<A>::isZeroFill() const
789 return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
793 template <typename A>
794 const char* AnonymousAtom<A>::getSectionName() const
796 if ( fReallyNonLazyPointer )
797 return "__nl_symbol_ptr";
798 if ( strlen(fSection->sectname()) > 15 ) {
799 static char temp[18];
800 strncpy(temp, fSection->sectname(), 16);
804 return fSection->sectname();
807 template <typename A>
808 uint8_t AnonymousAtom<A>::getAlignment() const
810 if ( fReallyNonLazyPointer )
811 return (uint8_t)log2(sizeof(pint_t));
812 switch ( fSection->flags() & SECTION_TYPE ) {
813 case S_4BYTE_LITERALS:
815 case S_8BYTE_LITERALS:
817 case S_NON_LAZY_SYMBOL_POINTERS:
818 return (uint8_t)log2(sizeof(pint_t));
820 return fSection->align();
824 template <typename A>
825 bool AnonymousAtom<A>::requiresFollowOnAtom() const
827 // requires follow-on if built with old compiler and not the last atom
828 if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
829 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
830 Reference<A>* ref = *it;
831 if ( ref->getKind() == A::kFollowOn )
838 template <typename A>
839 ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
841 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
842 Reference<A>* ref = *it;
843 if ( ref->getKind() == A::kFollowOn )
844 return ref->getTarget();
846 return *((ObjectFile::Atom*)NULL);
849 template <typename A>
850 void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
854 bzero(buffer, fSize);
856 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
857 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
864 template <typename A>
865 class Reader : public ObjectFile::Reader
868 static bool validFile(const uint8_t* fileContent);
869 static Reader<A>* make(const uint8_t* fileContent, const char* path, time_t modTime,
870 const ObjectFile::ReaderOptions& options)
871 { return new Reader<A>(fileContent, path, modTime, options); }
874 virtual const char* getPath() { return fPath; }
875 virtual time_t getModificationTime() { return fModTime; }
876 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
877 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
878 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
879 virtual std::vector<Stab>* getStabs() { return &fStabs; }
881 bool getTranslationUnitSource(const char** dir, const char** name) const;
884 typedef typename A::P P;
885 typedef typename A::P::E E;
886 typedef typename A::P::uint_t pint_t;
887 //typedef typename std::vector<Atom<A>*> AtomVector;
888 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
889 typedef typename A::ReferenceKinds Kinds;
890 friend class AnonymousAtom<A>;
891 friend class TentativeAtom<A>;
892 friend class SymbolAtom<A>;
893 Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options);
894 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
895 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
896 Kinds pointerDiffKindForLength_powerpc(uint8_t r_length);
897 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
898 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
899 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
900 static const char* assureFullPath(const char* path);
901 AtomAndOffset findAtomAndOffset(uint32_t addr);
902 AtomAndOffset findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr);
903 Reference<A>* makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr);
904 Reference<A>* makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr);
905 Reference<A>* makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr);
906 Reference<A>* makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr);
907 Reference<A>* makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset);
908 Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
909 void validSectionType(uint8_t type);
911 BaseAtom* findAtomByName(const char*);
915 const ObjectFile::ReaderOptions& fOptions;
916 const macho_header<P>* fHeader;
917 const char* fStrings;
918 const macho_nlist<P>* fSymbols;
919 uint32_t fSymbolCount;
920 const macho_segment_command<P>* fSegment;
921 const uint32_t* fIndirectTable;
922 std::vector<ObjectFile::Atom*> fAtoms;
923 std::map<uint32_t, BaseAtom*> fAddrToAtom;
924 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
925 ObjectFile::Reader::DebugInfoKind fDebugInfo;
926 const macho_section<P>* fDwarfDebugInfoSect;
927 const macho_section<P>* fDwarfDebugAbbrevSect;
928 const macho_section<P>* fDwarfDebugLineSect;
929 const char* fDwarfTranslationUnitDir;
930 const char* fDwarfTranslationUnitFile;
931 std::map<uint32_t,const char*> fDwarfIndexToFile;
932 std::vector<Stab> fStabs;
936 template <typename A>
937 Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options)
938 : fPath(strdup(path)), fModTime(modTime), fOptions(options), fHeader((const macho_header<P>*)fileContent),
939 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
940 fDebugInfo(kDebugInfoNone), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL),
941 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL)
944 if ( ! validFile(fileContent) )
945 throw "not a valid mach-o object file";
947 // cache intersting pointers
948 const macho_header<P>* header = (const macho_header<P>*)fileContent;
949 const uint32_t cmd_count = header->ncmds();
950 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
951 const macho_load_command<P>* cmd = cmds;
952 for (uint32_t i = 0; i < cmd_count; ++i) {
953 switch (cmd->cmd()) {
956 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
957 fSymbolCount = symtab->nsyms();
958 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
959 fStrings = (char*)header + symtab->stroff();
964 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
965 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
969 if (getDebugInfoKind() != kDebugInfoDwarf)
970 fDebugInfo = kDebugInfoStabsUUID;
974 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
975 fSegment = (macho_segment_command<P>*)cmd;
979 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
981 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
982 const macho_section<P>* const sectionsEnd = §ionsStart[fSegment->nsects()];
984 // inital guess for number of atoms
985 fAtoms.reserve(fSymbolCount);
987 // add all atoms that have entries in symbol table
988 const macho_section<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
989 for (uint32_t i=0; i < fSymbolCount; ++i) {
990 const macho_nlist<P>& sym = fSymbols[i];
991 if ( (sym.n_type() & N_STAB) == 0 ) {
992 uint8_t type = (sym.n_type() & N_TYPE);
993 if ( type == N_SECT ) {
994 const macho_section<P>* section = §ions[sym.n_sect()-1];
995 bool suppress = false;
996 // ignore atoms in debugger sections
997 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
998 // ignore labels for atoms in other sections
999 switch ( section->flags() & SECTION_TYPE ) {
1001 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
1002 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
1005 case S_4BYTE_LITERALS:
1006 case S_8BYTE_LITERALS:
1007 case S_CSTRING_LITERALS:
1009 BaseAtom* newAtom = new SymbolAtom<A>(*this, &sym, section);
1010 std::map<uint32_t, BaseAtom*>::iterator pos = fAddrToAtom.find(sym.n_value());
1011 if ( pos != fAddrToAtom.end() ) {
1012 // another label to an existing address
1013 // make this one be the real one and followed by the previous
1014 BaseAtom* existingAtom = pos->second;
1015 //fprintf(stderr, "new atom %s has same address as existing atom %s\n", newAtom->getDisplayName(), existingAtom->getDisplayName());
1016 new Reference<A>(A::kFollowOn, AtomAndOffset(newAtom), AtomAndOffset(existingAtom));
1017 newAtom->setSize(0);
1020 fAddrToAtom[sym.n_value()] = newAtom;
1023 fAtoms.push_back(newAtom);
1026 case S_SYMBOL_STUBS:
1027 case S_LAZY_SYMBOL_POINTERS:
1028 case S_NON_LAZY_SYMBOL_POINTERS:
1029 // ignore symboled stubs produces by old ld64
1032 fprintf(stderr, "ld64 warning: symbol %s found in unsupported section in %s\n",
1033 &fStrings[sym.n_strx()], this->getPath());
1037 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
1038 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
1043 // sort SymbolAtoms by address
1044 std::sort(fAtoms.begin(), fAtoms.end(), SymbolAtomSorter<A>(fAddrToAtom));
1046 // add all fixed size anonymous atoms from special sections
1047 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1048 uint32_t atomSize = 0;
1049 uint8_t type (sect->flags() & SECTION_TYPE);
1050 validSectionType(type);
1051 bool suppress = false;
1053 case S_SYMBOL_STUBS:
1055 atomSize = sect->reserved2();
1057 case S_LAZY_SYMBOL_POINTERS:
1059 atomSize = sizeof(pint_t);
1061 case S_NON_LAZY_SYMBOL_POINTERS:
1062 case S_LITERAL_POINTERS:
1063 case S_MOD_INIT_FUNC_POINTERS:
1064 case S_MOD_TERM_FUNC_POINTERS:
1065 atomSize = sizeof(pint_t);
1068 atomSize = sizeof(pint_t)*2;
1070 case S_4BYTE_LITERALS:
1073 case S_8BYTE_LITERALS:
1077 if ( atomSize != 0 ) {
1078 for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
1079 uint32_t atomAddr = sect->addr() + sectOffset;
1080 // add if not already an atom at that address
1081 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
1082 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
1084 fAtoms.push_back(newAtom);
1085 fAddrToAtom[atomAddr] = newAtom->redirectTo();
1091 // add all c-string anonymous atoms
1092 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1093 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
1095 uint32_t stringAddr;
1096 BaseAtom* firstEmptyString = NULL;
1097 for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
1098 stringAddr = sect->addr() + sectOffset;
1099 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
1100 // add if not already an atom at that address
1101 if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) {
1102 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
1103 if ( stringLen == 1 ) {
1104 // because of padding it may look like there are lots of empty strings
1105 // map them all to the first empty string
1106 if ( firstEmptyString == NULL ) {
1107 firstEmptyString = newAtom;
1108 fAtoms.push_back(firstEmptyString);
1110 fAddrToAtom[stringAddr] = firstEmptyString;
1113 fAtoms.push_back(newAtom);
1114 fAddrToAtom[stringAddr] = newAtom;
1121 // create atoms to cover any non-debug ranges not handled above
1122 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1123 pint_t sectionStartAddr = sect->addr();
1124 pint_t sectionEndAddr = sect->addr() + sect->size();
1125 const bool setFollowOnAtom = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
1126 if ( sect->size() != 0 ) {
1127 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1128 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
1129 fDebugInfo = kDebugInfoDwarf;
1130 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
1131 fDwarfDebugInfoSect = sect;
1132 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
1133 fDwarfDebugAbbrevSect = sect;
1134 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
1135 fDwarfDebugLineSect = sect;
1138 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
1139 throw "object file contains old DWARF debug info - rebuild with newer compiler";
1141 uint8_t type (sect->flags() & SECTION_TYPE);
1146 // detect if compiler has generated anonymous non-lazy pointers at end of __data section
1147 // HACK BEGIN - until compiler stops generated anonymous non-lazy pointers
1148 if ( (sect->size() >= sizeof(pint_t))
1149 && ((sect->size() % sizeof(pint_t)) == 0)
1150 && (sect->align() >= log2(sizeof(pint_t)))
1151 && (strcmp(sect->sectname(), "__data") == 0)
1152 && (strcmp(sect->segname(), "__DATA") == 0) ) {
1153 // find every pointer sized external reloc from end of section and split off into own atom
1154 uint32_t possiblePointerAddress = sect->size() - sizeof(pint_t);
1155 const uint8_t* sectionContent = ((uint8_t*)(fHeader))+sect->offset();
1156 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
1157 const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
1158 for (const macho_relocation_info<P>* r = relocs; r < relocsEnd; ++r) {
1159 if ( ((r->r_address() & R_SCATTERED) == 0)
1161 && (r->r_address() == possiblePointerAddress)
1162 && (fAddrToAtom.find(possiblePointerAddress+sect->addr()) == fAddrToAtom.end())
1163 && (P::getP(*((pint_t*)(sectionContent+possiblePointerAddress))) == 0) ) {
1164 // create an anonymous atom to cover this non-lazy pointer
1165 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr()+possiblePointerAddress, sizeof(pint_t));
1166 const macho_nlist<P>* targetSymbol = &fSymbols[r->r_symbolnum()];
1168 asprintf(&name, "%s$non_lazy_ptr", &fStrings[targetSymbol->n_strx()]);
1169 newAtom->fSynthesizedName = name;
1170 newAtom->fReallyNonLazyPointer = true;
1171 fAtoms.push_back(newAtom);
1172 fAddrToAtom[sect->addr()+possiblePointerAddress] = newAtom;
1173 possiblePointerAddress -= sizeof(pint_t);
1174 sectionEndAddr -= sizeof(pint_t);
1181 // HACK END - until compiler stops generated anonymous non-lazy pointers
1182 uint32_t previousAtomAddr = 0;
1183 BaseAtom* previousAtom = NULL;
1184 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
1185 // if there is not an atom already at the start of this section, add an anonymous one
1186 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
1187 fAtoms.push_back(newAtom);
1188 fAddrToAtom[sect->addr()] = newAtom;
1189 previousAtomAddr = sectionStartAddr;
1190 previousAtom = newAtom;
1192 // calculate size of all atoms in this section and add follow-on references
1193 for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1194 // note: this algorithm depends on the map iterator returning entries in address order
1195 if ( (it->first >= sectionStartAddr) && (it->first < sectionEndAddr) ) {
1196 //fprintf(stderr, " atom %s in section\n", it->second->getDisplayName());
1197 if ( previousAtom != NULL ) {
1198 previousAtom->setSize(it->first - previousAtomAddr);
1199 // FIX FIX: this setting of followOn atoms does not work when there are multiple
1200 // labels for the same atom
1201 if ( setFollowOnAtom && (it->second != previousAtom) )
1202 makeReference(A::kFollowOn, previousAtomAddr, it->first);
1204 previousAtomAddr = it->first;
1205 previousAtom = it->second;
1208 if ( previousAtom != NULL ) {
1209 // set last atom in section
1210 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
1218 // add relocation based references
1219 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1220 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1221 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
1222 switch ( sect->flags() & SECTION_TYPE ) {
1223 case S_SYMBOL_STUBS:
1224 case S_LAZY_SYMBOL_POINTERS:
1225 // we ignore compiler generated stubs, so ignore those relocs too
1228 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
1229 const uint32_t relocCount = sect->nreloc();
1230 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
1231 for (uint32_t r = 0; r < relocCount; ++r) {
1233 if ( addRelocReference(sect, &relocs[r]) )
1236 catch (const char* msg) {
1237 throwf("in section %s,%s reloc %u: %s\n", sect->segname(), sect->sectname(), r, msg);
1244 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
1245 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
1246 AnonymousAtom<A>* localNonLazy = *it;
1247 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
1248 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
1249 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
1252 // add implicit direct reference from each C++ function to its eh info
1253 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1254 if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
1255 for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1256 // note: this algorithm depens on the map iterator returning entries in address order
1257 if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) {
1258 uint32_t ehAtomAddress = it->first;
1259 BaseAtom* ehAtom = it->second;
1260 const char* ehName = ehAtom->getName();
1261 if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) )
1262 makeReferenceToEH(ehName, ehAtomAddress, sect);
1269 //for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1270 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
1273 // add translation unit info from dwarf
1275 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1276 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
1277 // if can't parse dwarf, warn and give up
1278 fDwarfTranslationUnitFile = NULL;
1279 fDwarfTranslationUnitDir = NULL;
1280 fprintf(stderr, "ld64: warning can't parse dwarf compilation unit info in %s\n", this->getPath());
1281 fDebugInfo = kDebugInfoNone;
1285 // add line number info to atoms from dwarf
1286 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1287 // file with just data will have no __debug_line info
1288 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0) ) {
1289 // validate stmt_list
1290 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
1291 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
1292 if ( debug_line != NULL ) {
1293 struct line_reader_data* lines = line_open(&debug_line[stmtList],
1294 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
1295 struct line_info result;
1296 ObjectFile::Atom* curAtom = NULL;
1297 uint32_t curAtomOffset = 0;
1298 uint32_t curAtomAddress = 0;
1299 uint32_t curAtomSize = 0;
1300 while ( line_next (lines, &result, line_stop_line) ) {
1301 // for performance, see if in next pc is in current atom
1302 if ( (curAtom != NULL) && (result.pc <= curAtomAddress+curAtomSize) && (curAtomAddress <= result.pc) ) {
1303 curAtomOffset = result.pc - curAtomAddress;
1306 // do slow look up of atom by address
1307 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
1309 if ( curAtom == NULL )
1310 break; // file has line info but no functions
1311 curAtomOffset = ao.offset;
1312 curAtomAddress = result.pc;
1313 curAtomSize = curAtom->getSize();
1315 const char* filename;
1316 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
1317 if ( pos == fDwarfIndexToFile.end() ) {
1318 filename = line_file(lines, result.file);
1319 fDwarfIndexToFile[result.file] = filename;
1322 filename = pos->second;
1324 ObjectFile::LineInfo info;
1325 info.atomOffset = curAtomOffset;
1326 info.fileName = filename;
1327 info.lineNumber = result.line;
1328 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s\n", result.pc, result.line, filename);
1329 ((BaseAtom*)curAtom)->addLineInfo(info);
1334 fprintf(stderr, "ld64: warning could not parse dwarf line number info in %s\n", this->getPath());
1340 // if no dwarf, try processing stabs debugging info
1341 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1342 // scan symbol table for stabs entries
1343 fStabs.reserve(fSymbolCount); // reduce re-allocations
1344 BaseAtom* currentAtom = NULL;
1345 pint_t currentAtomAddress = 0;
1346 enum { start, inBeginEnd, inFun } state = start;
1347 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
1348 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
1349 uint8_t type = sym->n_type();
1350 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
1351 if ( (type & N_STAB) != 0 ) {
1352 fDebugInfo = kDebugInfoStabs;
1356 stab.other = sym->n_sect();
1357 stab.desc = sym->n_desc();
1358 stab.value = sym->n_value();
1364 // beginning of function block
1366 // fall into case to lookup atom by addresss
1369 currentAtomAddress = sym->n_value();
1370 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
1371 if ( currentAtom != NULL ) {
1372 stab.atom = currentAtom;
1373 stab.string = symString;
1376 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s\n",
1377 (uint64_t)sym->n_value(), path);
1384 // not associated with an atom, just copy
1385 stab.string = symString;
1388 // n_value field is NOT atom address ;-(
1389 // need to find atom by name match
1390 const char* colon = strchr(symString, ':');
1391 if ( colon != NULL ) {
1392 // build underscore leading name
1393 int nameLen = colon - symString;
1394 char symName[nameLen+2];
1395 strlcpy(&symName[1], symString, nameLen+1);
1397 symName[nameLen+1] = '\0';
1398 currentAtom = findAtomByName(symName);
1399 if ( currentAtom != NULL ) {
1400 stab.atom = currentAtom;
1401 stab.string = symString;
1404 if ( stab.atom == NULL ) {
1405 fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
1409 // old style stabs without BNSYM
1411 currentAtomAddress = sym->n_value();
1412 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
1413 if ( currentAtom != NULL ) {
1414 stab.atom = currentAtom;
1415 stab.string = symString;
1418 fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
1419 (uint64_t)currentAtomAddress, path);
1424 stab.string = symString;
1430 stab.string = symString;
1431 // -gfull built .o file
1434 fprintf(stderr, "unknown stabs type 0x%X in %s\n", type, path);
1438 stab.atom = currentAtom;
1446 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
1447 if ( nestedAtom != NULL ) {
1448 stab.atom = nestedAtom;
1449 stab.string = symString;
1452 fprintf(stderr, "can't find atom for stabs 0x%X at %08llX in %s\n",
1453 type, (uint64_t)sym->n_value(), path);
1459 // adjust value to be offset in atom
1460 stab.value -= currentAtomAddress;
1462 stab.string = symString;
1469 if ( sym->n_sect() != 0 ) {
1470 // found another start stab, must be really old stabs...
1471 currentAtomAddress = sym->n_value();
1472 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
1473 if ( currentAtom != NULL ) {
1474 stab.atom = currentAtom;
1475 stab.string = symString;
1478 fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
1479 (uint64_t)currentAtomAddress, path);
1483 // found ending stab, switch back to start state
1484 stab.string = symString;
1485 stab.atom = currentAtom;
1493 // adjust value to be offset in atom
1494 stab.value -= currentAtomAddress;
1495 stab.atom = currentAtom;
1498 stab.string = symString;
1502 stab.atom = currentAtom;
1503 stab.string = symString;
1508 // add to list of stabs for this .o file
1509 fStabs.push_back(stab);
1516 // special case precompiled header .o file (which has no content) to have one empty atom
1517 if ( fAtoms.size() == 0 ) {
1518 int pathLen = strlen(path);
1519 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
1520 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
1521 //phony->fSynthesizedName = ".gch.o";
1522 fAtoms.push_back(phony);
1529 template <typename A>
1530 void Reader<A>::validSectionType(uint8_t type)
1534 template <typename A>
1535 bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
1537 if ( fDebugInfo == kDebugInfoDwarf ) {
1538 *dir = fDwarfTranslationUnitDir;
1539 *name = fDwarfTranslationUnitFile;
1545 template <typename A>
1546 BaseAtom* Reader<A>::findAtomByName(const char* name)
1548 // first search the more important atoms
1549 for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
1550 const char* atomName = it->second->getName();
1551 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
1555 // try all atoms, because this might have been a tentative definition
1556 for (std::vector<ObjectFile::Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
1557 BaseAtom* atom = (BaseAtom*)(*it);
1558 const char* atomName = atom->getName();
1559 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
1566 template <typename A>
1567 Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr)
1569 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
1572 template <typename A>
1573 Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr)
1575 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
1578 template <typename A>
1579 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr)
1581 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
1584 template <typename A>
1585 Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr)
1587 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
1590 template <typename A>
1591 Reference<A>* Reader<A>::makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset)
1593 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
1596 template <typename A>
1597 Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
1599 // add a direct reference from function atom to its eh frame atom
1600 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
1601 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
1602 uint32_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
1603 return makeReference(A::kNoFixUp, funcAddr, ehAtomAddress) ;
1608 template <typename A>
1609 AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t addr)
1611 // STL has no built-in for "find largest key that is same or less than"
1612 std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.upper_bound(addr);
1613 --it; // upper_bound gets us next key, so we back up one
1614 AtomAndOffset result;
1615 result.atom = it->second;
1616 result.offset = addr - it->first;
1617 //fprintf(stderr, "findAtomAndOffset(0x%0X) ==> %s (0x%0X -> 0x%0llX)\n",
1618 // addr, result.atom->getDisplayName(), it->first, it->first+result.atom->getSize());
1622 // "scattered" relocations enable you to offset into an atom past the end of it
1623 // baseAddr is the address of the target atom,
1624 // realAddr is the points into it
1625 template <typename A>
1626 AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr)
1628 std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.find(baseAddr);
1629 if ( it != fAddrToAtom.end() ) {
1630 AtomAndOffset result;
1631 result.atom = it->second;
1632 result.offset = realAddr - it->first;
1633 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
1636 // getting here means we have a scattered relocation to an address without a label
1637 // we should never get here...
1638 // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
1639 return findAtomAndOffset(realAddr);
1643 /* Skip over a LEB128 value (signed or unsigned). */
1645 skip_leb128 (const uint8_t ** offset, const uint8_t * end)
1647 while (*offset != end && **offset >= 0x80)
1653 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
1654 or error. On overflow, skip past the rest of the uleb128. */
1656 read_uleb128 (const uint8_t ** offset, const uint8_t * end)
1658 uint64_t result = 0;
1665 return (uint64_t) -1;
1667 b = **offset & 0x7f;
1669 if (bit >= 64 || b << bit >> bit != b)
1670 result = (uint64_t) -1;
1672 result |= b << bit, bit += 7;
1673 } while (*(*offset)++ >= 0x80);
1678 /* Skip over a DWARF attribute of form FORM. */
1679 template <typename A>
1680 bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
1681 uint8_t addr_size, bool dwarf64)
1691 case DW_FORM_block2:
1692 if (end - *offset < 2)
1694 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
1697 case DW_FORM_block4:
1698 if (end - *offset < 4)
1700 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
1718 case DW_FORM_string:
1719 while (*offset != end && **offset)
1728 sz = read_uleb128 (offset, end);
1731 case DW_FORM_block1:
1739 case DW_FORM_ref_udata:
1740 skip_leb128 (offset, end);
1744 case DW_FORM_ref_addr:
1745 sz = dwarf64 ? 8 : 4;
1751 if (end - *offset < sz)
1757 // Look at the compilation unit DIE and determine
1758 // its NAME, compilation directory (in COMP_DIR) and its
1759 // line number information offset (in STMT_LIST). NAME and COMP_DIR
1760 // may be NULL (especially COMP_DIR) if they are not in the .o file;
1761 // STMT_LIST will be (uint64_t) -1.
1763 // At present this assumes that there's only one compilation unit DIE.
1765 template <typename A>
1766 bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
1767 uint64_t *stmt_list)
1769 const uint8_t * debug_info;
1770 const uint8_t * debug_abbrev;
1773 const uint8_t * end;
1774 const uint8_t * enda;
1777 uint64_t abbrev_base;
1779 uint8_t address_size;
1784 *stmt_list = (uint64_t) -1;
1786 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
1789 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
1790 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
1793 if (fDwarfDebugInfoSect->size() < 12)
1794 /* Too small to be a real debug_info section. */
1796 sz = A::P::E::get32(*(uint32_t*)di);
1798 dwarf64 = sz == 0xffffffff;
1800 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
1801 else if (sz > 0xffffff00)
1802 /* Unknown dwarf format. */
1805 /* Verify claimed size. */
1806 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
1809 vers = A::P::E::get16(*(uint16_t*)di);
1810 if (vers < 2 || vers > 3)
1811 /* DWARF version wrong for this code.
1812 Chances are we could continue anyway, but we don't know for sure. */
1816 /* Find the debug_abbrev section. */
1817 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
1818 di += dwarf64 ? 8 : 4;
1820 if (abbrev_base > fDwarfDebugAbbrevSect->size())
1822 da = debug_abbrev + abbrev_base;
1823 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
1825 address_size = *di++;
1827 /* Find the abbrev number we're looking for. */
1829 abbrev = read_uleb128 (&di, end);
1830 if (abbrev == (uint64_t) -1)
1833 /* Skip through the debug_abbrev section looking for that abbrev. */
1836 uint64_t this_abbrev = read_uleb128 (&da, enda);
1839 if (this_abbrev == abbrev)
1840 /* This is almost always taken. */
1842 skip_leb128 (&da, enda); /* Skip the tag. */
1845 da++; /* Skip the DW_CHILDREN_* value. */
1848 attr = read_uleb128 (&da, enda);
1849 skip_leb128 (&da, enda);
1850 } while (attr != 0 && attr != (uint64_t) -1);
1855 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
1856 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
1860 da++; /* Skip the DW_CHILDREN_* value. */
1862 /* Now, go through the DIE looking for DW_AT_name,
1863 DW_AT_comp_dir, and DW_AT_stmt_list. */
1866 uint64_t attr = read_uleb128 (&da, enda);
1867 uint64_t form = read_uleb128 (&da, enda);
1869 if (attr == (uint64_t) -1)
1874 if (form == DW_FORM_indirect)
1875 form = read_uleb128 (&di, end);
1877 if (attr == DW_AT_name && form == DW_FORM_string)
1878 *name = (const char *) di;
1879 else if (attr == DW_AT_comp_dir && form == DW_FORM_string)
1880 *comp_dir = (const char *) di;
1881 /* Really we should support DW_FORM_strp here, too, but
1882 there's usually no reason for the producer to use that form
1883 for the DW_AT_name and DW_AT_comp_dir attributes. */
1884 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
1885 *stmt_list = A::P::E::get32(*(uint32_t*)di);
1886 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
1887 *stmt_list = A::P::E::get64(*(uint64_t*)di);
1888 if (! skip_form (&di, end, form, address_size, dwarf64))
1893 template <typename A>
1894 const char* Reader<A>::assureFullPath(const char* path)
1896 if ( path[0] == '/' )
1898 char cwdbuff[MAXPATHLEN];
1899 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
1901 asprintf(&result, "%s/%s", cwdbuff, path);
1902 if ( result != NULL )
1911 // To implement architecture xxx, you must write template specializations for the following six methods:
1912 // Reader<xxx>::validFile()
1913 // Reader<xxx>::addRelocReference()
1914 // Reference<xxx>::getDescription()
1920 bool Reader<ppc>::validFile(const uint8_t* fileContent)
1922 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1923 if ( header->magic() != MH_MAGIC )
1925 if ( header->cputype() != CPU_TYPE_POWERPC )
1927 if ( header->filetype() != MH_OBJECT )
1933 bool Reader<ppc64>::validFile(const uint8_t* fileContent)
1935 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1936 if ( header->magic() != MH_MAGIC_64 )
1938 if ( header->cputype() != CPU_TYPE_POWERPC64 )
1940 if ( header->filetype() != MH_OBJECT )
1946 bool Reader<x86>::validFile(const uint8_t* fileContent)
1948 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1949 if ( header->magic() != MH_MAGIC )
1951 if ( header->cputype() != CPU_TYPE_I386 )
1953 if ( header->filetype() != MH_OBJECT )
1960 template <typename A>
1961 bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
1963 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
1967 bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
1969 return addRelocReference_powerpc(sect, reloc);
1973 bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
1975 return addRelocReference_powerpc(sect, reloc);
1980 // ppc and ppc64 both use the same relocations, so process them in one common routine
1982 template <typename A>
1983 bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
1984 const macho_relocation_info<typename A::P>* reloc)
1989 int32_t displacement = 0;
1990 uint32_t instruction = 0;
1991 uint32_t offsetInTarget;
1993 bool result = false;
1994 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
1995 const macho_relocation_info<P>* nextReloc = &reloc[1];
1996 const char* targetName = NULL;
1997 bool weakImport = false;
1998 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
1999 if ( reloc->r_type() != PPC_RELOC_PAIR )
2000 instruction = BigEndian::get32(*fixUpPtr);
2001 srcAddr = sect->addr() + reloc->r_address();
2002 if ( reloc->r_extern() ) {
2003 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2004 targetName = &fStrings[targetSymbol->n_strx()];
2005 weakImport = this->isWeakImportSymbol(targetSymbol);
2007 switch ( reloc->r_type() ) {
2008 case PPC_RELOC_BR24:
2010 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2011 displacement = (instruction & 0x03FFFFFC);
2012 if ( (displacement & 0x02000000) != 0 )
2013 displacement |= 0xFC000000;
2016 printf("bad instruction for BR24 reloc");
2018 if ( reloc->r_extern() ) {
2019 offsetInTarget = srcAddr + displacement;
2021 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
2023 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
2026 dstAddr = srcAddr + displacement;
2027 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2028 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
2029 if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
2030 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
2031 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
2033 makeReference(A::kBranch24, srcAddr, dstAddr);
2037 case PPC_RELOC_BR14:
2039 displacement = (instruction & 0x0000FFFC);
2040 if ( (displacement & 0x00008000) != 0 )
2041 displacement |= 0xFFFF0000;
2042 if ( reloc->r_extern() ) {
2043 offsetInTarget = srcAddr + displacement;
2044 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
2047 dstAddr = srcAddr + displacement;
2048 makeReference(A::kBranch14, srcAddr, dstAddr);
2052 case PPC_RELOC_PAIR:
2053 // skip, processed by a previous look ahead
2055 case PPC_RELOC_LO16:
2057 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2058 printf("PPC_RELOC_LO16 missing following pair\n");
2062 lowBits = (instruction & 0xFFFF);
2063 if ( reloc->r_extern() ) {
2064 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2065 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
2068 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
2069 makeReference(A::kAbsLow16, srcAddr, dstAddr);
2073 case PPC_RELOC_LO14:
2075 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2076 printf("PPC_RELOC_LO14 missing following pair\n");
2080 lowBits = (instruction & 0xFFFC);
2081 if ( reloc->r_extern() ) {
2082 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2083 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
2086 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2087 Reference<A>* ref = makeReference(A::kAbsLow14, srcAddr, dstAddr);
2088 BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
2089 if ( target != NULL )
2090 target->alignAtLeast(2);
2094 case PPC_RELOC_HI16:
2096 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2097 printf("PPC_RELOC_HI16 missing following pair\n");
2101 if ( reloc->r_extern() ) {
2102 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
2103 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
2106 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
2107 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
2111 case PPC_RELOC_HA16:
2113 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2114 printf("PPC_RELOC_HA16 missing following pair\n");
2118 lowBits = (nextReloc->r_address() & 0x0000FFFF);
2119 if ( reloc->r_extern() ) {
2120 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
2121 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
2124 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
2125 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
2129 case PPC_RELOC_VANILLA:
2131 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
2132 if ( reloc->r_extern() ) {
2134 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
2136 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
2139 makeReference(A::kPointer, srcAddr, pointerValue);
2143 case PPC_RELOC_JBSR:
2144 // this is from -mlong-branch codegen. We ignore the jump island
2145 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2146 printf("PPC_RELOC_JBSR missing following pair\n");
2150 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
2153 printf("unknown relocation type %d\n", reloc->r_type());
2157 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2158 srcAddr = sect->addr() + sreloc->r_address();
2159 dstAddr = sreloc->r_value();
2160 uint32_t betterDstAddr;
2161 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
2162 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
2163 const macho_relocation_info<P>* nextReloc = &reloc[1];
2164 // file format allows pair to be scattered or not
2165 bool nextRelocIsPair = false;
2166 uint32_t nextRelocAddress = 0;
2167 uint32_t nextRelocValue = 0;
2168 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
2169 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
2170 nextRelocIsPair = true;
2171 nextRelocAddress = nextReloc->r_address();
2176 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
2177 nextRelocIsPair = true;
2178 nextRelocAddress = nextSReloc->r_address();
2179 nextRelocValue = nextSReloc->r_value();
2183 switch (sreloc->r_type()) {
2184 case PPC_RELOC_VANILLA:
2186 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
2187 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
2188 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
2189 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
2192 case PPC_RELOC_BR14:
2194 instruction = BigEndian::get32(*fixUpPtr);
2195 displacement = (instruction & 0x0000FFFC);
2196 if ( (displacement & 0x00008000) != 0 )
2197 displacement |= 0xFFFF0000;
2198 betterDstAddr = srcAddr+displacement;
2199 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
2200 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
2203 case PPC_RELOC_BR24:
2205 instruction = BigEndian::get32(*fixUpPtr);
2206 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2207 displacement = (instruction & 0x03FFFFFC);
2208 if ( (displacement & 0x02000000) != 0 )
2209 displacement |= 0xFC000000;
2210 betterDstAddr = srcAddr+displacement;
2211 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
2215 case PPC_RELOC_LO16_SECTDIFF:
2217 if ( ! nextRelocIsPair ) {
2218 printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
2221 instruction = BigEndian::get32(*fixUpPtr);
2222 lowBits = (instruction & 0xFFFF);
2223 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2224 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
2227 case PPC_RELOC_LO14_SECTDIFF:
2229 if ( ! nextRelocIsPair ) {
2230 printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
2233 instruction = BigEndian::get32(*fixUpPtr);
2234 lowBits = (instruction & 0xFFFC);
2235 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
2236 Reference<A>* ref = makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
2237 BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
2238 if ( target != NULL ) // can be NULL if target is turned into by-name reference
2239 target->alignAtLeast(2);
2242 case PPC_RELOC_HA16_SECTDIFF:
2244 if ( ! nextRelocIsPair ) {
2245 printf("PPC_RELOC_HA16_SECTDIFF missing following PAIR\n");
2248 instruction = BigEndian::get32(*fixUpPtr);
2249 lowBits = (nextRelocAddress & 0x0000FFFF);
2250 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
2251 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
2254 case PPC_RELOC_LO14:
2256 if ( ! nextRelocIsPair ) {
2257 printf("PPC_RELOC_LO14 missing following PAIR\n");
2260 instruction = BigEndian::get32(*fixUpPtr);
2261 lowBits = (instruction & 0xFFFC);
2262 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
2263 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
2266 case PPC_RELOC_LO16:
2268 if ( ! nextRelocIsPair ) {
2269 printf("PPC_RELOC_LO16 missing following PAIR\n");
2272 instruction = BigEndian::get32(*fixUpPtr);
2273 lowBits = (instruction & 0xFFFF);
2274 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
2275 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
2278 case PPC_RELOC_HA16:
2280 if ( ! nextRelocIsPair ) {
2281 printf("PPC_RELOC_HA16 missing following PAIR\n");
2284 instruction = BigEndian::get32(*fixUpPtr);
2285 lowBits = (nextRelocAddress & 0xFFFF);
2286 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
2287 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
2290 case PPC_RELOC_SECTDIFF:
2291 case PPC_RELOC_LOCAL_SECTDIFF:
2293 if ( ! nextRelocIsPair ) {
2294 printf("PPC_RELOC_SECTDIFF missing following pair\n");
2297 makeReference(pointerDiffKindForLength_powerpc(sreloc->r_length()), srcAddr, nextRelocValue, dstAddr);
2300 case PPC_RELOC_PAIR:
2302 case PPC_RELOC_HI16_SECTDIFF:
2303 printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
2306 printf("unknown scattered relocation type %d\n", sreloc->r_type());
2313 ppc::ReferenceKinds Reader<ppc>::pointerDiffKindForLength_powerpc(uint8_t r_length)
2315 if ( r_length == 2 )
2316 return ppc::kPointerDiff32;
2318 throw "bad diff relocations r_length for ppc architecture";
2322 ppc64::ReferenceKinds Reader<ppc64>::pointerDiffKindForLength_powerpc(uint8_t r_length)
2324 if ( r_length == 2 )
2325 return ppc64::kPointerDiff32;
2326 else if ( r_length == 3 )
2327 return ppc64::kPointerDiff64;
2329 throw "bad diff relocations r_length for ppc64 architecture";
2333 bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
2338 bool result = false;
2339 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2340 srcAddr = sect->addr() + reloc->r_address();
2341 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2342 switch ( reloc->r_type() ) {
2343 case GENERIC_RELOC_VANILLA:
2345 if ( reloc->r_length() != 2 )
2346 throw "bad vanilla relocation length";
2347 x86::ReferenceKinds kind;
2348 uint32_t pointerValue = E::get32(*fixUpPtr);
2349 if ( reloc->r_pcrel() ) {
2350 kind = x86::kPCRel32;
2351 pointerValue += srcAddr + sizeof(uint32_t);
2354 kind = x86::kPointer;
2356 if ( reloc->r_extern() ) {
2357 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2358 if ( this->isWeakImportSymbol(targetSymbol) )
2359 kind = x86::kPointerWeakImport;
2360 const char* targetName = &fStrings[targetSymbol->n_strx()];
2361 makeByNameReference(kind, srcAddr, targetName, pointerValue);
2364 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2365 ObjectFile::Atom* atom = findAtomAndOffset(pointerValue).atom;
2366 if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
2367 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
2368 makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
2370 makeReference(kind, srcAddr, pointerValue);
2375 printf("unknown relocation type %d\n", reloc->r_type());
2379 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2380 srcAddr = sect->addr() + sreloc->r_address();
2381 dstAddr = sreloc->r_value();
2382 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
2383 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
2384 const macho_relocation_info<P>* nextReloc = &reloc[1];
2385 pint_t betterDstAddr;
2386 // file format allows pair to be scattered or not
2387 bool nextRelocIsPair = false;
2388 uint32_t nextRelocAddress = 0;
2389 uint32_t nextRelocValue = 0;
2390 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
2391 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
2392 nextRelocIsPair = true;
2393 nextRelocAddress = nextReloc->r_address();
2398 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
2399 nextRelocIsPair = true;
2400 nextRelocAddress = nextSReloc->r_address();
2401 nextRelocValue = nextSReloc->r_value();
2404 switch (sreloc->r_type()) {
2405 case GENERIC_RELOC_VANILLA:
2406 betterDstAddr = LittleEndian::get32(*fixUpPtr);
2407 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
2408 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
2409 if ( sreloc->r_pcrel() ) {
2410 betterDstAddr += srcAddr + 4;
2411 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
2414 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
2417 case GENERIC_RELOC_SECTDIFF:
2418 case GENERIC_RELOC_LOCAL_SECTDIFF:
2420 if ( !nextRelocIsPair ) {
2421 printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
2424 if ( sreloc->r_length() != 2 )
2425 throw "bad length for GENERIC_RELOC_SECTDIFF";
2426 betterDstAddr = LittleEndian::get32(*fixUpPtr);
2427 makeReferenceWithToBase(x86::kPointerDiff, srcAddr, nextRelocValue, betterDstAddr+nextRelocValue, dstAddr);
2430 case GENERIC_RELOC_PAIR:
2431 // do nothing, already used via a look ahead
2434 printf("unknown scattered relocation type %d\n", sreloc->r_type());
2443 const char* Reference<x86>::getDescription() const
2445 static char temp[1024];
2448 sprintf(temp, "reference to ");
2450 case x86::kFollowOn:
2451 sprintf(temp, "followed by ");
2453 case x86::kPointerWeakImport:
2454 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
2457 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
2459 case x86::kPointerDiff:
2461 // by-name references have quoted names
2462 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
2463 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
2464 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
2465 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
2466 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
2470 case x86::kPCRel32WeakImport:
2471 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
2474 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
2477 // always quote by-name references
2478 if ( fToTargetName != NULL ) {
2480 strcat(temp, fToTargetName);
2483 else if ( fToTarget.atom != NULL ) {
2484 strcat(temp, fToTarget.atom->getDisplayName());
2487 strcat(temp, "NULL target");
2489 if ( fToTarget.offset != 0 )
2490 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
2497 const char* Reference<ppc>::getDescription() const
2499 static char temp[1024];
2502 sprintf(temp, "reference to ");
2504 case ppc::kFollowOn:
2505 sprintf(temp, "followed by ");
2507 case ppc::kPointerWeakImport:
2508 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
2511 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
2513 case ppc::kPointerDiff32:
2515 // by-name references have quoted names
2516 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
2517 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
2518 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
2519 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
2520 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
2523 case ppc::kPointerDiff64:
2524 throw "unsupported refrence kind";
2526 case ppc::kBranch24WeakImport:
2527 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
2529 case ppc::kBranch24:
2530 case ppc::kBranch14:
2531 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
2533 case ppc::kPICBaseLow16:
2534 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2536 case ppc::kPICBaseLow14:
2537 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2539 case ppc::kPICBaseHigh16:
2540 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2542 case ppc::kAbsLow16:
2543 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2545 case ppc::kAbsLow14:
2546 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
2548 case ppc::kAbsHigh16:
2549 sprintf(temp, "offset 0x%04X, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2551 case ppc::kAbsHigh16AddLow:
2552 sprintf(temp, "offset 0x%04X, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2555 // always quote by-name references
2556 if ( fToTargetName != NULL ) {
2558 strcat(temp, fToTargetName);
2561 else if ( fToTarget.atom != NULL ) {
2562 strcat(temp, fToTarget.atom->getDisplayName());
2565 strcat(temp, "NULL target");
2567 if ( fToTarget.offset != 0 )
2568 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
2574 const char* Reference<ppc64>::getDescription() const
2576 static char temp[1024];
2578 case ppc64::kNoFixUp:
2579 sprintf(temp, "reference to ");
2581 case ppc64::kFollowOn:
2582 sprintf(temp, "followed by ");
2584 case ppc64::kPointerWeakImport:
2585 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
2587 case ppc64::kPointer:
2588 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
2590 case ppc64::kPointerDiff64:
2592 // by-name references have quoted names
2593 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
2594 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
2595 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
2596 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
2597 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
2600 case ppc64::kPointerDiff32:
2602 // by-name references have quoted names
2603 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
2604 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
2605 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
2606 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
2607 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
2610 case ppc64::kBranch24WeakImport:
2611 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
2613 case ppc64::kBranch24:
2614 case ppc64::kBranch14:
2615 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
2617 case ppc64::kPICBaseLow16:
2618 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2620 case ppc64::kPICBaseLow14:
2621 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2623 case ppc64::kPICBaseHigh16:
2624 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
2626 case ppc64::kAbsLow16:
2627 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2629 case ppc64::kAbsLow14:
2630 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
2632 case ppc64::kAbsHigh16:
2633 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2635 case ppc64::kAbsHigh16AddLow:
2636 sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", fFixUpOffsetInSrc);
2639 // always quote by-name references
2640 if ( fToTargetName != NULL ) {
2642 strcat(temp, fToTargetName);
2645 else if ( fToTarget.atom != NULL ) {
2646 strcat(temp, fToTarget.atom->getDisplayName());
2649 strcat(temp, "NULL target");
2651 if ( fToTarget.offset != 0 )
2652 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
2660 }; // namespace relocatable
2661 }; // namespace mach_o
2663 #endif // __OBJECT_FILE_MACH_O__