]> git.saurik.com Git - apple/ld64.git/blame - src/ld/MachOReaderRelocatable.hpp
ld64-97.17.tar.gz
[apple/ld64.git] / src / ld / MachOReaderRelocatable.hpp
CommitLineData
d696c285
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
55e3d2f6 3 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
d696c285
A
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#ifndef __OBJECT_FILE_MACH_O__
26#define __OBJECT_FILE_MACH_O__
27
28#include <stdint.h>
29#include <math.h>
30#include <unistd.h>
31#include <sys/param.h>
d696c285
A
32
33#include <vector>
34#include <set>
35#include <algorithm>
36
37#include "MachOFileAbstraction.hpp"
38#include "Architectures.hpp"
39#include "ObjectFile.h"
40#include "dwarf2.h"
41#include "debugline.h"
42
55e3d2f6
A
43#include <libunwind/DwarfInstructions.hpp>
44#include <libunwind/AddressSpace.hpp>
45#include <libunwind/Registers.hpp>
d696c285
A
46
47//
48//
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()
54//
55//
56
57
58
59extern __attribute__((noreturn)) void throwf(const char* format, ...);
2f2f92e4 60extern void warning(const char* format, ...);
d696c285
A
61
62namespace mach_o {
63namespace relocatable {
64
65
66
74cfe461
A
67class ReferenceSorter
68{
69public:
70 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
71 {
72 return ( left->getFixUpOffset() < right->getFixUpOffset() );
73 }
74};
75
76
d696c285
A
77// forward reference
78template <typename A> class Reader;
d696c285
A
79
80struct AtomAndOffset
81{
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;
86};
87
88
89template <typename A>
90class Reference : public ObjectFile::Reference
91{
92public:
93 typedef typename A::P P;
94 typedef typename A::P::uint_t pint_t;
95 typedef typename A::ReferenceKinds Kinds;
96
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);
100
101 virtual ~Reference() {}
102
103
a61fdf0a
A
104 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const;
105 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const;
d696c285
A
106 virtual uint8_t getKind() const { return (uint8_t)fKind; }
107 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
55e3d2f6 108 virtual const char* getTargetName() const { return (fToTarget.atom != NULL) ? fToTarget.atom->getName() : fToTargetName; }
d696c285 109 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
69a49097 110 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
d696c285 111 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
55e3d2f6
A
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; }
d696c285
A
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; }
55e3d2f6
A
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; }
d696c285 123
a61fdf0a 124 static bool fgForFinalLinkedImage;
d696c285
A
125
126private:
127 pint_t fFixUpOffsetInSrc;
128 AtomAndOffset fToTarget;
129 AtomAndOffset fFromTarget;
130 const char* fToTargetName;
131 const char* fFromTargetName;
132 Kinds fKind;
a61fdf0a 133
d696c285
A
134};
135
55e3d2f6 136
a61fdf0a 137template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
d696c285
A
138
139template <typename A>
140Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
141 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
142 fKind(kind)
143{
69a49097
A
144 // make reference a by-name unless:
145 // - the reference type is only used with direct references
146 // - the target is translation unit scoped
a61fdf0a 147 // - the target kind is not regular (is weak or tentative)
2f2f92e4 148 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
a61fdf0a 149 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
77cc3118
A
150 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
151 && (toTarget.atom != at.atom) ) {
69a49097 152 fToTargetName = toTarget.atom->getName();
a61fdf0a 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());
d696c285
A
154 fToTarget.atom = NULL;
155 }
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);
158}
159
160template <typename A>
161Reference<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)
164{
165 // make reference a by-name where needed
2f2f92e4 166 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
d696c285 167 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
a61fdf0a 168 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
d696c285
A
169 && (toTarget.atom != at.atom) ) {
170 fToTargetName = toTarget.atom->getName();
171 fToTarget.atom = NULL;
172 }
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);
176}
177
178template <typename A>
179Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
180 : fFixUpOffsetInSrc(at.offset),
181 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
182{
183 fToTarget.offset = toOffset;
184 ((class BaseAtom*)at.atom)->addReference(this);
185}
186
a61fdf0a
A
187template <typename A>
188ObjectFile::Reference::TargetBinding Reference<A>::getTargetBinding() const
189{
190 if ( fgForFinalLinkedImage ) {
191 if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) )
192 return ObjectFile::Reference::kDontBind;
193 }
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;
200}
201
202template <typename A>
203ObjectFile::Reference::TargetBinding Reference<A>::getFromTargetBinding() const
204{
205 if ( fFromTarget.atom == NULL ) {
206 if ( fFromTargetName == NULL )
207 return ObjectFile::Reference::kDontBind;
208 else
209 return ObjectFile::Reference::kUnboundByName;
210 }
211 else {
212 if ( fFromTargetName == NULL )
213 return ObjectFile::Reference::kBoundDirectly;
214 else
215 return ObjectFile::Reference::kBoundByName;
216 }
217}
218
219
d696c285
A
220
221template <typename A>
222class Segment : public ObjectFile::Segment
223{
224public:
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; }
230private:
231 const macho_section<typename A::P>* fSection;
232 bool fWritable;
233 bool fExecutable;
234};
235
236template <typename A>
237Segment<A>::Segment(const macho_section<typename A::P>* sect)
69a49097 238 : fSection(sect), fWritable(true), fExecutable(false)
d696c285 239{
69a49097
A
240 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
241 fWritable = false;
d696c285
A
242 fExecutable = true;
243 }
244 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
245 fWritable = true;
246 fExecutable = true;
247 }
248}
249
250
251class DataSegment : public ObjectFile::Segment
252{
253public:
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; }
258
259 static DataSegment fgSingleton;
260};
261
262DataSegment DataSegment::fgSingleton;
263
a61fdf0a
A
264class LinkEditSegment : public ObjectFile::Segment
265{
266public:
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; }
271
272 static LinkEditSegment fgSingleton;
273};
274
275LinkEditSegment LinkEditSegment::fgSingleton;
d696c285
A
276
277class BaseAtom : public ObjectFile::Atom
278{
279public:
55e3d2f6 280 BaseAtom() : fStabsStartIndex(0), fStabsCount(0), fHasCompactUnwindInfo(false) {}
d696c285 281
55e3d2f6 282 virtual void setSize(uint64_t size) = 0;
d696c285 283 virtual void addReference(ObjectFile::Reference* ref) = 0;
74cfe461 284 virtual void sortReferences() = 0;
d696c285 285 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
55e3d2f6 286 virtual const ObjectFile::ReaderOptions& getOptions() const = 0;
a61fdf0a
A
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;
4be885f6 291 virtual unsigned int getSectionIndex() const = 0;
a61fdf0a 292 virtual bool isAlias() const { return false; }
55e3d2f6
A
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();
fb24a050 299 virtual ObjectFile::Reference* getFDE();
55e3d2f6
A
300 virtual Atom* getPersonalityPointer();
301 virtual void setCompactUnwindEncoding(uint64_t ehAtomAddress);
d696c285
A
302
303 uint32_t fStabsStartIndex;
304 uint32_t fStabsCount;
a61fdf0a 305 uint32_t fOrdinal;
55e3d2f6
A
306 ObjectFile::UnwindInfo fSingleUnwindInfo[1];
307 bool fHasCompactUnwindInfo;
a61fdf0a
A
308};
309
55e3d2f6
A
310
311ObjectFile::Reference* BaseAtom::getLSDA()
312{
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;
319 }
320 }
321 return NULL;
322}
323
fb24a050
A
324ObjectFile::Reference* BaseAtom::getFDE()
325{
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;
332 }
333 }
334 return NULL;
335}
336
55e3d2f6
A
337ObjectFile::Atom* BaseAtom::getPersonalityPointer()
338{
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();
348 }
349 }
350 return NULL;
351}
352
353
354void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress)
355{
356 fSingleUnwindInfo[0].unwindInfo = this->getCompactUnwindEncoding(ehAtomAddress);
357 fHasCompactUnwindInfo = true;
358}
359
360
a61fdf0a
A
361class BaseAtomSorter
362{
363public:
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;
371 }
372 else if ( leftAddr > rightAddr ) {
373 return false;
374 }
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 );
381 }
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 );
391 }
392 // sort multiple aliases for same address then by name
393 return ( strcmp(left->getName(), right->getName()) < 0 );
394 }
395 else if ( leftAlias ) {
396 return true;
397 }
398 else if ( rightAlias ) {
399 return false;
400 }
4be885f6
A
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;
409 }
410 switch ( right->getContentType() ) {
411 case ObjectFile::Atom::kSectionStart:
412 return false;
413 case ObjectFile::Atom::kSectionEnd:
414 return true;
415 default:
416 break;
417 }
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;
a61fdf0a
A
431 }
432 }
433 return false;
434 }
d696c285
A
435};
436
437
438//
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.
441//
442//
443template <typename A>
444class SymbolAtom : public BaseAtom
445{
446public:
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; }
55e3d2f6 455 virtual ObjectFile::Atom::ContentType getContentType() const { return fType; }
69a49097 456 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
a61fdf0a 457 virtual bool dontDeadStrip() const;
4be885f6 458 virtual bool isZeroFill() const;
2f2f92e4 459 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
d696c285
A
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; }
d696c285
A
465 virtual ObjectFile::Atom& getFollowOnAtom() const;
466 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
74cfe461 467 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
d696c285
A
468 virtual void copyRawContent(uint8_t buffer[]) const;
469 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
a61fdf0a 470 virtual void setSize(uint64_t size);
74cfe461
A
471 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
472 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
d696c285 473 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
55e3d2f6 474 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
a61fdf0a
A
475 virtual uint64_t getObjectAddress() const { return fAddress; }
476 virtual const void* getSectionRecord() const { return (const void*)fSection; }
4be885f6 477 virtual unsigned int getSectionIndex() const { return 1 + (fSection - fOwner.fSectionsStart); }
55e3d2f6
A
478 virtual uint8_t getLSDAReferenceKind() const;
479 virtual uint8_t getPersonalityReferenceKind() const;
480 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
d696c285
A
481
482protected:
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>;
d696c285
A
491
492 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
493 virtual ~SymbolAtom() {}
494
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;
69a49097 504 SymbolTableInclusion fSymbolTableInclusion;
55e3d2f6 505 ObjectFile::Atom::ContentType fType;
74cfe461 506 ObjectFile::Alignment fAlignment;
d696c285
A
507};
508
509
510template <typename A>
511SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
55e3d2f6 512 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fType(ObjectFile::Atom::kUnclassifiedType), fAlignment(0)
d696c285 513{
55e3d2f6
A
514 fSingleUnwindInfo[0].startOffset = 0;
515 fSingleUnwindInfo[0].unwindInfo = 0;
d696c285
A
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();
2f2f92e4
A
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) );
533 }
69a49097 534 }
d696c285 535 else {
2f2f92e4 536 warning("unknown symbol type: %d", type);
d696c285 537 }
2f2f92e4 538
d696c285
A
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;
555 }
556 }
557 }
558 }
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;
69a49097
A
574 case S_16BYTE_LITERALS:
575 setSize(16);
576 break;
d696c285
A
577 case S_CSTRING_LITERALS:
578 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
55e3d2f6 579 fType = ObjectFile::Atom::kCStringType;
69a49097 580 break;
d696c285
A
581 case S_REGULAR:
582 case S_ZEROFILL:
583 case S_COALESCED:
584 // size calculate later after next atom is found
585 break;
586 }
69a49097 587
77cc3118
A
588 // compute alignment
589 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
590
69a49097
A
591 // compute whether this atom needs to be in symbol table
592 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
593 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
594 }
a61fdf0a
A
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;
599 }
69a49097
A
600 else {
601 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
602 }
a61fdf0a
A
603
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;
608}
609
fb24a050 610
a61fdf0a
A
611template <typename A>
612bool SymbolAtom<A>::dontDeadStrip() const
613{
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 );
d696c285
A
619}
620
621
622template <typename A>
623const char* SymbolAtom<A>::getSectionName() const
624{
55e3d2f6
A
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";
640 }
641 }
642 }
a61fdf0a 643
d696c285
A
644 if ( strlen(fSection->sectname()) > 15 ) {
645 static char temp[18];
646 strncpy(temp, fSection->sectname(), 16);
647 temp[17] = '\0';
648 return temp;
649 }
650 return fSection->sectname();
651}
652
d696c285
A
653template <typename A>
654ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
655{
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();
660 }
661 return *((ObjectFile::Atom*)NULL);
662}
663
4be885f6
A
664template <typename A>
665bool SymbolAtom<A>::isZeroFill() const
666{
667 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
668}
669
d696c285 670
a61fdf0a
A
671class Beyond
672{
673public:
674 Beyond(uint64_t offset) : fOffset(offset) {}
675 bool operator()(ObjectFile::Reference* ref) const {
676 return ( ref->getFixUpOffset() >= fOffset );
677 }
678private:
679 uint64_t fOffset;
680};
681
d696c285 682
a61fdf0a
A
683template <typename A>
684void SymbolAtom<A>::setSize(uint64_t size)
685{
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;
691}
d696c285
A
692
693template <typename A>
694void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
695{
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);
702 }
703}
704
55e3d2f6
A
705
706
707
a61fdf0a
A
708//
709// A SymbolAliasAtom represents an alternate name for a SymbolAtom
710//
711//
d696c285 712template <typename A>
a61fdf0a 713class SymbolAliasAtom : public BaseAtom
d696c285
A
714{
715public:
a61fdf0a
A
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(); }
2f2f92e4 726 virtual bool isThumb() const { return fAliasOf.isThumb(); }
a61fdf0a
A
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) { }
55e3d2f6 741 virtual const ObjectFile::ReaderOptions& getOptions() const { return fAliasOf.getOptions(); }
a61fdf0a
A
742 virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); }
743 virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); }
4be885f6 744 virtual unsigned int getSectionIndex() const { return fAliasOf.getSectionIndex(); }
a61fdf0a
A
745 virtual bool isAlias() const { return true; }
746
747protected:
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>;
753
754 SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
755 virtual ~SymbolAliasAtom() {}
756
757 const char* fName;
758 const BaseAtom& fAliasOf;
759 ObjectFile::Atom::Scope fScope;
760 bool fDontDeadStrip;
761 ReferenceVector fReferences;
d696c285
A
762};
763
764
a61fdf0a
A
765template <typename A>
766SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
767 : fName(name), fAliasOf(aliasOf)
768{
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);
779 }
780 else {
781 // aliases defined on the command line are initially global scope
782 fScope = ObjectFile::Atom::scopeGlobal;
783 fDontDeadStrip = false;
784 }
785 // add follow-on reference to real atom
786 new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
787}
788
789
d696c285
A
790//
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.
794//
795template <typename A>
796class TentativeAtom : public BaseAtom
797{
798public:
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; }
4be885f6 806 virtual bool isZeroFill() const { return fOwner.fOptions.fOptimizeZeroFill; }
2f2f92e4 807 virtual bool isThumb() const { return false; }
d696c285
A
808 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
809 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
69a49097 810 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
d696c285
A
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; }
a61fdf0a 814 virtual const char* getSectionName() const;
d696c285 815 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
d696c285
A
816 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
817 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
74cfe461 818 virtual ObjectFile::Alignment getAlignment() const;
d696c285
A
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) { }
a61fdf0a 822 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
74cfe461 823 virtual void sortReferences() { }
a61fdf0a 824 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
55e3d2f6 825 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
a61fdf0a
A
826 virtual uint64_t getObjectAddress() const { return ULLONG_MAX; }
827 virtual const void* getSectionRecord() const { return NULL; }
4be885f6 828 virtual unsigned int getSectionIndex() const { return 0; }
d696c285
A
829
830protected:
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>;
836
837 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
838 virtual ~TentativeAtom() {}
839
840 Reader<A>& fOwner;
841 const macho_nlist<P>* fSymbol;
842 ObjectFile::Atom::Scope fScope;
843 static std::vector<ObjectFile::Reference*> fgNoReferences;
844};
845
846template <typename A>
847std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
848
849template <typename A>
850TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
851 : fOwner(owner), fSymbol(symbol)
852{
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
862 }
863 else {
2f2f92e4 864 warning("unknown symbol type: %d", type);
d696c285
A
865 }
866 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
867}
868
869
870template <typename A>
74cfe461 871ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
d696c285 872{
a61fdf0a
A
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;
883 }
d696c285 884 // limit alignment of extremely large commons to 2^15 bytes (8-page)
a61fdf0a 885 if ( alignment < 12 )
74cfe461 886 return ObjectFile::Alignment(alignment);
d696c285 887 else
a61fdf0a
A
888 return ObjectFile::Alignment(12);
889}
890
891template <typename A>
892const char* TentativeAtom<A>::getSectionName() const
893{
894 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
895 return "__common";
896 else
897 return "._tentdef";
d696c285
A
898}
899
a61fdf0a 900
d696c285
A
901template <typename A>
902void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
903{
904 bzero(buffer, getSize());
905}
906
907
908//
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.
912//
913template <typename A>
914class AnonymousAtom : public BaseAtom
915{
916public:
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;
2f2f92e4 922 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; }
55e3d2f6 923 virtual ObjectFile::Atom::ContentType getContentType() const { return fType; }
69a49097
A
924 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
925 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
d696c285 926 virtual bool isZeroFill() const;
2f2f92e4 927 virtual bool isThumb() const { return false; }
d696c285
A
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; }
d696c285
A
933 virtual ObjectFile::Atom& getFollowOnAtom() const;
934 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
74cfe461 935 virtual ObjectFile::Alignment getAlignment() const;
d696c285 936 virtual void copyRawContent(uint8_t buffer[]) const;
69a49097 937 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
d696c285 938 virtual void setSize(uint64_t size) { fSize = size; }
74cfe461
A
939 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
940 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
fb24a050 941 virtual void addLineInfo(const ObjectFile::LineInfo& info);
55e3d2f6 942 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
a61fdf0a
A
943 virtual uint64_t getObjectAddress() const { return fAddress; }
944 virtual const void* getSectionRecord() const { return (const void*)fSection; }
4be885f6 945 virtual unsigned int getSectionIndex() const { return fSectionIndex; }
d696c285
A
946 BaseAtom* redirectTo() { return fRedirect; }
947 bool isWeakImportStub() { return fWeakImportStub; }
a61fdf0a 948 void resolveName();
55e3d2f6
A
949 virtual uint8_t getLSDAReferenceKind() const;
950 virtual uint8_t getPersonalityReferenceKind() const;
951 virtual uint32_t getCompactUnwindEncoding(uint64_t ehAtomAddress);
a61fdf0a 952
d696c285
A
953protected:
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>;
962
2f2f92e4 963 AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
d696c285 964 virtual ~AnonymousAtom() {}
a61fdf0a 965 static bool cstringsHaveLabels();
d696c285
A
966
967 Reader<A>& fOwner;
968 const char* fSynthesizedName;
a61fdf0a 969 const char* fDisplayName;
d696c285 970 const macho_section<P>* fSection;
2f2f92e4
A
971 pint_t fAddress;
972 pint_t fSize;
d696c285
A
973 Segment<A>* fSegment;
974 ReferenceVector fReferences;
975 BaseAtom* fRedirect;
69a49097 976 bool fDontDeadStrip;
d696c285 977 bool fWeakImportStub;
69a49097
A
978 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
979 ObjectFile::Atom::Scope fScope;
2f2f92e4 980 ObjectFile::Atom::DefinitionKind fKind;
55e3d2f6 981 ObjectFile::Atom::ContentType fType;
4be885f6 982 unsigned int fSectionIndex;
d696c285
A
983};
984
985template <typename A>
2f2f92e4 986AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
a61fdf0a
A
987 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
988 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
55e3d2f6 989 fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition),
4be885f6 990 fType(ObjectFile::Atom::kUnclassifiedType), fSectionIndex(1 + (section - owner.fSectionsStart))
d696c285
A
991{
992 fSegment = new Segment<A>(fSection);
993 fRedirect = this;
994 uint8_t type = fSection->flags() & SECTION_TYPE;
2f2f92e4 995 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
d696c285
A
996 switch ( type ) {
997 case S_ZEROFILL:
998 {
999 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
1000 }
1001 break;
a61fdf0a 1002 case S_COALESCED:
d696c285 1003 case S_REGULAR:
55e3d2f6
A
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";
1013 }
1014 else {
1015 // is FDE
1016 fSynthesizedName = ".eh_PENDING";
1017 fDontDeadStrip = false;
1018 owner.fAtomsPendingAName.push_back(this);
1019 }
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;
1024 }
1025 else if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
69a49097 1026 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
a61fdf0a
A
1027 fSynthesizedName = ".objc_class_name_PENDING";
1028 owner.fAtomsPendingAName.push_back(this);
1029 owner.fSectionsWithAtomsPendingAName.insert(fSection);
69a49097
A
1030 if ( fOwner.fOptions.fForFinalLinkedImage )
1031 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
1032 else
1033 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
1034 fScope = ObjectFile::Atom::scopeGlobal;
1035 }
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);
1040 }
2f2f92e4
A
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;
1048 }
55e3d2f6
A
1049 else if ( (fSection->flags() & S_ATTR_SOME_INSTRUCTIONS) != 0 ) {
1050 fDontDeadStrip = false;
1051 asprintf((char**)&fSynthesizedName, "anon-func-0x%X", addr);
1052 }
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;
1060 }
c211e7c9
A
1061 else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1062 fSynthesizedName = "objc-class-pointer-name-PENDING";
1063 fScope = ObjectFile::Atom::scopeLinkageUnit;
1064 owner.fAtomsPendingAName.push_back(this);
1065 owner.fSectionsWithAtomsPendingAName.insert(fSection);
1066 fKind = ObjectFile::Atom::kWeakDefinition;
1067 }
fb24a050
A
1068 else if ( section == owner.fUTF16Section ) {
1069 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1070 fDontDeadStrip = false;
1071 fScope = ObjectFile::Atom::scopeLinkageUnit;
1072 fKind = ObjectFile::Atom::kWeakDefinition;
1073 char* name = new char[16+5*size];
1074 strcpy(name, "utf16-string=");
1075 char* s = &name[13];
1076 const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr());
1077 unsigned int wordCount = size/2;
fb24a050
A
1078 bool needSeperator = false;
1079 for(unsigned int i=0; i < wordCount; ++i) {
1080 if ( needSeperator )
1081 strcpy(s++, ".");
1082 sprintf(s, "%04X", E::get32(words[i]));
1083 s += 4;
1084 needSeperator = true;
1085 }
1086 fSynthesizedName = name;
1087 }
1088 else {
1089 asprintf((char**)&fSynthesizedName, "lutf16-0x%X", addr);
1090 }
1091 }
69a49097 1092 break;
d696c285
A
1093 case S_CSTRING_LITERALS:
1094 {
1095 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
fb24a050 1096 if ( (strcmp(fSection->sectname(), "__cstring") == 0) && (strcmp(section->segname(), "__TEXT") == 0) )
55e3d2f6
A
1097 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
1098 else
1099 asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str);
69a49097 1100 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 1101 fKind = ObjectFile::Atom::kWeakDefinition;
55e3d2f6 1102 fType = ObjectFile::Atom::kCStringType;
69a49097 1103 fDontDeadStrip = false;
a61fdf0a
A
1104 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
1105 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
d696c285
A
1106 }
1107 break;
1108 case S_4BYTE_LITERALS:
1109 {
1110 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1111 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
69a49097 1112 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 1113 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097 1114 fDontDeadStrip = false;
d696c285
A
1115 }
1116 break;
1117 case S_8BYTE_LITERALS:
1118 {
1119 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1120 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
69a49097 1121 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 1122 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097
A
1123 fDontDeadStrip = false;
1124 }
1125 break;
1126 case S_16BYTE_LITERALS:
1127 {
1128 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1129 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
1130 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
1131 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 1132 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097 1133 fDontDeadStrip = false;
d696c285
A
1134 }
1135 break;
1136 case S_LITERAL_POINTERS:
1137 {
a61fdf0a
A
1138 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
1139 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
1140 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
1141 fSynthesizedName = "literal-pointer-name-PENDING";
69a49097 1142 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4
A
1143 fKind = ObjectFile::Atom::kWeakDefinition;
1144 fDontDeadStrip = false;
a61fdf0a
A
1145 owner.fAtomsPendingAName.push_back(this);
1146 owner.fSectionsWithAtomsPendingAName.insert(fSection);
d696c285
A
1147 }
1148 break;
1149 case S_MOD_INIT_FUNC_POINTERS:
1150 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1151 break;
1152 case S_MOD_TERM_FUNC_POINTERS:
1153 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
1154 break;
1155 case S_SYMBOL_STUBS:
1156 {
1157 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
1158 index += fSection->reserved1();
1159 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1160 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
1161 uint32_t strOffset = sym->n_strx();
1162 // want name to not have $stub suffix, this is what automatic stub generation expects
1163 fSynthesizedName = &fOwner.fStrings[strOffset];
1164 // check for weak import
1165 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
1166 // sometimes the compiler gets confused and generates a stub to a static function
1167 // if so, we should redirect any call to the stub to be calls to the real static function atom
a61fdf0a 1168 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
d696c285 1169 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
a61fdf0a 1170 if ( staticAtom != NULL )
d696c285
A
1171 fRedirect = staticAtom;
1172 }
2f2f92e4 1173 fKind = ObjectFile::Atom::kWeakDefinition;
a61fdf0a
A
1174 // might be a spurious stub for a static function, make stub static too
1175 if ( (sym->n_type() & N_EXT) == 0 )
1176 fScope = ObjectFile::Atom::scopeTranslationUnit;
1177 else
1178 fScope = ObjectFile::Atom::scopeLinkageUnit;
d696c285
A
1179 }
1180 break;
1181 case S_LAZY_SYMBOL_POINTERS:
1182 case S_NON_LAZY_SYMBOL_POINTERS:
1183 {
fb24a050
A
1184 // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when
1185 // generating the new compressed LINKEDIT format
1186 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) && fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
1187 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1188 dummySection->set_segname("__DATA");
1189 dummySection->set_sectname("__nl_symbol_ptr");
1190 fSection = dummySection;
1191 fSegment = new Segment<A>(fSection);
1192 }
1193
69a49097
A
1194 fDontDeadStrip = false;
1195 fScope = ObjectFile::Atom::scopeLinkageUnit;
d696c285
A
1196 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
1197 index += fSection->reserved1();
1198 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1199 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1200 // Silly codegen with non-lazy pointer to a local symbol
d696c285
A
1201 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1202 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
69a49097 1203 // All atoms not created yet, so we need to scan symbol table
a61fdf0a 1204 const macho_nlist<P>* closestSym = NULL;
d696c285
A
1205 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1206 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
69a49097 1207 if ( ((sym->n_type() & N_TYPE) == N_SECT)
a61fdf0a
A
1208 && ((sym->n_type() & N_STAB) == 0) ) {
1209 if ( sym->n_value() == nonLazyPtrValue ) {
1210 const char* name = &fOwner.fStrings[sym->n_strx()];
1211 char* str = new char[strlen(name)+16];
1212 strcpy(str, name);
1213 strcat(str, "$non_lazy_ptr");
1214 fSynthesizedName = str;
1215 // add direct reference to target later, because its atom may not be constructed yet
1216 fOwner.fLocalNonLazys.push_back(this);
1217 fScope = ObjectFile::Atom::scopeTranslationUnit;
fb24a050 1218 fType = ObjectFile::Atom::kNonLazyPointer;
a61fdf0a
A
1219 return;
1220 }
1221 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1222 closestSym = sym;
1223 }
d696c285
A
1224 }
1225 }
a61fdf0a
A
1226 // add direct reference to target later, because its atom may not be constructed yet
1227 if ( closestSym != NULL ) {
1228 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1229 char* str;
1230 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1231 fSynthesizedName = str;
1232 }
1233 else {
1234 fSynthesizedName = "$interior$non_lazy_ptr";
1235 }
1236 fScope = ObjectFile::Atom::scopeTranslationUnit;
1237 fOwner.fLocalNonLazys.push_back(this);
fb24a050 1238 fType = ObjectFile::Atom::kNonLazyPointer;
a61fdf0a 1239 return;
d696c285
A
1240 }
1241 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1242 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1243 char* str = new char[strlen(name)+16];
1244 strcpy(str, name);
fb24a050 1245 if ( type == S_LAZY_SYMBOL_POINTERS ) {
d696c285 1246 strcat(str, "$lazy_ptr");
fb24a050
A
1247 fType = ObjectFile::Atom::kLazyPointer;
1248 }
1249 else {
d696c285 1250 strcat(str, "$non_lazy_ptr");
fb24a050
A
1251 fType = ObjectFile::Atom::kNonLazyPointer;
1252 }
d696c285
A
1253 fSynthesizedName = str;
1254
2f2f92e4
A
1255 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1256 fKind = ObjectFile::Atom::kWeakDefinition;
fb24a050 1257
69a49097
A
1258 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1259 // target is translation unit scoped, so add direct reference to target
1260 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1261 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1262 }
1263 else {
1264 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1265 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1266 else
1267 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1268 }
d696c285
A
1269 }
1270 break;
1271 default:
fb24a050 1272 throwf("section type %d not supported with address=0x%08llX", type, (uint64_t)addr);
d696c285
A
1273 }
1274 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1275}
1276
a61fdf0a
A
1277// x86_64 uses L labels on cstrings to allow relocs with addends
1278template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1279template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1280
fb24a050
A
1281template <typename A>
1282void AnonymousAtom<A>::addLineInfo(const ObjectFile::LineInfo& info)
1283{
1284 // <rdar://problem/6545406> don't warn if line table has entries for stubs
1285 if ( (fSection->flags() & SECTION_TYPE) != S_SYMBOL_STUBS )
1286 warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath());
1287}
a61fdf0a
A
1288
1289template <typename A>
1290void AnonymousAtom<A>::resolveName()
1291{
1292 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1293 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1294 // references are not yet sorted, so scan the vector
1295 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1296 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1297 const char* superStr = (*rit)->getTargetName();
55e3d2f6 1298 if ( strncmp(superStr, "cstring", 7) == 0 ) {
a61fdf0a
A
1299 const char* superClassName;
1300 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1301 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1302 }
1303 break;
1304 }
1305 }
1306 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1307 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1308 const char* classStr = (*rit)->getTargetName();
55e3d2f6 1309 if ( strncmp(classStr, "cstring", 7) == 0 ) {
a61fdf0a
A
1310 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1311 }
1312 break;
1313 }
1314 }
1315 }
1316 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
2f2f92e4
A
1317 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1318 if ( references.size() < 1 )
1319 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1320 ObjectFile::Reference* ref = references[0];
a61fdf0a 1321 const char* str = ref->getTargetName();
55e3d2f6 1322 if ( strncmp(str, "cstring", 7) == 0 ) {
a61fdf0a
A
1323 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1324 }
1325 }
2f2f92e4
A
1326 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1327 // references are not yet sorted, so scan the vector
1328 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1329 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1330 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1331 const char* superStr = (*rit)->getTargetName();
1332 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1333 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1334 }
fb24a050
A
1335 else if ( (superStr != NULL) && (strncmp(superStr, "utf16-string=", 13) == 0) ) {
1336 asprintf((char**)&fSynthesizedName, "cfstring-utf16=%s", &superStr[13]);
1337 }
2f2f92e4
A
1338 else {
1339 // compiled with -fwritable-strings or a non-ASCII string
2f2f92e4
A
1340 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1341 fScope = ObjectFile::Atom::scopeTranslationUnit;
1342 fSynthesizedName = "cfstring-not-coalesable";
55e3d2f6
A
1343 if ( (*rit)->getTargetOffset() != 0 )
1344 warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner.getPath());
2f2f92e4
A
1345 }
1346 break;
1347 }
1348 }
1349 }
55e3d2f6
A
1350 else if ( fSection == fOwner.fehFrameSection ) {
1351 // give name to FDE
1352 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromFDEAddress(fAddress);
1353 if ( funcAtom != NULL )
1354 asprintf((char**)&fSynthesizedName, "%s.eh", funcAtom->getDisplayName());
1355 }
1356 else if ( fOwner.fLSDAAtoms.count(this) != 0) {
1357 // give name to LSDA
1358 ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromLSDAAddress(fAddress);
1359 if ( funcAtom != NULL )
1360 asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
1361 }
c211e7c9
A
1362 else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1363 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1364 if ( references.size() != 1 )
1365 throwf("__objc_classrefs element missing reloc (count=%ld) for target class in %s", references.size(), fOwner.getPath());
1366 const char* targetName = references[0]->getTargetName();
1367 if ( strncmp(targetName, "_OBJC_CLASS_$_", 14) == 0 )
1368 asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", &targetName[14]);
1369 else
1370 asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", targetName);
1371 }
a61fdf0a
A
1372}
1373
d696c285
A
1374
1375template <typename A>
1376const char* AnonymousAtom<A>::getDisplayName() const
1377{
1378 if ( fSynthesizedName != NULL )
1379 return fSynthesizedName;
1380
a61fdf0a
A
1381 if ( fDisplayName != NULL )
1382 return fDisplayName;
1383
d696c285
A
1384 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1385 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
a61fdf0a 1386 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
d696c285
A
1387 }
1388 else {
a61fdf0a 1389 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
d696c285 1390 }
a61fdf0a 1391 return fDisplayName;
d696c285
A
1392}
1393
a61fdf0a 1394
d696c285
A
1395template <typename A>
1396ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1397{
74cfe461 1398 return fScope;
d696c285
A
1399}
1400
d696c285
A
1401
1402template <typename A>
1403bool AnonymousAtom<A>::isZeroFill() const
1404{
4be885f6 1405 return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
d696c285
A
1406}
1407
1408
1409template <typename A>
1410const char* AnonymousAtom<A>::getSectionName() const
1411{
55e3d2f6
A
1412 if ( fOwner.fOptions.fForFinalLinkedImage ) {
1413 switch ( fSection->flags() & SECTION_TYPE ) {
1414 case S_4BYTE_LITERALS:
1415 case S_8BYTE_LITERALS:
1416 case S_16BYTE_LITERALS:
1417 return "__const";
1418 }
1419 }
1420
d696c285
A
1421 if ( strlen(fSection->sectname()) > 15 ) {
1422 static char temp[18];
1423 strncpy(temp, fSection->sectname(), 16);
1424 temp[17] = '\0';
1425 return temp;
1426 }
1427 return fSection->sectname();
1428}
1429
1430template <typename A>
74cfe461 1431ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
d696c285 1432{
55e3d2f6
A
1433 // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
1434 if ( fType == ObjectFile::Atom::kCFIType )
1435 return ObjectFile::Alignment(0);
1436
d696c285
A
1437 switch ( fSection->flags() & SECTION_TYPE ) {
1438 case S_4BYTE_LITERALS:
74cfe461 1439 return ObjectFile::Alignment(2);
d696c285 1440 case S_8BYTE_LITERALS:
74cfe461 1441 return ObjectFile::Alignment(3);
69a49097 1442 case S_16BYTE_LITERALS:
74cfe461 1443 return ObjectFile::Alignment(4);
d696c285 1444 case S_NON_LAZY_SYMBOL_POINTERS:
74cfe461 1445 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
a61fdf0a
A
1446 case S_CSTRING_LITERALS:
1447 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1448 return ObjectFile::Alignment(fSection->align());
d696c285 1449 default:
74cfe461 1450 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
d696c285
A
1451 }
1452}
1453
d696c285
A
1454
1455template <typename A>
1456ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1457{
1458 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1459 Reference<A>* ref = *it;
1460 if ( ref->getKind() == A::kFollowOn )
1461 return ref->getTarget();
1462 }
1463 return *((ObjectFile::Atom*)NULL);
1464}
1465
1466template <typename A>
1467void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1468{
1469 // copy base bytes
1470 if ( isZeroFill() )
1471 bzero(buffer, fSize);
1472 else {
1473 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1474 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1475 }
1476}
1477
a61fdf0a
A
1478//
1479// An AbsoluteAtom represents an N_ABS symbol which can only be created in
1480// assembly language and usable by static executables such as the kernel/
1481//
1482template <typename A>
1483class AbsoluteAtom : public BaseAtom
1484{
1485public:
1486 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1487 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1488 { return fOwner.getTranslationUnitSource(dir, name); }
1489 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1490 virtual const char* getDisplayName() const { return getName(); }
1491 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1492 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1493 virtual bool isZeroFill() const { return false; }
2f2f92e4 1494 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
a61fdf0a
A
1495 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1496 virtual bool dontDeadStrip() const { return false; }
1497 virtual uint64_t getSize() const { return 0; }
1498 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1499 virtual bool mustRemainInSection() const { return true; }
1500 virtual const char* getSectionName() const { return "._absolute"; }
1501 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1502 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1503 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1504 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1505 virtual void copyRawContent(uint8_t buffer[]) const { }
1506 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1507 virtual void setSize(uint64_t size) { }
1508 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1509 virtual void sortReferences() { }
1510 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
55e3d2f6 1511 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
a61fdf0a
A
1512 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1513 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1514 virtual const void* getSectionRecord() const { return NULL; }
4be885f6 1515 virtual unsigned int getSectionIndex() const { return 0; }
a61fdf0a
A
1516
1517protected:
1518 typedef typename A::P P;
1519 typedef typename A::P::E E;
1520 typedef typename A::P::uint_t pint_t;
1521 typedef typename A::ReferenceKinds Kinds;
1522 friend class Reader<A>;
1523
1524 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1525 virtual ~AbsoluteAtom() {}
1526
1527 Reader<A>& fOwner;
1528 const macho_nlist<P>* fSymbol;
1529 ObjectFile::Atom::Scope fScope;
1530 static std::vector<ObjectFile::Reference*> fgNoReferences;
1531};
1532
1533template <typename A>
1534std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1535
1536template <typename A>
1537AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1538 : fOwner(owner), fSymbol(symbol)
1539{
1540 // store absolute adress in fSectionOffset
1541 fSectionOffset = symbol->n_value();
1542 // compute scope
1543 uint8_t type = symbol->n_type();
1544 if ( (type & N_EXT) == 0 )
1545 fScope = ObjectFile::Atom::scopeTranslationUnit;
1546 else if ( (type & N_PEXT) != 0 )
1547 fScope = ObjectFile::Atom::scopeLinkageUnit;
1548 else
1549 fScope = ObjectFile::Atom::scopeGlobal;
1550 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1551}
1552
d696c285 1553
4be885f6
A
1554//
1555// An SectionBoundaryAtom represent the start or end of a section
1556//
1557template <typename A>
1558class SectionBoundaryAtom : public BaseAtom
1559{
1560public:
1561 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1562 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1563 { return fOwner.getTranslationUnitSource(dir, name); }
1564 virtual const char* getName() const { return fSymbolName; }
1565 virtual const char* getDisplayName() const { return fDisplayName; }
1566 virtual ObjectFile::Atom::Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; }
1567 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kWeakDefinition; }
1568 virtual ObjectFile::Atom::ContentType getContentType() const { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
c211e7c9 1569 virtual bool isZeroFill() const { return fZeroFill; }
4be885f6
A
1570 virtual bool isThumb() const { return false; }
1571 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
1572 virtual bool dontDeadStrip() const { return false; }
1573 virtual uint64_t getSize() const { return 0; }
1574 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1575 virtual bool mustRemainInSection() const { return true; }
1576 virtual const char* getSectionName() const { return fSectionName; }
1577 virtual ObjectFile::Segment& getSegment() const { return *fSegment; }
1578 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1579 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1580 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1581 virtual void copyRawContent(uint8_t buffer[]) const { }
1582 virtual void setScope(ObjectFile::Atom::Scope newScope) { }
1583 virtual void setSize(uint64_t size) { }
1584 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1585 virtual void sortReferences() { }
1586 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1587 virtual const ObjectFile::ReaderOptions& getOptions() const { return fOwner.fOptions; }
1588 virtual uint64_t getObjectAddress() const { return 0; }
1589 virtual const void* getSectionRecord() const { return NULL; }
1590 virtual unsigned int getSectionIndex() const { return 0; }
1591
1592protected:
1593 typedef typename A::P P;
1594 typedef typename A::P::E E;
1595 typedef typename A::P::uint_t pint_t;
1596 typedef typename A::ReferenceKinds Kinds;
1597 friend class Reader<A>;
1598
1599
1600 class Segment : public ObjectFile::Segment
1601 {
1602 public:
1603 Segment(const char* name, bool r, bool w, bool x):
1604 fName(name), fReadable(r), fWritable(w), fExecutable(x) {}
1605
1606 virtual const char* getName() const { return fName; }
1607 virtual bool isContentReadable() const { return fReadable; }
1608 virtual bool isContentWritable() const { return fWritable; }
1609 virtual bool isContentExecutable() const { return fExecutable; }
1610 private:
1611 const char* fName;
1612 bool fReadable;
1613 bool fWritable;
1614 bool fExecutable;
1615 };
1616
1617 SectionBoundaryAtom(Reader<A>&, bool start, const char* symbolName, const char* segSectName);
1618 virtual ~SectionBoundaryAtom() {}
1619
1620 Reader<A>& fOwner;
1621 class Segment* fSegment;
1622 const char* fSymbolName;
1623 const char* fSectionName;
1624 const char* fDisplayName;
1625 bool fStart;
c211e7c9 1626 bool fZeroFill;
4be885f6
A
1627 static std::vector<ObjectFile::Reference*> fgNoReferences;
1628};
1629
1630template <typename A>
1631std::vector<ObjectFile::Reference*> SectionBoundaryAtom<A>::fgNoReferences;
1632
1633// examples:
1634// section$start$__DATA$__my
1635// section$end$__DATA$__my
1636template <typename A>
1637SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
c211e7c9 1638 : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start), fZeroFill(false)
4be885f6
A
1639{
1640 const char* segSectDividor = strrchr(segSectName, '$');
1641 if ( segSectDividor == NULL )
1642 throwf("malformed section reference name: %s", symbolName);
1643 fSectionName = segSectDividor + 1;
1644 int segNameLen = segSectDividor - segSectName;
1645 if ( segNameLen > 16 )
1646 throwf("malformed section reference name: %s", symbolName);
1647 char segName[18];
1648 strlcpy(segName, segSectName, segNameLen+1);
1649 if ( strcmp(segName, "__TEXT") == 0 )
1650 fSegment = new Segment("__TEXT", true, false, true);
c211e7c9 1651 else if ( strcmp(segName, "__DATA") == 0 ) {
4be885f6 1652 fSegment = new Segment("__DATA", true, true, false);
c211e7c9
A
1653 if ( (strcmp(fSectionName, "__bss") == 0) || (strcmp(fSectionName, "__common") == 0) )
1654 fZeroFill = true;
1655 }
4be885f6
A
1656 else
1657 fSegment = new Segment(strdup(segName), true, true, false);
1658
1659 asprintf((char**)&fDisplayName, "%s of section '%s' in segment '%s'", (start ? "start" : "end"), fSectionName, segName);
1660}
1661
d696c285 1662
55e3d2f6
A
1663
1664///
1665/// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
1666/// dwarf CFI information in an object file.
1667///
1668template <typename A>
1669class ObjectFileAddressSpace
1670{
1671public:
1672 ObjectFileAddressSpace(Reader<A>& reader);
1673
1674 typedef typename A::P::uint_t pint_t;
1675 typedef typename A::P P;
1676 typedef typename A::P::uint_t sint_t;
1677
1678 uint8_t get8(pint_t addr);
1679 uint16_t get16(pint_t addr);
1680 uint32_t get32(pint_t addr);
1681 uint64_t get64(pint_t addr);
1682 pint_t getP(pint_t addr);
1683 uint64_t getULEB128(pint_t& addr, pint_t end);
1684 int64_t getSLEB128(pint_t& addr, pint_t end);
1685 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
1686private:
1687 const void* mappedAddress(pint_t addr, pint_t* relocTarget=NULL);
1688 pint_t relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount);
fb24a050 1689 void buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map);
55e3d2f6
A
1690
1691 Reader<A>& fReader;
1692 const uint8_t* fMappingStart;
1693 const macho_section<P>* fSectionsStart;
1694 const macho_section<P>* fSectionsEnd;
fb24a050 1695 std::map<uint32_t,uint64_t> fEHFrameOffsetToTargetMap;
55e3d2f6
A
1696};
1697
1698
1699template <typename A>
1700ObjectFileAddressSpace<A>::ObjectFileAddressSpace(Reader<A>& reader)
1701 : fReader(reader), fMappingStart(NULL), fSectionsStart(NULL), fSectionsEnd(NULL)
1702{
1703}
1704
1705
1706
1707template <typename A>
1708const void* ObjectFileAddressSpace<A>::mappedAddress(pint_t addr, pint_t* relocTarget)
1709{
1710 if ( fMappingStart == NULL ) {
1711 // delay initialization until now when fReader.fSegment is set up
1712 fMappingStart = (uint8_t*)fReader.fHeader;
1713 fSectionsStart = (macho_section<P>*)((char*)fReader.fSegment + sizeof(macho_segment_command<P>));
1714 fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()];
fb24a050
A
1715 // find __eh_frame section and build map of relocations for performance
1716 buildRelocatedMap(fReader.fehFrameSection, fEHFrameOffsetToTargetMap);
55e3d2f6 1717 }
fb24a050
A
1718 // special case lookups in __eh_frame section to be fast
1719 const macho_section<P>* ehSect = fReader.fehFrameSection;
1720 if ( (ehSect->addr() <= addr) && (addr < (ehSect->addr()+ehSect->size())) ) {
1721 pint_t offsetOfAddrInSection = addr - ehSect->addr();
1722 if ( relocTarget != NULL ) {
1723 std::map<uint32_t,uint64_t>::iterator pos = fEHFrameOffsetToTargetMap.find(offsetOfAddrInSection);
1724 if ( pos != fEHFrameOffsetToTargetMap.end() )
1725 *relocTarget = pos->second;
1726 else
1727 *relocTarget = 0;
1728 }
1729 return fMappingStart + ehSect->offset() + offsetOfAddrInSection;
1730 }
1731 else {
1732 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
1733 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
1734 pint_t offsetOfAddrInSection = addr - sect->addr();
1735 if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
1736 const uint32_t indirectTableOffset = sect->reserved1();
1737 const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t);
1738 const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]);
1739 // return pointer to symbol name which this non-lazy-pointer will point to
1740 if ( relocTarget != NULL )
1741 *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()];
1742 }
1743 else {
1744 if ( relocTarget != NULL )
1745 *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc());
1746 }
1747 return fMappingStart + sect->offset() + offsetOfAddrInSection;
4be885f6 1748 }
55e3d2f6 1749 }
fb24a050 1750 throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr);
55e3d2f6
A
1751 }
1752}
1753
1754
1755
1756
1757template <typename A>
1758uint8_t ObjectFileAddressSpace<A>::get8(pint_t logicalAddr)
1759{
1760 return *((uint8_t*)mappedAddress(logicalAddr));
1761}
1762
1763template <typename A>
1764uint16_t ObjectFileAddressSpace<A>::get16(pint_t logicalAddr)
1765{
1766 return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr)));
1767}
1768
1769template <typename A>
1770uint32_t ObjectFileAddressSpace<A>::get32(pint_t logicalAddr)
1771{
1772 pint_t relocTarget;
1773 return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1774}
1775
1776template <typename A>
1777uint64_t ObjectFileAddressSpace<A>::get64(pint_t logicalAddr)
1778{
1779 pint_t relocTarget;
1780 return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1781}
1782
1783template <typename A>
1784typename A::P::uint_t ObjectFileAddressSpace<A>::getP(pint_t logicalAddr)
1785{
1786 pint_t relocTarget;
1787 return P::getP(*((pint_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
1788}
1789
1790template <typename A>
1791uint64_t ObjectFileAddressSpace<A>::getULEB128(pint_t& logicalAddr, pint_t end)
1792{
1793 uintptr_t size = (end - logicalAddr);
1794 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1795 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1796 uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
1797 logicalAddr += (laddr-sladdr);
1798 return result;
1799}
1800
1801template <typename A>
1802int64_t ObjectFileAddressSpace<A>::getSLEB128(pint_t& logicalAddr, pint_t end)
1803{
1804 uintptr_t size = (end - logicalAddr);
1805 libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
1806 libunwind::LocalAddressSpace::pint_t sladdr = laddr;
1807 int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
1808 logicalAddr += (laddr-sladdr);
1809 return result;
1810}
1811
1812
1813
1814
1815
1816
d696c285
A
1817template <typename A>
1818class Reader : public ObjectFile::Reader
1819{
1820public:
55e3d2f6 1821 static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
c211e7c9 1822 static const char* fileKind(const uint8_t* fileContent);
a61fdf0a
A
1823 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1824 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
d696c285
A
1825 virtual ~Reader() {}
1826
1827 virtual const char* getPath() { return fPath; }
1828 virtual time_t getModificationTime() { return fModTime; }
1829 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1830 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1831 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1832 virtual std::vector<Stab>* getStabs() { return &fStabs; }
a61fdf0a 1833 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
2f2f92e4 1834 virtual uint32_t updateCpuConstraint(uint32_t current);
a61fdf0a
A
1835 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1836 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
2f2f92e4 1837 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
d696c285
A
1838
1839 bool getTranslationUnitSource(const char** dir, const char** name) const;
1840
1841private:
1842 typedef typename A::P P;
1843 typedef typename A::P::E E;
1844 typedef typename A::P::uint_t pint_t;
1845 //typedef typename std::vector<Atom<A>*> AtomVector;
1846 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1847 typedef typename A::ReferenceKinds Kinds;
55e3d2f6
A
1848 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::FDE_Atom_Info FDE_Atom_Info;
1849 typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::CIE_Atom_Info CIE_Atom_Info;
1850 typedef class ObjectFileAddressSpace<A> OAS;
1851 friend class ObjectFileAddressSpace<A>;
d696c285
A
1852 friend class AnonymousAtom<A>;
1853 friend class TentativeAtom<A>;
a61fdf0a 1854 friend class AbsoluteAtom<A>;
4be885f6 1855 friend class SectionBoundaryAtom<A>;
d696c285 1856 friend class SymbolAtom<A>;
2f2f92e4 1857 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
a61fdf0a
A
1858
1859 void addReferencesForSection(const macho_section<P>* sect);
d696c285
A
1860 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1861 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
55e3d2f6 1862 const char* getDwarfString(uint64_t form, const uint8_t* p);
d696c285
A
1863 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1864 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1865 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1866 static const char* assureFullPath(const char* path);
2f2f92e4 1867 AtomAndOffset findAtomAndOffset(pint_t addr);
4be885f6 1868 AtomAndOffset findAtomAndOffsetForSection(pint_t addr, unsigned int sectionIndex);
2f2f92e4
A
1869 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1870 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1871 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1872 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1873 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1874 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
55e3d2f6 1875 BaseAtom* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
2f2f92e4 1876 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
d696c285 1877 void validSectionType(uint8_t type);
a61fdf0a
A
1878 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1879 void setCpuConstraint(uint32_t cpusubtype);
55e3d2f6
A
1880 const macho_section<P>* getSectionForAddress(pint_t);
1881 ObjectFile::Atom* getFunctionAtomFromFDEAddress(pint_t);
1882 ObjectFile::Atom* getFunctionAtomFromLSDAAddress(pint_t);
1883 void addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target);
1884 void addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding);
1885 bool isSectDiffReloc(uint8_t r_type);
1886
d696c285
A
1887
1888 BaseAtom* findAtomByName(const char*);
1889
1890 const char* fPath;
1891 time_t fModTime;
a61fdf0a 1892 uint32_t fOrdinalBase;
d696c285
A
1893 const ObjectFile::ReaderOptions& fOptions;
1894 const macho_header<P>* fHeader;
1895 const char* fStrings;
1896 const macho_nlist<P>* fSymbols;
1897 uint32_t fSymbolCount;
1898 const macho_segment_command<P>* fSegment;
1899 const uint32_t* fIndirectTable;
a61fdf0a 1900 std::vector<BaseAtom*> fAtoms;
2f2f92e4
A
1901 AddrToAtomMap fAddrToAtom;
1902 AddrToAtomMap fAddrToAbsoluteAtom;
d696c285 1903 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
a61fdf0a
A
1904 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1905 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1906 std::vector<const char*> fDtraceProviderInfo;
d696c285 1907 ObjectFile::Reader::DebugInfoKind fDebugInfo;
69a49097 1908 bool fHasUUID;
55e3d2f6 1909 const macho_section<P>* fehFrameSection;
fb24a050 1910 const macho_section<P>* fUTF16Section;
55e3d2f6 1911 std::set<BaseAtom*> fLSDAAtoms;
d696c285
A
1912 const macho_section<P>* fDwarfDebugInfoSect;
1913 const macho_section<P>* fDwarfDebugAbbrevSect;
1914 const macho_section<P>* fDwarfDebugLineSect;
55e3d2f6 1915 const macho_section<P>* fDwarfDebugStringSect;
d696c285
A
1916 const char* fDwarfTranslationUnitDir;
1917 const char* fDwarfTranslationUnitFile;
1918 std::map<uint32_t,const char*> fDwarfIndexToFile;
1919 std::vector<Stab> fStabs;
55e3d2f6
A
1920 std::vector<FDE_Atom_Info> fFDEInfos;
1921 std::vector<CIE_Atom_Info> fCIEInfos;
69a49097 1922 bool fAppleObjc;
a61fdf0a
A
1923 bool fHasDTraceProbes;
1924 bool fHaveIndirectSymbols;
1925 bool fReplacementClasses;
2f2f92e4 1926 bool fHasLongBranchStubs;
a61fdf0a 1927 ObjectFile::Reader::ObjcConstraint fObjConstraint;
2f2f92e4 1928 uint32_t fCpuConstraint;
55e3d2f6
A
1929 const macho_section<P>* fSectionsStart;
1930 const macho_section<P>* fSectionsEnd;
1931 OAS fObjectAddressSpace;
d696c285
A
1932};
1933
d696c285 1934template <typename A>
a61fdf0a
A
1935Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1936 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
d696c285 1937 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
fb24a050 1938 fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), fUTF16Section(NULL),
55e3d2f6 1939 fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
a61fdf0a 1940 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
2f2f92e4 1941 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
55e3d2f6
A
1942 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny),
1943 fSectionsStart(NULL), fSectionsEnd(NULL), fObjectAddressSpace(*this)
d696c285
A
1944{
1945 // sanity check
55e3d2f6 1946 if ( ! validFile(fileContent, false, 0) )
d696c285
A
1947 throw "not a valid mach-o object file";
1948
a61fdf0a
A
1949 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1950
1951 // write out path for -t or -whatsloaded option
1952 if ( options.fLogObjectFiles || options.fLogAllFiles )
1953 printf("%s\n", path);
1954
d696c285
A
1955 // cache intersting pointers
1956 const macho_header<P>* header = (const macho_header<P>*)fileContent;
a61fdf0a 1957 this->setCpuConstraint(header->cpusubtype());
d696c285
A
1958 const uint32_t cmd_count = header->ncmds();
1959 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
2f2f92e4 1960 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
d696c285 1961 const macho_load_command<P>* cmd = cmds;
69a49097
A
1962 uint32_t undefinedStartIndex = 0;
1963 uint32_t undefinedEndIndex = 0;
d696c285
A
1964 for (uint32_t i = 0; i < cmd_count; ++i) {
1965 switch (cmd->cmd()) {
1966 case LC_SYMTAB:
1967 {
1968 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1969 fSymbolCount = symtab->nsyms();
1970 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1971 fStrings = (char*)header + symtab->stroff();
a61fdf0a
A
1972 if ( undefinedEndIndex == 0 ) {
1973 undefinedStartIndex = 0;
1974 undefinedEndIndex = symtab->nsyms();
1975 }
d696c285
A
1976 }
1977 break;
1978 case LC_DYSYMTAB:
1979 {
1980 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1981 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
69a49097
A
1982 undefinedStartIndex = dsymtab->iundefsym();
1983 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
d696c285
A
1984 }
1985 break;
1986 case LC_UUID:
69a49097 1987 fHasUUID = true;
d696c285
A
1988 break;
1989
1990 default:
1991 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1992 fSegment = (macho_segment_command<P>*)cmd;
1993 }
1994 break;
1995 }
1996 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
2f2f92e4
A
1997 if ( cmd > cmdsEnd )
1998 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
d696c285 1999 }
2f2f92e4
A
2000
2001 // if there are no load commands, then this file has no content, so no atoms
2002 if ( header->ncmds() < 1 )
2003 return;
2004
55e3d2f6
A
2005 fSectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
2006 fSectionsEnd = &fSectionsStart[fSegment->nsects()];
d696c285
A
2007
2008 // inital guess for number of atoms
2009 fAtoms.reserve(fSymbolCount);
2010
55e3d2f6
A
2011 // if there is an __eh_frame section, decode it into chunks to get atoms in that
2012 // section as well as division points for functions in __text
2013 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2014 if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
2015 fehFrameSection = sect;
fb24a050
A
2016 const char* msg = libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::getCFIs(fObjectAddressSpace, sect->addr(),
2017 sect->size(), fFDEInfos, fCIEInfos);
2018 if ( msg != NULL ) {
2019 throwf("malformed __eh_frame section: %s", msg);
2020 }
2021 else {
55e3d2f6
A
2022 //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size());
2023 // add anonymous atoms for each CIE
2024 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2025 AnonymousAtom<A>* cieAtom = new AnonymousAtom<A>(*this, sect, it->cieAddress, 1);
2026 fAtoms.push_back(cieAtom);
2027 fAddrToAtom[it->cieAddress] = cieAtom;
2028 }
2029 // add anonymous atoms for each FDE and LSDA
2030 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2031 //fprintf(stderr, "fdeAddress=0x%08llX, lsdaAddr=0x%08llX, funcAddr=0x%08llX\n", (uint64_t)it->fdeAddress, (uint64_t)it->lsda.address, (uint64_t)it->function.address);
2032 AnonymousAtom<A>* fdeAtom = new AnonymousAtom<A>(*this, sect, it->fdeAddress, 0);
2033 fAtoms.push_back(fdeAtom);
2034 fAddrToAtom[it->fdeAddress] = fdeAtom;
2035 if ( it->lsda.address != 0 ) {
2036 AnonymousAtom<A>* lsdaAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->lsda.address), it->lsda.address, 0);
2037 fAtoms.push_back(lsdaAtom);
2038 fAddrToAtom[it->lsda.address] = lsdaAtom;
2039 fLSDAAtoms.insert(lsdaAtom);
2040 }
2041 }
2042 }
fb24a050 2043 }
d9246299
A
2044 else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) && (sect->size() != 0) ) {
2045 // if there is a __ustring section parse it into atoms
fb24a050 2046 fUTF16Section = sect;
d9246299
A
2047 // first find all cleave points
2048 const uint16_t* words = (uint16_t*)((char*)(fHeader) + fUTF16Section->offset());
2049 unsigned int wordCount = fUTF16Section->size()/2;
fb24a050 2050 std::vector<pint_t> utf16Addreses;
d9246299
A
2051 bool inString = false;
2052 for (unsigned int i=0; i < wordCount; ++i) {
2053 if ( inString ) {
2054 if ( words[i] == 0x0000 ) {
2055 inString = false;
2056 }
2057 }
2058 else {
2059 if ( words[i] == 0x0000 ) {
2060 // skip over zero padding
2061 }
2062 else {
2063 inString = true;
2064 utf16Addreses.push_back(fUTF16Section->addr() + i*2);
2065 }
2066 }
2067 }
2068 utf16Addreses.push_back(fUTF16Section->addr() + sect->size());
2069 // build map of symbols
2070 std::map<pint_t, const macho_nlist<P>* > symbolMap;
fb24a050
A
2071 for (int i=fSymbolCount-1; i >= 0 ; --i) {
2072 const macho_nlist<P>& sym = fSymbols[i];
2073 if ( (sym.n_type() & N_STAB) == 0 ) {
2074 uint8_t type = (sym.n_type() & N_TYPE);
2075 if ( type == N_SECT ) {
2076 if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) {
d9246299
A
2077 // rdar://problem/7429384 don't coalesce UTF16 strings unless label starts with ___utf16_string
2078 if ( strncmp(&fStrings[sym.n_strx()], "___utf16_string", 15) != 0 ) {
2079 symbolMap[sym.n_value()] = &sym;
2080 // <rdar://problem/7516793> if this symbol is a string of just 0x0000, it may not be in utf16Addreses
2081 if ( words[(sym.n_value() - sect->addr())/2] == 0x0000 ) {
2082 for(typename std::vector<pint_t>::iterator sit=utf16Addreses.begin(); sit != utf16Addreses.end(); ++sit) {
2083 if ( *sit == sym.n_value() ) {
2084 // already in utf16Addreses
2085 break;
2086 }
2087 if ( *sit > sym.n_value() ) {
2088 // need to insert
2089 utf16Addreses.insert(sit, sym.n_value());
2090 break;
2091 }
2092 }
2093 }
2094 }
fb24a050
A
2095 }
2096 }
2097 }
2098 }
d9246299 2099 // make atom for each string
fb24a050
A
2100 for(int i=utf16Addreses.size()-2; i >=0 ; --i) {
2101 pint_t size = utf16Addreses[i+1] - utf16Addreses[i];
d9246299
A
2102 typename std::map<pint_t, const macho_nlist<P>* >::iterator pos = symbolMap.find(utf16Addreses[i]);
2103 if ( pos == symbolMap.end() ) {
2104 AnonymousAtom<A>* strAtom = new AnonymousAtom<A>(*this, fUTF16Section, utf16Addreses[i], size);
2105 fAtoms.push_back(strAtom);
2106 fAddrToAtom[utf16Addreses[i]] = strAtom;
2107 }
2108 else {
2109 SymbolAtom<A>* newAtom = new SymbolAtom<A>(*this, pos->second, fUTF16Section);
2110 fAtoms.push_back(newAtom);
2111 fAddrToAtom[utf16Addreses[i]] = newAtom;
2112 newAtom->setSize(size);
2113 }
4be885f6 2114 }
55e3d2f6
A
2115 }
2116 }
2117
2118
d696c285 2119 // add all atoms that have entries in symbol table
55e3d2f6
A
2120 BaseAtom* sectionEndAtoms[fSegment->nsects()];
2121 for (unsigned int i=0; i < fSegment->nsects(); ++i)
2122 sectionEndAtoms[i] = NULL;
a61fdf0a 2123 for (int i=fSymbolCount-1; i >= 0 ; --i) {
55e3d2f6 2124 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name
d696c285
A
2125 const macho_nlist<P>& sym = fSymbols[i];
2126 if ( (sym.n_type() & N_STAB) == 0 ) {
2127 uint8_t type = (sym.n_type() & N_TYPE);
2128 if ( type == N_SECT ) {
55e3d2f6
A
2129 const macho_section<P>* section = &fSectionsStart[sym.n_sect()-1];
2130 const pint_t sectionStartAddr = section->addr();
2131 const pint_t sectionEndAddr = sectionStartAddr + section->size();
d696c285 2132 bool suppress = false;
55e3d2f6 2133 // ignore atoms in debugger sections
d696c285 2134 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
a61fdf0a
A
2135 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
2136 // ignore dtrace probe labels
2137 fHasDTraceProbes = true;
2138 }
2139 else if ( fStrings[sym.n_strx()] == 'L' ) {
2140 // ignore L labels, <rdar://problem/3962731>
2141 }
55e3d2f6
A
2142 else if ( section == fehFrameSection ) {
2143 // ignore labels in __eh_frame section
2144 }
fb24a050
A
2145 else if ( section == fUTF16Section ) {
2146 // ignore labels in __ustring section
2147 }
a61fdf0a
A
2148 else {
2149 // ignore labels for atoms in other sections
2150 switch ( section->flags() & SECTION_TYPE ) {
2151 case S_REGULAR:
2152 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
2153 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
2154 case S_ZEROFILL:
2155 case S_COALESCED:
2156 case S_4BYTE_LITERALS:
2157 case S_8BYTE_LITERALS:
2158 case S_16BYTE_LITERALS:
2159 case S_CSTRING_LITERALS:
2160 {
2161 BaseAtom* newAtom;
2f2f92e4 2162 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
55e3d2f6
A
2163 if ( (pos != fAddrToAtom.end()) && (pos->second->getSectionRecord() == section) ) {
2164 if ( fLSDAAtoms.count(pos->second) != 0 ) {
2165 // already have LSDA atom from for this address, ignore compiler's label
2166 suppress = true;
2167 break;
2168 }
2169 else {
2170 // another label to an existing address in the same section, make this an alias
2171 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
2172 }
a61fdf0a
A
2173 }
2174 else {
55e3d2f6
A
2175 if ( sym.n_value() == sectionEndAddr ) {
2176 // Symbol address is at end of section. This can interfere
2177 // with a symbol at the start of the next section, so don't
2178 // add to fAddrToAtom. But do track in sectionEndAtoms so we
2179 // still make aliases if there are duplicates.
2180 if ( sectionEndAtoms[sym.n_sect()-1] == NULL ) {
2181 newAtom = new SymbolAtom<A>(*this, &sym, section);
2182 sectionEndAtoms[sym.n_sect()-1] = newAtom;
2183 // if this is a zero length section, so add to fAddrToAtom
2184 if ( sym.n_value() == sectionStartAddr )
2185 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
2186 }
2187 else {
2188 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *sectionEndAtoms[sym.n_sect()-1]);
2189 }
2190 }
2191 else {
2192 // make SymbolAtom atom for this address
2193 newAtom = new SymbolAtom<A>(*this, &sym, section);
2f2f92e4 2194 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
55e3d2f6 2195 }
a61fdf0a
A
2196 }
2197 if ( ! suppress )
2198 fAtoms.push_back(newAtom);
2199 }
2200 break;
2201 case S_SYMBOL_STUBS:
2202 case S_LAZY_SYMBOL_POINTERS:
2203 case S_NON_LAZY_SYMBOL_POINTERS:
2204 // ignore symboled stubs produces by old ld64
2205 break;
2206 default:
2f2f92e4 2207 warning("symbol %s found in unsupported section in %s",
a61fdf0a
A
2208 &fStrings[sym.n_strx()], this->getPath());
2209 }
d696c285
A
2210 }
2211 }
2212 }
2213 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
2214 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
2215 }
4be885f6
A
2216 else if ( (type == N_UNDF) && (sym.n_value() == 0) ) {
2217 const char* symName = &fStrings[sym.n_strx()];
2218 if ( strncmp(symName, "section$start$", 14) == 0)
2219 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, true, symName, &symName[14]));
2220 else if ( strncmp(symName, "section$end$", 12) == 0)
2221 fAtoms.push_back(new SectionBoundaryAtom<A>(*this, false, symName, &symName[12]));
2222 }
a61fdf0a
A
2223 else if ( type == N_ABS ) {
2224 const char* symName = &fStrings[sym.n_strx()];
2f2f92e4 2225 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
a61fdf0a
A
2226 // ignore .objc_class_name_* symbols
2227 fAppleObjc = true;
2228 }
2229 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
2230 // ignore empty *.eh symbols
2231 }
2232 else {
2233 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
2234 fAtoms.push_back(abAtom);
2235 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
2236 }
2237 }
2238 else if ( type == N_INDR ) {
2239 fHaveIndirectSymbols = true;
69a49097 2240 }
d696c285
A
2241 }
2242 }
2243
55e3d2f6
A
2244 // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names
2245 if ( fehFrameSection != NULL ) {
2246 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2247 // add if not already an atom at that address
2248 if ( fAddrToAtom.find(it->function.address) == fAddrToAtom.end() ) {
2249 AnonymousAtom<A>* funcAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->function.address), it->function.address, 0);
2250 fAtoms.push_back(funcAtom);
2251 fAddrToAtom[it->function.address] = funcAtom;
2252 // even though we've made a new atom, be conservative and make sure they lay out together
2253 if ( canScatterAtoms() ) {
2254 AtomAndOffset prev = findAtomAndOffset(it->function.address-1);
2255 if ( prev.atom != NULL ) {
2256 if ( ((BaseAtom*)(prev.atom))->getSectionRecord() == funcAtom->getSectionRecord() )
2257 new Reference<A>(A::kFollowOn, prev, AtomAndOffset(funcAtom));
2258 }
2259 }
2260 }
2261 }
2262 }
2263
2264
d696c285 2265 // add all fixed size anonymous atoms from special sections
55e3d2f6 2266 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2f2f92e4 2267 pint_t atomSize = 0;
d696c285
A
2268 uint8_t type (sect->flags() & SECTION_TYPE);
2269 validSectionType(type);
2270 bool suppress = false;
2271 switch ( type ) {
2272 case S_SYMBOL_STUBS:
2273 suppress = true;
2274 atomSize = sect->reserved2();
2275 break;
2276 case S_LAZY_SYMBOL_POINTERS:
2277 suppress = true;
2278 atomSize = sizeof(pint_t);
2279 break;
2280 case S_NON_LAZY_SYMBOL_POINTERS:
2281 case S_LITERAL_POINTERS:
2282 case S_MOD_INIT_FUNC_POINTERS:
2283 case S_MOD_TERM_FUNC_POINTERS:
2284 atomSize = sizeof(pint_t);
2285 break;
2286 case S_INTERPOSING:
2287 atomSize = sizeof(pint_t)*2;
2288 break;
2289 case S_4BYTE_LITERALS:
2290 atomSize = 4;
2291 break;
2292 case S_8BYTE_LITERALS:
2293 atomSize = 8;
2294 break;
69a49097
A
2295 case S_16BYTE_LITERALS:
2296 atomSize = 16;
2297 break;
2298 case S_REGULAR:
2299 // special case ObjC classes to synthesize .objc_class_name_* symbols
2300 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
2301 // gcc sometimes over aligns class structure
2302 uint32_t align = 1 << sect->align();
2303 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
a61fdf0a
A
2304 }
2305 // get objc Garbage Collection info
2306 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
2307 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
2308 // struct objc_image_info {
2309 // uint32_t version; // initially 0
2310 // uint32_t flags;
2311 // };
2312 // #define OBJC_IMAGE_SUPPORTS_GC 2
2313 // #define OBJC_IMAGE_GC_ONLY 4
2314 //
2315 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
2316 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
2317 uint32_t flags = E::get32(contents[1]);
2318 if ( (flags & 4) == 4 )
2319 fObjConstraint = ObjectFile::Reader::kObjcGC;
2320 else if ( (flags & 2) == 2 )
2321 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
2322 else
2323 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
2324 if ( (flags & 1) == 1 )
2325 fReplacementClasses = true;
2326 // don't make atom for this section
2327 atomSize = sect->size();
2328 suppress = true;
69a49097 2329 }
a61fdf0a 2330 else {
2f2f92e4 2331 warning("can't parse __OBJC/__image_info section in %s", fPath);
a61fdf0a
A
2332 }
2333 }
2f2f92e4
A
2334 // special case constant NS/CFString literals and make an atom out of each one
2335 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
2336 atomSize = 4 * sizeof(pint_t);
2337 }
c211e7c9
A
2338 // special case class reference sections
2339 else if ( (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0) ) {
2340 atomSize = sizeof(pint_t);;
2341 }
69a49097 2342 break;
d696c285
A
2343 }
2344 if ( atomSize != 0 ) {
2f2f92e4
A
2345 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
2346 pint_t atomAddr = sect->addr() + sectOffset;
d696c285
A
2347 // add if not already an atom at that address
2348 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
2349 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
2350 if ( !suppress )
2351 fAtoms.push_back(newAtom);
2352 fAddrToAtom[atomAddr] = newAtom->redirectTo();
2353 }
2354 }
2355 }
2356 }
2357
2358 // add all c-string anonymous atoms
55e3d2f6 2359 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
d696c285
A
2360 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
2361 uint32_t stringLen;
2f2f92e4 2362 pint_t stringAddr;
a61fdf0a
A
2363 BaseAtom* mostAlignedEmptyString = NULL;
2364 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
2f2f92e4
A
2365 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
2366 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
d696c285
A
2367 stringAddr = sect->addr() + sectOffset;
2368 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
4be885f6
A
2369 // add if not already a non-zero length atom at that address
2370 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(stringAddr);
2371 if ( (pos == fAddrToAtom.end()) || (pos->second->getSize() == 0) ) {
d696c285
A
2372 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
2373 if ( stringLen == 1 ) {
a61fdf0a 2374 // because of padding it may look like there are lots of empty strings, keep track of all
2f2f92e4 2375 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
a61fdf0a
A
2376 // record empty string with greatest alignment requirement
2377 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
2378 if ( (mostAlignedEmptyString == NULL)
2379 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
2380 mostAlignedEmptyString = newAtom;
2381 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
d696c285 2382 }
d696c285
A
2383 }
2384 else {
2385 fAtoms.push_back(newAtom);
2386 fAddrToAtom[stringAddr] = newAtom;
2387 }
2388 }
2389 }
a61fdf0a
A
2390 // map all uses of empty strings to the most aligned one
2391 if ( mostAlignedEmptyString != NULL ) {
2392 // make most aligned atom a real atom
2393 fAtoms.push_back(mostAlignedEmptyString);
2394 // map all other empty atoms to this one
2f2f92e4 2395 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
a61fdf0a
A
2396 fAddrToAtom[it->first] = mostAlignedEmptyString;
2397 }
2398 }
d696c285
A
2399 }
2400 }
2401
a61fdf0a
A
2402 // sort all atoms so far by address and section
2403 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2404
2405 //fprintf(stderr, "sorted atoms:\n");
2406 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
2407 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
2408
d696c285 2409 // create atoms to cover any non-debug ranges not handled above
55e3d2f6 2410 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
d696c285
A
2411 pint_t sectionStartAddr = sect->addr();
2412 pint_t sectionEndAddr = sect->addr() + sect->size();
55e3d2f6
A
2413 // don't set follow-on atoms in __eh_frame section
2414 const bool setFollowOnAtom = !canScatterAtoms() && (sect != fehFrameSection);
d696c285
A
2415 if ( sect->size() != 0 ) {
2416 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
2417 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
2418 fDebugInfo = kDebugInfoDwarf;
2419 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
2420 fDwarfDebugInfoSect = sect;
2421 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
2422 fDwarfDebugAbbrevSect = sect;
2423 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
2424 fDwarfDebugLineSect = sect;
55e3d2f6
A
2425 else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
2426 fDwarfDebugStringSect = sect;
d696c285
A
2427 }
2428 else {
2429 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
2430 throw "object file contains old DWARF debug info - rebuild with newer compiler";
2431 }
2432 uint8_t type (sect->flags() & SECTION_TYPE);
2433 switch ( type ) {
2434 case S_REGULAR:
2435 case S_ZEROFILL:
2436 case S_COALESCED:
69a49097 2437 // if there is not an atom already at the start of this section, add an anonymous one
2f2f92e4 2438 pint_t previousAtomAddr = 0;
d696c285
A
2439 BaseAtom* previousAtom = NULL;
2440 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
d696c285 2441 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
d696c285 2442 fAddrToAtom[sect->addr()] = newAtom;
a61fdf0a 2443 fAtoms.push_back(newAtom);
d696c285
A
2444 previousAtomAddr = sectionStartAddr;
2445 previousAtom = newAtom;
a61fdf0a 2446 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
d696c285
A
2447 }
2448 // calculate size of all atoms in this section and add follow-on references
a61fdf0a
A
2449 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2450 BaseAtom* atom = (BaseAtom*)(*it);
2f2f92e4 2451 pint_t atomAddr = atom->getObjectAddress();
a61fdf0a 2452 if ( atom->getSectionRecord() == sect ) {
2f2f92e4 2453 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
a61fdf0a
A
2454 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
2455 previousAtom->setSize(atomAddr - previousAtomAddr);
2456 if ( setFollowOnAtom && (atom != previousAtom) )
2457 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
d696c285 2458 }
a61fdf0a
A
2459 previousAtomAddr = atomAddr;
2460 previousAtom = atom;
2461 }
d696c285
A
2462 }
2463 if ( previousAtom != NULL ) {
2464 // set last atom in section
2465 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
2466 }
2467 break;
2468 }
2469 }
2470 }
2471 }
2472
a61fdf0a
A
2473 // check for object file that defines no objc classes, but uses objc classes
2474 // check for dtrace provider info
2475 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
2476 const macho_nlist<P>& sym = fSymbols[i];
2477 if ( (sym.n_type() & N_STAB) == 0 ) {
2478 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
2479 const char* undefinedName = &fStrings[sym.n_strx()];
2f2f92e4 2480 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
a61fdf0a
A
2481 fAppleObjc = true;
2482 }
2483 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
2484 if ( strchr(undefinedName, '$') != NULL ) {
2485 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
2486 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
2487 // is extra provider info
2488 fDtraceProviderInfo.push_back(undefinedName);
d696c285
A
2489 }
2490 }
a61fdf0a 2491 }
d696c285
A
2492 }
2493 }
2494 }
a61fdf0a
A
2495
2496 // add relocation based references to sections that have atoms with pending names
55e3d2f6 2497 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
a61fdf0a
A
2498 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
2499 addReferencesForSection(sect);
2500 }
2501
2502 // update any anonymous atoms that need references built in order to name themselves
2503 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
2504 (*it)->resolveName();
2505 }
d696c285 2506
a61fdf0a 2507 // add relocation based references to other sections
55e3d2f6 2508 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
a61fdf0a
A
2509 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
2510 addReferencesForSection(sect);
69a49097
A
2511 }
2512
2513 // add objective-c references
2514 if ( fAppleObjc ) {
55e3d2f6 2515 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
a61fdf0a 2516 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
69a49097 2517 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
a61fdf0a
A
2518 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
2519 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
2520 if ( classRef->getFixUpOffset() == 0 ) {
2521 const char* classStr = classRef->getTargetName();
2522 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
2523 const char* className;
2524 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
2525 new Reference<A>(A::kNoFixUp, ao, className, 0);
2526 }
2527 }
69a49097
A
2528 }
2529 }
2530 }
2531 }
2532
d696c285
A
2533 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
2534 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
2535 AnonymousAtom<A>* localNonLazy = *it;
2536 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
2537 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
2538 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
2539 }
a61fdf0a 2540
55e3d2f6
A
2541
2542 // add personality references to CIEs
2543 for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
2544 if ( it->personality.offsetInFDE != 0 )
2545 addCiePersonalityReference(fAddrToAtom[it->cieAddress], it->personality.offsetInFDE, it->personality.encodingOfAddress);
2546 }
2547
2548 // add all references for FDEs, including implicit group references
2549 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2550 AtomAndOffset funcAO = this->findAtomAndOffset(it->function.address);
2551 if ( funcAO.offset != 0 )
2552 warning("FDE does not point to start of function %s\n", funcAO.atom->getDisplayName());
2553 AtomAndOffset fdeAO = this->findAtomAndOffset(it->fdeAddress);
2554 if ( fdeAO.offset != 0 )
2555 warning("FDE does start its own atom %s\n", funcAO.atom->getDisplayName());
2556 AtomAndOffset cieAO = this->findAtomAndOffset(it->cie.address);
2557 if ( cieAO.offset != 0 )
2558 warning("CIE does start its own atom %s\n", cieAO.atom->getDisplayName());
2559 AtomAndOffset lsdaAO;
2560 if ( it->lsda.address != 0 ) {
2561 lsdaAO = this->findAtomAndOffset(it->lsda.address);
2562 if ( lsdaAO.offset != 0 )
2563 warning("LSDA does start its own atom %s\n", lsdaAO.atom->getDisplayName());
2564 }
2565
2566 // add reference from FDE to CIE
2567 AtomAndOffset cieInfdeAO = AtomAndOffset(fdeAO.atom, it->cie.offsetInFDE);
2568 new Reference<A>(A::kPointerDiff32, cieInfdeAO, cieAO, cieInfdeAO);
2569
2570 // add reference from FDE to function
2571 addFdeReference(it->function.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->function.offsetInFDE), funcAO);
2572
2573 // add reference from FDE to LSDA
2574 if ( it->lsda.address != 0 ) {
2575 addFdeReference(it->lsda.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->lsda.offsetInFDE), lsdaAO);
2576 }
2577
2578 // FDE is in group lead by function atom
2579 new Reference<A>(A::kGroupSubordinate, funcAO, fdeAO);
2580
2581 // LSDA is in group lead by function atom
2582 if ( it->lsda.address != 0 ) {
2583 new Reference<A>(A::kGroupSubordinate, funcAO, lsdaAO);
2584 // add back reference from LSDA to owning function
2585 new Reference<A>(A::kNoFixUp, lsdaAO, funcAO);
2586 }
2587
2588 // compute compact encoding for this FDE
2589 if ( fOptions.fAddCompactUnwindEncoding ) {
2590 ((BaseAtom*)(funcAO.atom))->setCompactUnwindEncoding(it->fdeAddress);
2591 // add reference from function atom to personality function
2592 // the only reference a CIE can have is the reference to the personality function
2593 std::vector<class ObjectFile::Reference*>& cieRefs = cieAO.atom->getReferences();
2594 if ( cieRefs.size() == 1 ) {
2595 new Reference<A>((typename A::ReferenceKinds)((BaseAtom*)(funcAO.atom))->getPersonalityReferenceKind(),
2596 funcAO, cieRefs[0]->getTargetName(), 0);
d696c285
A
2597 }
2598 }
2599 }
2600
a61fdf0a
A
2601 // add command line aliases
2602 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
2603 BaseAtom* target = this->findAtomByName(it->realName);
2604 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
2605 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
2606 }
2607
2608 // add dtrace probe locations
2609 if ( fHasDTraceProbes ) {
2610 for (uint32_t i=0; i < fSymbolCount; ++i) {
2611 const macho_nlist<P>& sym = fSymbols[i];
2612 if ( (sym.n_type() & N_STAB) == 0 ) {
2613 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
2614 const char* symbolName = &fStrings[sym.n_strx()];
2615 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
2616 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
2617 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
2618 }
2619 }
2620 }
2621 }
2622 }
2623
55e3d2f6 2624 // turn indirect symbols into SymbolAliasAtom
a61fdf0a
A
2625 if ( fHaveIndirectSymbols ) {
2626 for (uint32_t i=0; i < fSymbolCount; ++i) {
2627 const macho_nlist<P>& sym = fSymbols[i];
2628 if ( (sym.n_type() & N_STAB) == 0 ) {
2629 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
2630 const char* aliasName = &fStrings[sym.n_strx()];
2631 const char* targetName = &fStrings[sym.n_value()];
2632 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
2633 BaseAtom* target = this->findAtomByName(targetName);
2634 // only currently support N_INDR based aliases to something in the same .o file
2635 if ( target != NULL ) {
2636 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
2637 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
2638 }
2639 }
2640 }
2641 }
2642 }
d696c285 2643
2f2f92e4 2644 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
d696c285
A
2645 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
2646 //}
2647
2648 // add translation unit info from dwarf
2649 uint64_t stmtList;
2650 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
69a49097
A
2651 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
2652 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
2653 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
2654 // if can't parse dwarf, warn and give up
2655 fDwarfTranslationUnitFile = NULL;
2656 fDwarfTranslationUnitDir = NULL;
2f2f92e4 2657 warning("can't parse dwarf compilation unit info in %s", this->getPath());
69a49097
A
2658 fDebugInfo = kDebugInfoNone;
2659 }
d696c285
A
2660 }
2661 }
2662
2663 // add line number info to atoms from dwarf
2664 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2665 // file with just data will have no __debug_line info
a61fdf0a
A
2666 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
2667 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
d696c285
A
2668 // validate stmt_list
2669 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
2670 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
2671 if ( debug_line != NULL ) {
2672 struct line_reader_data* lines = line_open(&debug_line[stmtList],
2673 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
2674 struct line_info result;
2675 ObjectFile::Atom* curAtom = NULL;
2676 uint32_t curAtomOffset = 0;
2677 uint32_t curAtomAddress = 0;
2678 uint32_t curAtomSize = 0;
55e3d2f6
A
2679 if ( lines != NULL ) {
2680 while ( line_next (lines, &result, line_stop_pc) ) {
2681 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
2682 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
2683 // work around weird debug line table compiler generates if no functions in __text section
2684 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
2685 continue;
2686 // for performance, see if in next pc is in current atom
2687 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
2688 curAtomOffset = result.pc - curAtomAddress;
2689 }
2690 // or pc at end of current atom
2691 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
2692 curAtomOffset = result.pc - curAtomAddress;
2693 }
2694 else {
2695 // do slow look up of atom by address
2696 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
2697 curAtom = ao.atom;
2698 if ( curAtom == NULL )
2699 break; // file has line info but no functions
2700 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
2701 // a one line function can be returned by line_next() as one entry with pc at end of blob
2702 // look for alt atom starting at end of previous atom
2703 uint32_t previousEnd = curAtomAddress+curAtomSize;
2704 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
2705 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
2706 curAtom = alt.atom;
2707 curAtomOffset = alt.offset;
2708 curAtomAddress = previousEnd - alt.offset;
2709 curAtomSize = curAtom->getSize();
2710 }
2711 else {
2712 curAtomOffset = ao.offset;
2713 curAtomAddress = result.pc - ao.offset;
2714 curAtomSize = curAtom->getSize();
2715 }
a61fdf0a
A
2716 }
2717 else {
2718 curAtomOffset = ao.offset;
2719 curAtomAddress = result.pc - ao.offset;
2720 curAtomSize = curAtom->getSize();
2721 }
2722 }
55e3d2f6
A
2723 const char* filename;
2724 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2725 if ( pos == fDwarfIndexToFile.end() ) {
2726 filename = line_file(lines, result.file);
2727 fDwarfIndexToFile[result.file] = filename;
2728 }
a61fdf0a 2729 else {
55e3d2f6
A
2730 filename = pos->second;
2731 }
2732 ObjectFile::LineInfo info;
2733 info.atomOffset = curAtomOffset;
2734 info.fileName = filename;
2735 info.lineNumber = result.line;
2736 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2737 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
2738 ((BaseAtom*)curAtom)->addLineInfo(info);
2739 if ( result.end_of_sequence ) {
2740 curAtom = NULL;
a61fdf0a 2741 }
d696c285 2742 }
d696c285 2743 line_free(lines);
55e3d2f6 2744 }
d696c285
A
2745 }
2746 else {
2f2f92e4 2747 warning("could not parse dwarf line number info in %s", this->getPath());
d696c285
A
2748 }
2749 }
2750 }
2751 }
2752
2753 // if no dwarf, try processing stabs debugging info
2754 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2755 // scan symbol table for stabs entries
2756 fStabs.reserve(fSymbolCount); // reduce re-allocations
2757 BaseAtom* currentAtom = NULL;
2758 pint_t currentAtomAddress = 0;
2759 enum { start, inBeginEnd, inFun } state = start;
2760 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2761 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
69a49097 2762 bool useStab = true;
d696c285
A
2763 uint8_t type = sym->n_type();
2764 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2765 if ( (type & N_STAB) != 0 ) {
69a49097 2766 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
d696c285
A
2767 Stab stab;
2768 stab.atom = NULL;
2769 stab.type = type;
2770 stab.other = sym->n_sect();
2771 stab.desc = sym->n_desc();
2772 stab.value = sym->n_value();
2773 stab.string = NULL;
2774 switch (state) {
2775 case start:
2776 switch (type) {
2777 case N_BNSYM:
2778 // beginning of function block
2779 state = inBeginEnd;
2780 // fall into case to lookup atom by addresss
2781 case N_LCSYM:
2782 case N_STSYM:
2783 currentAtomAddress = sym->n_value();
2784 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2785 if ( currentAtom != NULL ) {
2786 stab.atom = currentAtom;
2787 stab.string = symString;
2788 }
2789 else {
2f2f92e4 2790 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
d696c285
A
2791 (uint64_t)sym->n_value(), path);
2792 }
2793 break;
2794 case N_SO:
2795 case N_OSO:
2796 case N_OPT:
2797 case N_LSYM:
a61fdf0a
A
2798 case N_RSYM:
2799 case N_PSYM:
d696c285
A
2800 // not associated with an atom, just copy
2801 stab.string = symString;
2802 break;
2803 case N_GSYM:
a61fdf0a 2804 {
d696c285
A
2805 // n_value field is NOT atom address ;-(
2806 // need to find atom by name match
2807 const char* colon = strchr(symString, ':');
2808 if ( colon != NULL ) {
2809 // build underscore leading name
2810 int nameLen = colon - symString;
2811 char symName[nameLen+2];
2812 strlcpy(&symName[1], symString, nameLen+1);
2813 symName[0] = '_';
2814 symName[nameLen+1] = '\0';
2815 currentAtom = findAtomByName(symName);
2816 if ( currentAtom != NULL ) {
2817 stab.atom = currentAtom;
2818 stab.string = symString;
2819 }
2820 }
74cfe461
A
2821 else {
2822 // might be a debug-note without trailing :G()
2823 currentAtom = findAtomByName(symString);
2824 if ( currentAtom != NULL ) {
2825 stab.atom = currentAtom;
2826 stab.string = symString;
2827 }
2828 }
d696c285 2829 if ( stab.atom == NULL ) {
55e3d2f6
A
2830 // ld_classic added bogus GSYM stabs for old style dtrace probes
2831 if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
2832 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
69a49097 2833 useStab = false;
d696c285
A
2834 }
2835 break;
a61fdf0a 2836 }
d696c285
A
2837 case N_FUN:
2838 // old style stabs without BNSYM
2839 state = inFun;
2840 currentAtomAddress = sym->n_value();
2841 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2842 if ( currentAtom != NULL ) {
2843 stab.atom = currentAtom;
2844 stab.string = symString;
2845 }
2846 else {
2f2f92e4 2847 warning("can't find atom for stabs FUN at %08llX in %s",
d696c285
A
2848 (uint64_t)currentAtomAddress, path);
2849 }
2850 break;
2851 case N_SOL:
2852 case N_SLINE:
2853 stab.string = symString;
2854 // old stabs
2855 break;
2856 case N_BINCL:
2857 case N_EINCL:
2858 case N_EXCL:
2859 stab.string = symString;
2860 // -gfull built .o file
2861 break;
2862 default:
2f2f92e4 2863 warning("unknown stabs type 0x%X in %s", type, path);
d696c285
A
2864 }
2865 break;
2866 case inBeginEnd:
2867 stab.atom = currentAtom;
2868 switch (type) {
2869 case N_ENSYM:
2870 state = start;
2871 currentAtom = NULL;
2872 break;
2873 case N_LCSYM:
2874 case N_STSYM:
a61fdf0a 2875 {
d696c285
A
2876 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2877 if ( nestedAtom != NULL ) {
2878 stab.atom = nestedAtom;
2879 stab.string = symString;
2880 }
2881 else {
2f2f92e4 2882 warning("can't find atom for stabs 0x%X at %08llX in %s",
d696c285
A
2883 type, (uint64_t)sym->n_value(), path);
2884 }
2885 break;
a61fdf0a 2886 }
d696c285
A
2887 case N_LBRAC:
2888 case N_RBRAC:
2889 case N_SLINE:
2890 // adjust value to be offset in atom
2891 stab.value -= currentAtomAddress;
2892 default:
2893 stab.string = symString;
2894 break;
2895 }
2896 break;
2897 case inFun:
2898 switch (type) {
2899 case N_FUN:
2900 if ( sym->n_sect() != 0 ) {
2901 // found another start stab, must be really old stabs...
2902 currentAtomAddress = sym->n_value();
2903 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2904 if ( currentAtom != NULL ) {
2905 stab.atom = currentAtom;
2906 stab.string = symString;
2907 }
2908 else {
2f2f92e4 2909 warning("can't find atom for stabs FUN at %08llX in %s",
d696c285
A
2910 (uint64_t)currentAtomAddress, path);
2911 }
2912 }
2913 else {
2914 // found ending stab, switch back to start state
2915 stab.string = symString;
2916 stab.atom = currentAtom;
2917 state = start;
2918 currentAtom = NULL;
2919 }
2920 break;
2921 case N_LBRAC:
2922 case N_RBRAC:
2923 case N_SLINE:
2924 // adjust value to be offset in atom
2925 stab.value -= currentAtomAddress;
2926 stab.atom = currentAtom;
2927 break;
2928 case N_SO:
2929 stab.string = symString;
2930 state = start;
2931 break;
2932 default:
2933 stab.atom = currentAtom;
2934 stab.string = symString;
2935 break;
2936 }
2937 break;
2938 }
2939 // add to list of stabs for this .o file
69a49097
A
2940 if ( useStab )
2941 fStabs.push_back(stab);
d696c285
A
2942 }
2943 }
2944 }
2945
d696c285
A
2946#if 0
2947 // special case precompiled header .o file (which has no content) to have one empty atom
2948 if ( fAtoms.size() == 0 ) {
2949 int pathLen = strlen(path);
2950 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2951 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2952 //phony->fSynthesizedName = ".gch.o";
2953 fAtoms.push_back(phony);
2954 }
2955 }
55e3d2f6
A
2956#endif
2957
2958 // sort all atoms by address
2959 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2960
2961 // set ordinal and sort references in each atom
2962 uint32_t index = fOrdinalBase;
2963 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2964 BaseAtom* atom = (BaseAtom*)(*it);
2965 atom->setOrdinal(index++);
2966 atom->sortReferences();
2967 }
2968
2969}
2970
2971template <typename A>
2972const macho_section<typename A::P>* Reader<A>::getSectionForAddress(pint_t addr)
2973{
2974 for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
2975 if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) )
2976 return sect;
2977 }
2978 throwf("section not found for address 0x%08llX", (uint64_t)addr);
2979}
2980
2981template <typename A>
2982ObjectFile::Atom* Reader<A>::getFunctionAtomFromFDEAddress(pint_t addr)
2983{
2984 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2985 if ( it->fdeAddress == addr ) {
2986 return findAtomAndOffset(it->function.address).atom;
2987 }
2988 }
2989 // CIEs won't be in fFDEInfos
2990 return NULL;
2991}
2992
2993template <typename A>
2994ObjectFile::Atom* Reader<A>::getFunctionAtomFromLSDAAddress(pint_t addr)
2995{
2996 for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
2997 if ( it->lsda.address == addr ) {
2998 return findAtomAndOffset(it->function.address).atom;
2999 }
3000 }
3001 return NULL;
3002}
3003
3004
fb24a050
A
3005template <>
3006void ObjectFileAddressSpace<x86_64>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
3007{
3008 // mach-o x86_64 is different, the content of a section with a relocation is the addend
3009 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + sect->reloff());
3010 const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
3011 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3012 std::map<uint32_t,uint64_t>::iterator pos;
3013 switch ( reloc->r_type() ) {
3014 case X86_64_RELOC_UNSIGNED:
3015 pos = map.find(reloc->r_address());
3016 if ( pos != map.end() )
3017 pos->second += fReader.fSymbols[reloc->r_symbolnum()].n_value();
3018 else
3019 map[reloc->r_address()] = fReader.fSymbols[reloc->r_symbolnum()].n_value();
3020 break;
3021 case X86_64_RELOC_SUBTRACTOR:
3022 map[reloc->r_address()] = -fReader.fSymbols[reloc->r_symbolnum()].n_value();
3023 break;
3024 case X86_64_RELOC_GOT:
3025 // there is no good address to return here.
3026 // GOT slots are synthsized by the linker
3027 // this is used for the reference to the personality function in CIEs
3028 map[reloc->r_address()] = 0;
3029 break;
3030 default:
3031 fprintf(stderr, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc->r_address());
3032 break;
3033 }
3034 }
3035}
3036
3037template <typename A>
3038void ObjectFileAddressSpace<A>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
3039{
3040 // in all architectures except x86_64, the section contents are already fixed up to point
3041 // to content in the same object file.
3042}
55e3d2f6
A
3043
3044template <>
3045uint64_t ObjectFileAddressSpace<x86_64>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
3046{
3047 // mach-o x86_64 is different, the content of a section with a relocation is the addend
3048 uint64_t result = 0;
3049 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + relocsOffset);
3050 const macho_relocation_info<P>* relocsEnd = &relocs[relocsCount];
3051 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3052 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address());
3053 if ( reloc->r_address() == sectOffset ) {
3054 switch ( reloc->r_type() ) {
3055 case X86_64_RELOC_UNSIGNED:
3056 result += fReader.fSymbols[reloc->r_symbolnum()].n_value();
3057 break;
3058 case X86_64_RELOC_SUBTRACTOR:
3059 result -= fReader.fSymbols[reloc->r_symbolnum()].n_value();
3060 break;
3061 case X86_64_RELOC_GOT:
3062 // there is no good address to return here.
3063 // GOT slots are synthsized by the linker
3064 // this is used for the reference to the personality function in CIEs
3065 result = 0;
3066 break;
3067 default:
3068 fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset, reloc->r_type(), reloc->r_symbolnum());
3069 break;
3070 }
3071 }
3072 }
3073 //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result);
3074 return result;
3075}
3076
3077template <typename A>
3078typename A::P::uint_t ObjectFileAddressSpace<A>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
3079{
3080 // in all architectures except x86_64, the section contents are already fixed up to point
3081 // to content in the same object file.
3082 return 0;
3083}
3084
3085
3086
3087// FSF exception handling Pointer-Encoding constants
3088// Used in CFI augmentation by gcc compiler
3089enum {
3090 DW_EH_PE_ptr = 0x00,
3091 DW_EH_PE_uleb128 = 0x01,
3092 DW_EH_PE_udata2 = 0x02,
3093 DW_EH_PE_udata4 = 0x03,
3094 DW_EH_PE_udata8 = 0x04,
3095 DW_EH_PE_signed = 0x08,
3096 DW_EH_PE_sleb128 = 0x09,
3097 DW_EH_PE_sdata2 = 0x0A,
3098 DW_EH_PE_sdata4 = 0x0B,
3099 DW_EH_PE_sdata8 = 0x0C,
3100 DW_EH_PE_absptr = 0x00,
3101 DW_EH_PE_pcrel = 0x10,
3102 DW_EH_PE_textrel = 0x20,
3103 DW_EH_PE_datarel = 0x30,
3104 DW_EH_PE_funcrel = 0x40,
3105 DW_EH_PE_aligned = 0x50,
3106 DW_EH_PE_indirect = 0x80,
3107 DW_EH_PE_omit = 0xFF
3108};
3109
3110template <>
3111void Reader<x86_64>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
3112{
3113 if ( encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4) )
3114 throw "unexpected personality encoding in CIE";
3115
3116 // walk relocs looking for reloc in this CIE
3117 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
3118 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
3119 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
3120 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3121 if ( reloc->r_address() == sectOffset ) {
3122 switch ( reloc->r_type() ) {
3123 case X86_64_RELOC_GOT:
3124 if ( !reloc->r_extern() )
3125 throw "GOT reloc not extern for personality function";
3126 new Reference<x86_64>(x86_64::kPCRel32GOT, AtomAndOffset(cieAtom, offsetInCIE), &fStrings[fSymbols[reloc->r_symbolnum()].n_strx()], 4);
3127 return;
3128 default:
3129 throw "expected GOT reloc for personality function";
3130 }
3131 }
3132 }
3133 throw "personality function not found for CIE";
3134}
3135
3136template <>
3137bool Reader<ppc>::isSectDiffReloc(uint8_t r_type)
3138{
3139 switch ( r_type ) {
3140 case PPC_RELOC_LOCAL_SECTDIFF:
3141 case PPC_RELOC_SECTDIFF:
3142 return true;
3143 }
3144 return false;
3145}
3146
3147template <>
3148bool Reader<ppc64>::isSectDiffReloc(uint8_t r_type)
3149{
3150 switch ( r_type ) {
3151 case PPC_RELOC_LOCAL_SECTDIFF:
3152 case PPC_RELOC_SECTDIFF:
3153 return true;
3154 }
3155 return false;
3156}
3157
3158template <>
3159bool Reader<x86>::isSectDiffReloc(uint8_t r_type)
3160{
3161 switch ( r_type ) {
3162 case GENERIC_RELOC_LOCAL_SECTDIFF:
3163 case GENERIC_RELOC_SECTDIFF:
3164 return true;
3165 }
3166 return false;
3167}
3168
3169template <>
3170bool Reader<arm>::isSectDiffReloc(uint8_t r_type)
3171{
3172 switch ( r_type ) {
3173 case ARM_RELOC_LOCAL_SECTDIFF:
3174 case ARM_RELOC_SECTDIFF:
3175 return true;
3176 }
3177 return false;
3178}
3179
3180template <typename A>
3181void Reader<A>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
3182{
3183 if ( (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4)) && (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel)) )
3184 throw "unexpected personality encoding in CIE";
3185
3186 // walk relocs looking for personality reloc in this CIE
3187 uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
3188 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
3189 const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
3190 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3191 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3192 // ignore
3193 }
3194 else {
3195 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3196 if ( sreloc->r_address() == sectOffset ) {
3197 if ( isSectDiffReloc(sreloc->r_type()) ) {
3198 // r_value is address of non-lazy-pointer to personality function
3199 new Reference<A>(A::kPointerDiff32, AtomAndOffset(cieAtom, offsetInCIE), AtomAndOffset(cieAtom, offsetInCIE),
3200 findAtomAndOffset(sreloc->r_value()));
3201 return;
3202 }
3203 }
3204 }
3205 }
3206 throw "can't find relocation for personality in CIE";
3207}
a61fdf0a 3208
55e3d2f6
A
3209template <typename A>
3210void Reader<A>::addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target)
3211{
3212 if ( (encoding & 0xF0) != DW_EH_PE_pcrel )
3213 throw "unsupported encoding in FDE";
3214 Kinds kind = A::kNoFixUp;
3215 switch ( encoding & 0xF ) {
3216 case DW_EH_PE_ptr:
3217 kind = A::kPointerDiff;
3218 break;
3219 case DW_EH_PE_sdata4:
3220 kind = A::kPointerDiff32;
3221 break;
3222 default:
3223 throw "unsupported encoding in FDE";
3224 }
3225 new Reference<A>(kind, inFDE, inFDE, target);
3226}
a61fdf0a 3227
55e3d2f6
A
3228template <typename A>
3229typename A::P::uint_t ObjectFileAddressSpace<A>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
3230{
3231 pint_t startAddr = addr;
3232 pint_t p = addr;
3233 pint_t result;
3234
3235 // first get value
3236 switch (encoding & 0x0F) {
3237 case DW_EH_PE_ptr:
3238 result = getP(addr);
3239 p += sizeof(pint_t);
3240 addr = (pint_t)p;
3241 break;
3242 case DW_EH_PE_uleb128:
3243 result = getULEB128(addr, end);
3244 break;
3245 case DW_EH_PE_udata2:
3246 result = get16(addr);
3247 p += 2;
3248 addr = (pint_t)p;
3249 break;
3250 case DW_EH_PE_udata4:
3251 result = get32(addr);
3252 p += 4;
3253 addr = (pint_t)p;
3254 break;
3255 case DW_EH_PE_udata8:
3256 result = get64(addr);
3257 p += 8;
3258 addr = (pint_t)p;
3259 break;
3260 case DW_EH_PE_sleb128:
3261 result = getSLEB128(addr, end);
3262 break;
3263 case DW_EH_PE_sdata2:
3264 result = (int16_t)get16(addr);
3265 p += 2;
3266 addr = (pint_t)p;
3267 break;
3268 case DW_EH_PE_sdata4:
3269 result = (int32_t)get32(addr);
3270 p += 4;
3271 addr = (pint_t)p;
3272 break;
3273 case DW_EH_PE_sdata8:
3274 result = get64(addr);
3275 p += 8;
3276 addr = (pint_t)p;
3277 break;
3278 default:
3279 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3280 }
3281
3282 // then add relative offset
3283 switch ( encoding & 0x70 ) {
3284 case DW_EH_PE_absptr:
3285 // do nothing
3286 break;
3287 case DW_EH_PE_pcrel:
c211e7c9
A
3288 // <rdar://problem/7200658> pc-rel sdata4 should return zero if content is zero
3289 if ( (result != 0) || ((encoding & DW_EH_PE_indirect) != 0) )
3290 result += startAddr;
55e3d2f6
A
3291 break;
3292 case DW_EH_PE_textrel:
3293 throw "DW_EH_PE_textrel pointer encoding not supported";
3294 break;
3295 case DW_EH_PE_datarel:
3296 throw "DW_EH_PE_datarel pointer encoding not supported";
3297 break;
3298 case DW_EH_PE_funcrel:
3299 throw "DW_EH_PE_funcrel pointer encoding not supported";
3300 break;
3301 case DW_EH_PE_aligned:
3302 throw "DW_EH_PE_aligned pointer encoding not supported";
3303 break;
3304 default:
3305 throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
3306 break;
a61fdf0a
A
3307 }
3308
55e3d2f6
A
3309 if ( encoding & DW_EH_PE_indirect )
3310 result = getP(result);
3311
3312 return result;
3313}
3314
3315template <>
3316uint32_t SymbolAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3317{
3318 pint_t lsda;
3319 pint_t personality;
fb24a050 3320 char warningBuffer[1024];
55e3d2f6 3321 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
fb24a050
A
3322 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3323 if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
55e3d2f6
A
3324 //if ( fOwner.fOptions.fForDyld )
3325 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3326 //else
3327 if ( fOwner.fOptions.fWarnCompactUnwind )
fb24a050 3328 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
55e3d2f6
A
3329 }
3330 return result;
3331}
3332
3333template <>
3334uint32_t SymbolAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3335{
3336 pint_t lsda;
3337 pint_t personality;
fb24a050 3338 char warningBuffer[1024];
55e3d2f6 3339 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
fb24a050
A
3340 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3341 if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
55e3d2f6
A
3342 //if ( fOwner.fOptions.fForDyld )
3343 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3344 //else
3345 if ( fOwner.fOptions.fWarnCompactUnwind )
fb24a050 3346 warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
55e3d2f6
A
3347 }
3348 return result;
3349}
3350
3351template <>
3352uint32_t SymbolAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3353{
3354 // compact encoding not supported for ppc
3355 return 0;
3356}
3357
3358template <>
3359uint32_t SymbolAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3360{
3361 // compact encoding not supported for ppc64
3362 return 0;
3363}
3364
3365template <>
3366uint32_t SymbolAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3367{
3368 // compact encoding not supported for arm
3369 return 0;
3370}
3371
3372
3373template <typename A>
3374uint8_t SymbolAtom<A>::getLSDAReferenceKind() const
3375{
3376 return A::kGroupSubordinate;
3377}
3378
3379template <>
3380uint8_t SymbolAtom<x86_64>::getPersonalityReferenceKind() const
3381{
3382 return x86_64::kGOTNoFixUp;
3383}
3384
3385template <>
3386uint8_t SymbolAtom<x86>::getPersonalityReferenceKind() const
3387{
3388 return x86::kNoFixUp;
3389}
3390
3391template <typename A>
3392uint8_t SymbolAtom<A>::getPersonalityReferenceKind() const
3393{
3394 // only used with architectures that support compact unwinding
3395 return 0;
3396}
3397
3398
3399template <>
3400uint32_t AnonymousAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3401{
3402 pint_t lsda;
3403 pint_t personality;
fb24a050 3404 char warningBuffer[1024];
55e3d2f6 3405 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
fb24a050
A
3406 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3407 if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
55e3d2f6
A
3408 //if ( fOwner.fOptions.fForDyld )
3409 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3410 //else
fb24a050 3411 if ( fOwner.fOptions.fWarnCompactUnwind )
55e3d2f6
A
3412 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3413 }
3414 return result;
3415}
3416
3417template <>
3418uint32_t AnonymousAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3419{
3420 pint_t lsda;
3421 pint_t personality;
fb24a050 3422 char warningBuffer[1024];
55e3d2f6 3423 uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
fb24a050
A
3424 fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
3425 if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
55e3d2f6
A
3426 //if ( fOwner.fOptions.fForDyld )
3427 // throwf("can't make compact unwind encoding from dwarf for %s", this->getDisplayName());
3428 //else
fb24a050 3429 if ( fOwner.fOptions.fWarnCompactUnwind )
55e3d2f6
A
3430 warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
3431 }
3432 return result;
3433}
3434
3435template <>
3436uint32_t AnonymousAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3437{
3438 // compact encoding not supported for ppc
3439 return 0;
3440}
3441
3442template <>
3443uint32_t AnonymousAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3444{
3445 // compact encoding not supported for ppc64
3446 return 0;
3447}
3448
3449template <>
3450uint32_t AnonymousAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
3451{
3452 // compact encoding not supported for arm
3453 return 0;
3454}
3455
3456
3457template <typename A>
3458uint8_t AnonymousAtom<A>::getLSDAReferenceKind() const
3459{
3460 return A::kGroupSubordinate;
3461}
3462
3463template <>
3464uint8_t AnonymousAtom<x86_64>::getPersonalityReferenceKind() const
3465{
3466 return x86_64::kGOTNoFixUp;
3467}
3468
3469template <>
3470uint8_t AnonymousAtom<x86>::getPersonalityReferenceKind() const
3471{
3472 return x86::kNoFixUp;
3473}
3474
3475template <typename A>
3476uint8_t AnonymousAtom<A>::getPersonalityReferenceKind() const
3477{
3478 // only used with architectures that support compact unwinding
3479 return 0;
a61fdf0a
A
3480}
3481
3482
55e3d2f6
A
3483
3484
3485
3486
3487
a61fdf0a
A
3488template <>
3489void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
3490{
3491 switch (cpusubtype) {
3492 case CPU_SUBTYPE_POWERPC_ALL:
a61fdf0a 3493 case CPU_SUBTYPE_POWERPC_750:
a61fdf0a
A
3494 case CPU_SUBTYPE_POWERPC_7400:
3495 case CPU_SUBTYPE_POWERPC_7450:
a61fdf0a 3496 case CPU_SUBTYPE_POWERPC_970:
2f2f92e4 3497 fCpuConstraint = cpusubtype;
a61fdf0a
A
3498 break;
3499 default:
2f2f92e4
A
3500 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3501 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
3502 break;
a61fdf0a
A
3503 }
3504}
3505
2f2f92e4
A
3506template <>
3507void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
3508{
3509 switch (cpusubtype) {
3510 case CPU_SUBTYPE_ARM_ALL:
3511 case CPU_SUBTYPE_ARM_V4T:
3512 case CPU_SUBTYPE_ARM_V5TEJ:
3513 case CPU_SUBTYPE_ARM_V6:
3514 case CPU_SUBTYPE_ARM_XSCALE:
77cc3118 3515 case CPU_SUBTYPE_ARM_V7:
2f2f92e4
A
3516 fCpuConstraint = cpusubtype;
3517 break;
3518 default:
3519 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
3520 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
3521 break;
3522 }
3523}
a61fdf0a
A
3524
3525template <typename A>
3526void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
3527{
3528 // no cpu sub types for this architecture
3529}
3530
2f2f92e4
A
3531template <>
3532uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
3533{
3534 switch ( previous ) {
3535 case CPU_SUBTYPE_POWERPC_ALL:
3536 return fCpuConstraint;
3537 break;
3538 case CPU_SUBTYPE_POWERPC_750:
3539 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
3540 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
3541 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3542 return fCpuConstraint;
3543 break;
3544 case CPU_SUBTYPE_POWERPC_7400:
3545 case CPU_SUBTYPE_POWERPC_7450:
3546 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
3547 return fCpuConstraint;
3548 break;
3549 case CPU_SUBTYPE_POWERPC_970:
3550 // G5 can run everything
3551 break;
3552 default:
3553 throw "Unhandled PPC cpu subtype!";
3554 break;
3555 }
3556 return previous;
3557}
3558
3559
3560
3561template <>
3562uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
3563{
3564 switch (previous) {
3565 case CPU_SUBTYPE_ARM_ALL:
3566 return fCpuConstraint;
3567 break;
3568 case CPU_SUBTYPE_ARM_V5TEJ:
77cc3118 3569 // v6, v7, and xscale are more constrained than previous file (v5), so use it
2f2f92e4 3570 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
77cc3118 3571 || (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
2f2f92e4
A
3572 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3573 return fCpuConstraint;
3574 break;
3575 case CPU_SUBTYPE_ARM_V4T:
77cc3118
A
3576 // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
3577 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
3578 || (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
2f2f92e4
A
3579 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
3580 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
3581 return fCpuConstraint;
3582 break;
3583 case CPU_SUBTYPE_ARM_V6:
77cc3118 3584 // v6 can run everything except xscale and v7
2f2f92e4
A
3585 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3586 throw "can't mix xscale and v6 code";
77cc3118
A
3587 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3588 return fCpuConstraint;
2f2f92e4
A
3589 break;
3590 case CPU_SUBTYPE_ARM_XSCALE:
77cc3118 3591 // xscale can run everything except v6 and v7
2f2f92e4
A
3592 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
3593 throw "can't mix xscale and v6 code";
77cc3118
A
3594 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
3595 throw "can't mix xscale and v7 code";
3596 break;
3597 case CPU_SUBTYPE_ARM_V7:
3598 // v7 can run everything except xscale
3599 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
3600 throw "can't mix xscale and v7 code";
2f2f92e4
A
3601 break;
3602 default:
3603 throw "Unhandled ARM cpu subtype!";
3604 }
3605 return previous;
3606}
3607
3608template <typename A>
3609uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
3610{
3611 // no cpu sub types for this architecture
3612 return current;
3613}
3614
a61fdf0a
A
3615template <typename A>
3616void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
3617{
3618 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
3619 // a matching provider name, add a by-name kDtraceTypeReference at probe site
3620 const char* dollar = strchr(providerName, '$');
3621 if ( dollar != NULL ) {
3622 int providerNameLen = dollar-providerName+1;
3623 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
3624 const char* typeDollar = strchr(*it, '$');
3625 if ( typeDollar != NULL ) {
3626 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
3627 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
3628 }
3629 }
3630 }
3631 }
d696c285
A
3632}
3633
a61fdf0a 3634
69a49097
A
3635template <>
3636void Reader<x86_64>::validSectionType(uint8_t type)
3637{
3638 switch ( type ) {
3639 case S_SYMBOL_STUBS:
3640 throw "symbol_stub sections not valid in x86_64 object files";
3641 case S_LAZY_SYMBOL_POINTERS:
3642 throw "lazy pointer sections not valid in x86_64 object files";
3643 case S_NON_LAZY_SYMBOL_POINTERS:
3644 throw "non lazy pointer sections not valid in x86_64 object files";
3645 }
3646}
d696c285
A
3647
3648template <typename A>
3649void Reader<A>::validSectionType(uint8_t type)
3650{
3651}
3652
3653template <typename A>
3654bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
3655{
3656 if ( fDebugInfo == kDebugInfoDwarf ) {
3657 *dir = fDwarfTranslationUnitDir;
3658 *name = fDwarfTranslationUnitFile;
a61fdf0a 3659 return (fDwarfTranslationUnitFile != NULL);
d696c285
A
3660 }
3661 return false;
3662}
3663
3664template <typename A>
3665BaseAtom* Reader<A>::findAtomByName(const char* name)
3666{
3667 // first search the more important atoms
2f2f92e4 3668 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
d696c285
A
3669 const char* atomName = it->second->getName();
3670 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3671 return it->second;
3672 }
3673 }
3674 // try all atoms, because this might have been a tentative definition
a61fdf0a 3675 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
d696c285
A
3676 BaseAtom* atom = (BaseAtom*)(*it);
3677 const char* atomName = atom->getName();
3678 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
3679 return atom;
3680 }
3681 }
3682 return NULL;
3683}
3684
3685template <typename A>
2f2f92e4 3686Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
d696c285
A
3687{
3688 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
3689}
3690
3691template <typename A>
2f2f92e4 3692Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
d696c285
A
3693{
3694 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
3695}
3696
3697template <typename A>
2f2f92e4 3698Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
d696c285
A
3699{
3700 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
3701}
3702
3703template <typename A>
2f2f92e4 3704Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
d696c285
A
3705{
3706 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
3707}
3708
3709template <typename A>
2f2f92e4 3710Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
d696c285
A
3711{
3712 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3713}
3714
3715template <typename A>
55e3d2f6 3716BaseAtom* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
d696c285 3717{
55e3d2f6 3718 // add a group subordinate reference from function atom to its eh frame atom
d696c285
A
3719 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
3720 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
2f2f92e4 3721 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
55e3d2f6
A
3722 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3723 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3724 new Reference<A>(A::kGroupSubordinate, funcAtom, ehAtom);
3725 return (BaseAtom*)funcAtom;
d696c285
A
3726}
3727
3728
69a49097 3729template <>
2f2f92e4 3730Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
69a49097
A
3731{
3732 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3733 // instead check scope of target
3734 BaseAtom* target = findAtomByName(toName);
3735 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
3736 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
3737 else
3738 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
3739}
3740
3741template <>
2f2f92e4 3742Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
69a49097
A
3743{
3744 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
3745 // instead check scope of target
a61fdf0a 3746 const char* symbolName = &fStrings[toSymbol->n_strx()];
4be885f6
A
3747 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) {
3748 AtomAndOffset targetAO = findAtomAndOffsetForSection(toSymbol->n_value(), toSymbol->n_sect());
3749 targetAO.offset = toOffset;
3750 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), targetAO);
3751 }
69a49097 3752 else
a61fdf0a 3753 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
69a49097
A
3754}
3755
3756
3757template <>
55e3d2f6 3758BaseAtom* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
69a49097 3759{
55e3d2f6 3760 // add a group subordinate reference from function atom to its eh frame atom
69a49097
A
3761 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
3762 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
3763 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
3764 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
3765 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
3766 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
2f2f92e4 3767 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
55e3d2f6
A
3768 ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
3769 ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
3770 new Reference<x86_64>(x86_64::kGroupSubordinate, funcAtom, ehAtom);
3771 return (BaseAtom*)funcAtom;
69a49097
A
3772 }
3773 }
2f2f92e4 3774 warning("can't find matching function for eh symbol %s", ehName);
69a49097
A
3775 return NULL;
3776}
d696c285 3777
4be885f6
A
3778template <typename A>
3779AtomAndOffset Reader<A>::findAtomAndOffsetForSection(pint_t addr, unsigned int expectedSectionIndex)
3780{
3781 AtomAndOffset ao = findAtomAndOffset(addr);
3782 if ( ao.atom != NULL ) {
3783 if ( ((BaseAtom*)(ao.atom))->getSectionIndex() == expectedSectionIndex )
3784 return ao;
3785 }
3786 // The atom found is not in the section expected.
3787 // This probably means there was a label at the end of the section.
3788 // Do a slow sequential lookup
3789 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); ++it) {
3790 BaseAtom* atom = *it;
3791 if ( atom->getSectionIndex() == expectedSectionIndex ) {
3792 pint_t objAddr = atom->getObjectAddress();
3793 if ( (objAddr == addr) || ((objAddr < addr) && (objAddr+atom->getSize() > addr)) ) {
3794 return AtomAndOffset(atom, addr-atom->getObjectAddress());
3795 }
3796 }
3797 }
fb24a050
A
3798 // no atom found that matched section, fall back to one orginally found
3799 return ao;
4be885f6 3800}
86b84c30 3801
d696c285 3802template <typename A>
2f2f92e4 3803AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
d696c285
A
3804{
3805 // STL has no built-in for "find largest key that is same or less than"
2f2f92e4
A
3806 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
3807 // if no atoms up to this address return none found
3808 if ( it == fAddrToAtom.begin() )
3809 return AtomAndOffset(NULL);
3810 // otherwise upper_bound gets us next key, so we back up one
3811 --it;
d696c285
A
3812 AtomAndOffset result;
3813 result.atom = it->second;
3814 result.offset = addr - it->first;
2f2f92e4
A
3815 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
3816 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
d696c285
A
3817 return result;
3818}
3819
3820// "scattered" relocations enable you to offset into an atom past the end of it
3821// baseAddr is the address of the target atom,
3822// realAddr is the points into it
3823template <typename A>
2f2f92e4 3824AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
d696c285 3825{
2f2f92e4 3826 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
d696c285
A
3827 if ( it != fAddrToAtom.end() ) {
3828 AtomAndOffset result;
3829 result.atom = it->second;
3830 result.offset = realAddr - it->first;
55e3d2f6
A
3831 if ( result.atom->isThumb() )
3832 result.offset &= -2;
d696c285
A
3833 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
3834 return result;
3835 }
3836 // getting here means we have a scattered relocation to an address without a label
fb24a050
A
3837 // so, find the atom that contains the baseAddr, and offset from that to the readAddr
3838 AtomAndOffset result = findAtomAndOffset(baseAddr);
3839 result.offset += (realAddr-baseAddr);
3840 return result;
d696c285
A
3841}
3842
3843
3844/* Skip over a LEB128 value (signed or unsigned). */
3845static void
3846skip_leb128 (const uint8_t ** offset, const uint8_t * end)
3847{
3848 while (*offset != end && **offset >= 0x80)
3849 (*offset)++;
3850 if (*offset != end)
3851 (*offset)++;
3852}
3853
3854/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
3855 or error. On overflow, skip past the rest of the uleb128. */
3856static uint64_t
3857read_uleb128 (const uint8_t ** offset, const uint8_t * end)
3858{
3859 uint64_t result = 0;
3860 int bit = 0;
3861
3862 do {
3863 uint64_t b;
3864
3865 if (*offset == end)
3866 return (uint64_t) -1;
3867
3868 b = **offset & 0x7f;
3869
3870 if (bit >= 64 || b << bit >> bit != b)
3871 result = (uint64_t) -1;
3872 else
3873 result |= b << bit, bit += 7;
3874 } while (*(*offset)++ >= 0x80);
3875 return result;
3876}
3877
3878
3879/* Skip over a DWARF attribute of form FORM. */
3880template <typename A>
3881bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
3882 uint8_t addr_size, bool dwarf64)
3883{
3884 int64_t sz=0;
3885
3886 switch (form)
3887 {
3888 case DW_FORM_addr:
3889 sz = addr_size;
3890 break;
3891
3892 case DW_FORM_block2:
3893 if (end - *offset < 2)
3894 return false;
3895 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
3896 break;
3897
3898 case DW_FORM_block4:
3899 if (end - *offset < 4)
3900 return false;
3901 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
3902 break;
3903
3904 case DW_FORM_data2:
3905 case DW_FORM_ref2:
3906 sz = 2;
3907 break;
3908
3909 case DW_FORM_data4:
3910 case DW_FORM_ref4:
3911 sz = 4;
3912 break;
3913
3914 case DW_FORM_data8:
3915 case DW_FORM_ref8:
3916 sz = 8;
3917 break;
3918
3919 case DW_FORM_string:
3920 while (*offset != end && **offset)
3921 ++*offset;
3922 case DW_FORM_data1:
3923 case DW_FORM_flag:
3924 case DW_FORM_ref1:
3925 sz = 1;
3926 break;
3927
3928 case DW_FORM_block:
3929 sz = read_uleb128 (offset, end);
3930 break;
3931
3932 case DW_FORM_block1:
3933 if (*offset == end)
3934 return false;
3935 sz = 1 + **offset;
3936 break;
3937
3938 case DW_FORM_sdata:
3939 case DW_FORM_udata:
3940 case DW_FORM_ref_udata:
3941 skip_leb128 (offset, end);
3942 return true;
3943
3944 case DW_FORM_strp:
3945 case DW_FORM_ref_addr:
55e3d2f6 3946 sz = 4;
d696c285
A
3947 break;
3948
3949 default:
3950 return false;
3951 }
3952 if (end - *offset < sz)
3953 return false;
3954 *offset += sz;
3955 return true;
3956}
3957
55e3d2f6
A
3958template <typename A>
3959const char* Reader<A>::getDwarfString(uint64_t form, const uint8_t* p)
3960{
3961 if ( form == DW_FORM_string )
3962 return (const char*)p;
3963 else if ( form == DW_FORM_strp ) {
3964 uint32_t offset = E::get32(*((uint32_t*)p));
3965 const char* dwarfStrings = (char*)(fHeader) + fDwarfDebugStringSect->offset();
3966 if ( offset > fDwarfDebugStringSect->size() ) {
3967 warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->getPath());
3968 return NULL;
3969 }
3970 return &dwarfStrings[offset];
3971 }
3972 warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->getPath());
3973 return NULL;
3974}
3975
3976
d696c285
A
3977// Look at the compilation unit DIE and determine
3978// its NAME, compilation directory (in COMP_DIR) and its
3979// line number information offset (in STMT_LIST). NAME and COMP_DIR
3980// may be NULL (especially COMP_DIR) if they are not in the .o file;
3981// STMT_LIST will be (uint64_t) -1.
3982//
3983// At present this assumes that there's only one compilation unit DIE.
3984//
3985template <typename A>
3986bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
3987 uint64_t *stmt_list)
3988{
3989 const uint8_t * debug_info;
3990 const uint8_t * debug_abbrev;
3991 const uint8_t * di;
3992 const uint8_t * da;
3993 const uint8_t * end;
3994 const uint8_t * enda;
3995 uint64_t sz;
3996 uint16_t vers;
3997 uint64_t abbrev_base;
3998 uint64_t abbrev;
3999 uint8_t address_size;
4000 bool dwarf64;
4001
4002 *name = NULL;
4003 *comp_dir = NULL;
4004 *stmt_list = (uint64_t) -1;
4005
4006 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
4007 return false;
4008
4009 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
4010 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
4011 di = debug_info;
4012
4013 if (fDwarfDebugInfoSect->size() < 12)
4014 /* Too small to be a real debug_info section. */
4015 return false;
4016 sz = A::P::E::get32(*(uint32_t*)di);
4017 di += 4;
4018 dwarf64 = sz == 0xffffffff;
4019 if (dwarf64)
4020 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
4021 else if (sz > 0xffffff00)
4022 /* Unknown dwarf format. */
4023 return false;
4024
4025 /* Verify claimed size. */
4026 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
4027 return false;
4028
4029 vers = A::P::E::get16(*(uint16_t*)di);
4030 if (vers < 2 || vers > 3)
4031 /* DWARF version wrong for this code.
4032 Chances are we could continue anyway, but we don't know for sure. */
4033 return false;
4034 di += 2;
4035
4036 /* Find the debug_abbrev section. */
4037 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
4038 di += dwarf64 ? 8 : 4;
4039
4040 if (abbrev_base > fDwarfDebugAbbrevSect->size())
4041 return false;
4042 da = debug_abbrev + abbrev_base;
4043 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
4044
4045 address_size = *di++;
4046
4047 /* Find the abbrev number we're looking for. */
4048 end = di + sz;
4049 abbrev = read_uleb128 (&di, end);
4050 if (abbrev == (uint64_t) -1)
4051 return false;
4052
4053 /* Skip through the debug_abbrev section looking for that abbrev. */
4054 for (;;)
4055 {
4056 uint64_t this_abbrev = read_uleb128 (&da, enda);
4057 uint64_t attr;
4058
4059 if (this_abbrev == abbrev)
4060 /* This is almost always taken. */
4061 break;
4062 skip_leb128 (&da, enda); /* Skip the tag. */
4063 if (da == enda)
4064 return false;
4065 da++; /* Skip the DW_CHILDREN_* value. */
4066
4067 do {
4068 attr = read_uleb128 (&da, enda);
4069 skip_leb128 (&da, enda);
4070 } while (attr != 0 && attr != (uint64_t) -1);
4071 if (attr != 0)
4072 return false;
4073 }
4074
4075 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
4076 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
4077 return false;
4078 if (da == enda)
4079 return false;
4080 da++; /* Skip the DW_CHILDREN_* value. */
4081
4082 /* Now, go through the DIE looking for DW_AT_name,
4083 DW_AT_comp_dir, and DW_AT_stmt_list. */
4084 for (;;)
4085 {
4086 uint64_t attr = read_uleb128 (&da, enda);
4087 uint64_t form = read_uleb128 (&da, enda);
4088
4089 if (attr == (uint64_t) -1)
4090 return false;
4091 else if (attr == 0)
4092 return true;
4093
4094 if (form == DW_FORM_indirect)
4095 form = read_uleb128 (&di, end);
4096
55e3d2f6
A
4097 if (attr == DW_AT_name)
4098 *name = getDwarfString(form, di);
4099 else if (attr == DW_AT_comp_dir)
4100 *comp_dir = getDwarfString(form, di);
d696c285
A
4101 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
4102 *stmt_list = A::P::E::get32(*(uint32_t*)di);
4103 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
4104 *stmt_list = A::P::E::get64(*(uint64_t*)di);
4105 if (! skip_form (&di, end, form, address_size, dwarf64))
4106 return false;
4107 }
4108}
4109
4110template <typename A>
4111const char* Reader<A>::assureFullPath(const char* path)
4112{
4113 if ( path[0] == '/' )
4114 return path;
4115 char cwdbuff[MAXPATHLEN];
4116 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
4117 char* result;
4118 asprintf(&result, "%s/%s", cwdbuff, path);
4119 if ( result != NULL )
4120 return result;
4121 }
4122 return path;
4123}
4124
4125
4126//
4127//
4128// To implement architecture xxx, you must write template specializations for the following six methods:
4129// Reader<xxx>::validFile()
4130// Reader<xxx>::addRelocReference()
4131// Reference<xxx>::getDescription()
4132//
4133//
4134
4135
4136template <>
55e3d2f6 4137bool Reader<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
d696c285
A
4138{
4139 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4140 if ( header->magic() != MH_MAGIC )
4141 return false;
4142 if ( header->cputype() != CPU_TYPE_POWERPC )
4143 return false;
4144 if ( header->filetype() != MH_OBJECT )
4145 return false;
4146 return true;
4147}
4148
4149template <>
55e3d2f6 4150bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
d696c285
A
4151{
4152 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4153 if ( header->magic() != MH_MAGIC_64 )
4154 return false;
4155 if ( header->cputype() != CPU_TYPE_POWERPC64 )
4156 return false;
4157 if ( header->filetype() != MH_OBJECT )
4158 return false;
4159 return true;
4160}
4161
4162template <>
55e3d2f6 4163bool Reader<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
d696c285
A
4164{
4165 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4166 if ( header->magic() != MH_MAGIC )
4167 return false;
4168 if ( header->cputype() != CPU_TYPE_I386 )
4169 return false;
4170 if ( header->filetype() != MH_OBJECT )
4171 return false;
4172 return true;
4173}
4174
69a49097 4175template <>
55e3d2f6 4176bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
69a49097
A
4177{
4178 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4179 if ( header->magic() != MH_MAGIC_64 )
4180 return false;
4181 if ( header->cputype() != CPU_TYPE_X86_64 )
4182 return false;
4183 if ( header->filetype() != MH_OBJECT )
4184 return false;
4185 return true;
4186}
d696c285 4187
2f2f92e4 4188template <>
55e3d2f6 4189bool Reader<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
2f2f92e4
A
4190{
4191 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4192 if ( header->magic() != MH_MAGIC )
4193 return false;
4194 if ( header->cputype() != CPU_TYPE_ARM )
4195 return false;
4196 if ( header->filetype() != MH_OBJECT )
4197 return false;
55e3d2f6
A
4198 if ( subtypeMustMatch && ((cpu_subtype_t)header->cpusubtype() != subtype) )
4199 return false;
2f2f92e4
A
4200 return true;
4201}
d696c285 4202
c211e7c9
A
4203
4204template <>
4205const char* Reader<ppc>::fileKind(const uint8_t* fileContent)
4206{
4207 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4208 if ( header->magic() != MH_MAGIC )
4209 return NULL;
4210 if ( header->cputype() != CPU_TYPE_POWERPC )
4211 return NULL;
4212 switch ( header->cpusubtype() ) {
4213 case CPU_SUBTYPE_POWERPC_750:
4214 return "ppc750";
4215 case CPU_SUBTYPE_POWERPC_7400:
4216 return "ppc7400";
4217 case CPU_SUBTYPE_POWERPC_7450:
4218 return "ppc7450";
4219 case CPU_SUBTYPE_POWERPC_970:
4220 return "ppc970";
4221 case CPU_SUBTYPE_POWERPC_ALL:
4222 return "ppc";
4223 }
4224 return "ppc???";
4225}
4226
4227template <>
4228const char* Reader<ppc64>::fileKind(const uint8_t* fileContent)
4229{
4230 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4231 if ( header->magic() != MH_MAGIC )
4232 return NULL;
4233 if ( header->cputype() != CPU_TYPE_POWERPC64 )
4234 return NULL;
4235 return "ppc64";
4236}
4237
4238template <>
4239const char* Reader<x86>::fileKind(const uint8_t* fileContent)
4240{
4241 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4242 if ( header->magic() != MH_MAGIC )
4243 return NULL;
4244 if ( header->cputype() != CPU_TYPE_I386 )
4245 return NULL;
4246 return "i386";
4247}
4248
4249template <>
4250const char* Reader<x86_64>::fileKind(const uint8_t* fileContent)
4251{
4252 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4253 if ( header->magic() != MH_MAGIC )
4254 return NULL;
4255 if ( header->cputype() != CPU_TYPE_X86_64 )
4256 return NULL;
4257 return "x86_64";
4258}
4259
4260template <>
4261const char* Reader<arm>::fileKind(const uint8_t* fileContent)
4262{
4263 const macho_header<P>* header = (const macho_header<P>*)fileContent;
4264 if ( header->magic() != MH_MAGIC )
4265 return NULL;
4266 if ( header->cputype() != CPU_TYPE_ARM )
4267 return NULL;
4268 switch ( header->cpusubtype() ) {
4269 case CPU_SUBTYPE_ARM_V4T:
4270 return "armv4t";
4271 case CPU_SUBTYPE_ARM_V5TEJ:
4272 return "armv5";
4273 case CPU_SUBTYPE_ARM_V6:
4274 return "armv6";
4275 case CPU_SUBTYPE_ARM_V7:
4276 return "armv7";
4277 }
4278 return "arm???";
4279}
4280
4281
d696c285
A
4282template <typename A>
4283bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
4284{
4285 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
4286}
4287
4288template <>
4289bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
4290{
4291 return addRelocReference_powerpc(sect, reloc);
4292}
4293
4294template <>
4295bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
4296{
4297 return addRelocReference_powerpc(sect, reloc);
4298}
4299
4300
4301//
4302// ppc and ppc64 both use the same relocations, so process them in one common routine
4303//
4304template <typename A>
4305bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
4306 const macho_relocation_info<typename A::P>* reloc)
4307{
4308 uint32_t srcAddr;
4309 uint32_t dstAddr;
4310 uint32_t* fixUpPtr;
4311 int32_t displacement = 0;
4312 uint32_t instruction = 0;
4313 uint32_t offsetInTarget;
4314 int16_t lowBits;
4315 bool result = false;
4316 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4317 const macho_relocation_info<P>* nextReloc = &reloc[1];
4318 const char* targetName = NULL;
4319 bool weakImport = false;
4320 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4321 if ( reloc->r_type() != PPC_RELOC_PAIR )
4322 instruction = BigEndian::get32(*fixUpPtr);
4323 srcAddr = sect->addr() + reloc->r_address();
4324 if ( reloc->r_extern() ) {
4325 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
4326 targetName = &fStrings[targetSymbol->n_strx()];
4327 weakImport = this->isWeakImportSymbol(targetSymbol);
4328 }
4329 switch ( reloc->r_type() ) {
4330 case PPC_RELOC_BR24:
4331 {
4332 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4333 displacement = (instruction & 0x03FFFFFC);
4334 if ( (displacement & 0x02000000) != 0 )
4335 displacement |= 0xFC000000;
4336 }
4337 else {
4338 printf("bad instruction for BR24 reloc");
4339 }
4340 if ( reloc->r_extern() ) {
4341 offsetInTarget = srcAddr + displacement;
a61fdf0a
A
4342 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4343 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4344 addDtraceExtraInfos(srcAddr, &targetName[16]);
4345 }
4346 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4347 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4348 addDtraceExtraInfos(srcAddr, &targetName[20]);
4349 }
4350 else if ( weakImport )
d696c285
A
4351 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
4352 else
4353 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
4354 }
4355 else {
4356 dstAddr = srcAddr + displacement;
4357 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
4358 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
a61fdf0a
A
4359 targetName = atom->getName();
4360 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4361 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
4362 addDtraceExtraInfos(srcAddr, &targetName[16]);
4363 }
4364 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4365 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4366 addDtraceExtraInfos(srcAddr, &targetName[20]);
4367 }
4368 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
d696c285
A
4369 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
4370 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
4371 else
4372 makeReference(A::kBranch24, srcAddr, dstAddr);
4373 }
4374 }
4375 break;
4376 case PPC_RELOC_BR14:
4377 {
4378 displacement = (instruction & 0x0000FFFC);
4379 if ( (displacement & 0x00008000) != 0 )
4380 displacement |= 0xFFFF0000;
4381 if ( reloc->r_extern() ) {
4382 offsetInTarget = srcAddr + displacement;
4383 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
4384 }
4385 else {
4386 dstAddr = srcAddr + displacement;
4387 makeReference(A::kBranch14, srcAddr, dstAddr);
4388 }
4389 }
4390 break;
4391 case PPC_RELOC_PAIR:
4392 // skip, processed by a previous look ahead
4393 break;
4394 case PPC_RELOC_LO16:
4395 {
4396 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
55e3d2f6 4397 throw "PPC_RELOC_LO16 missing following pair";
d696c285
A
4398 }
4399 result = true;
4400 lowBits = (instruction & 0xFFFF);
4401 if ( reloc->r_extern() ) {
4402 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4403 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
4404 }
4405 else {
4406 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
a61fdf0a
A
4407 if ( reloc->r_symbolnum() == R_ABS ) {
4408 // find absolute symbol that corresponds to pointerValue
2f2f92e4 4409 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
4410 if ( pos != fAddrToAbsoluteAtom.end() )
4411 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
4412 else
4413 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4414 }
4415 else {
4416 makeReference(A::kAbsLow16, srcAddr, dstAddr);
4417 }
d696c285
A
4418 }
4419 }
4420 break;
4421 case PPC_RELOC_LO14:
4422 {
4423 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
55e3d2f6 4424 throw "PPC_RELOC_LO14 missing following pair";
d696c285
A
4425 }
4426 result = true;
4427 lowBits = (instruction & 0xFFFC);
4428 if ( reloc->r_extern() ) {
4429 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4430 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
4431 }
4432 else {
4433 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
a61fdf0a
A
4434 if ( reloc->r_symbolnum() == R_ABS ) {
4435 // find absolute symbol that corresponds to pointerValue
2f2f92e4 4436 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
4437 if ( pos != fAddrToAbsoluteAtom.end() )
4438 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
4439 else
4440 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4441 }
4442 else {
4443 makeReference(A::kAbsLow14, srcAddr, dstAddr);
4444 }
d696c285
A
4445 }
4446 }
4447 break;
4448 case PPC_RELOC_HI16:
4449 {
4450 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
55e3d2f6 4451 throw "PPC_RELOC_HI16 missing following pair";
d696c285
A
4452 }
4453 result = true;
4454 if ( reloc->r_extern() ) {
4455 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
4456 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
4457 }
4458 else {
4459 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
a61fdf0a
A
4460 if ( reloc->r_symbolnum() == R_ABS ) {
4461 // find absolute symbol that corresponds to pointerValue
2f2f92e4 4462 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
4463 if ( pos != fAddrToAbsoluteAtom.end() )
4464 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
4465 else
4466 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4467 }
4468 else {
4469 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
4470 }
d696c285
A
4471 }
4472 }
4473 break;
4474 case PPC_RELOC_HA16:
4475 {
4476 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
55e3d2f6 4477 throw "PPC_RELOC_HA16 missing following pair";
d696c285
A
4478 }
4479 result = true;
4480 lowBits = (nextReloc->r_address() & 0x0000FFFF);
4481 if ( reloc->r_extern() ) {
4482 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4483 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
4484 }
4485 else {
4486 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
a61fdf0a
A
4487 if ( reloc->r_symbolnum() == R_ABS ) {
4488 // find absolute symbol that corresponds to pointerValue
2f2f92e4 4489 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
4490 if ( pos != fAddrToAbsoluteAtom.end() )
4491 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
4492 else
4493 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4494 }
4495 else {
4496 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
4497 }
d696c285
A
4498 }
4499 }
4500 break;
4501 case PPC_RELOC_VANILLA:
4502 {
4503 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
4504 if ( reloc->r_extern() ) {
4505 if ( weakImport )
4506 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
4507 else
4508 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
4509 }
4510 else {
4be885f6 4511 new Reference<A>(A::kPointer, findAtomAndOffset(srcAddr), findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()));
d696c285
A
4512 }
4513 }
4514 break;
4515 case PPC_RELOC_JBSR:
a61fdf0a 4516 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
d696c285 4517 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
55e3d2f6 4518 throw "PPC_RELOC_JBSR missing following pair";
d696c285 4519 }
55e3d2f6
A
4520 if ( !fHasLongBranchStubs )
4521 warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath);
2f2f92e4 4522 fHasLongBranchStubs = true;
d696c285 4523 result = true;
55e3d2f6
A
4524 if ( reloc->r_extern() ) {
4525 throw "PPC_RELOC_JBSR should not be using an external relocation";
4526 }
d696c285 4527 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
a61fdf0a
A
4528 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4529 displacement = (instruction & 0x03FFFFFC);
4530 if ( (displacement & 0x02000000) != 0 )
4531 displacement |= 0xFC000000;
4532 }
4533 else {
4534 fprintf(stderr, "bad instruction for BR24 reloc");
4535 }
d696c285
A
4536 break;
4537 default:
2f2f92e4 4538 warning("unknown relocation type %d", reloc->r_type());
d696c285
A
4539 }
4540 }
4541 else {
4542 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4543 srcAddr = sect->addr() + sreloc->r_address();
4544 dstAddr = sreloc->r_value();
4545 uint32_t betterDstAddr;
4546 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4547 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4548 const macho_relocation_info<P>* nextReloc = &reloc[1];
4549 // file format allows pair to be scattered or not
4550 bool nextRelocIsPair = false;
4551 uint32_t nextRelocAddress = 0;
4552 uint32_t nextRelocValue = 0;
4553 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4554 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
4555 nextRelocIsPair = true;
4556 nextRelocAddress = nextReloc->r_address();
4557 result = true;
4558 }
4559 }
4560 else {
4561 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
4562 nextRelocIsPair = true;
4563 nextRelocAddress = nextSReloc->r_address();
4564 nextRelocValue = nextSReloc->r_value();
4565 result = true;
4566 }
4567 }
4568 switch (sreloc->r_type()) {
4569 case PPC_RELOC_VANILLA:
4570 {
4571 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
4572 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
4573 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4574 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
4575 }
4576 break;
4577 case PPC_RELOC_BR14:
4578 {
4579 instruction = BigEndian::get32(*fixUpPtr);
4580 displacement = (instruction & 0x0000FFFC);
4581 if ( (displacement & 0x00008000) != 0 )
4582 displacement |= 0xFFFF0000;
4583 betterDstAddr = srcAddr+displacement;
4584 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
4585 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
4586 }
4587 break;
4588 case PPC_RELOC_BR24:
4589 {
4590 instruction = BigEndian::get32(*fixUpPtr);
4591 if ( (instruction & 0x4C000000) == 0x48000000 ) {
4592 displacement = (instruction & 0x03FFFFFC);
4593 if ( (displacement & 0x02000000) != 0 )
4594 displacement |= 0xFC000000;
4595 betterDstAddr = srcAddr+displacement;
4596 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
4597 }
4598 }
4599 break;
4600 case PPC_RELOC_LO16_SECTDIFF:
4601 {
4602 if ( ! nextRelocIsPair ) {
55e3d2f6 4603 throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
d696c285
A
4604 }
4605 instruction = BigEndian::get32(*fixUpPtr);
4606 lowBits = (instruction & 0xFFFF);
4607 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
4608 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4609 }
4610 break;
4611 case PPC_RELOC_LO14_SECTDIFF:
4612 {
4613 if ( ! nextRelocIsPair ) {
55e3d2f6 4614 throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
d696c285
A
4615 }
4616 instruction = BigEndian::get32(*fixUpPtr);
4617 lowBits = (instruction & 0xFFFC);
4618 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
74cfe461 4619 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
d696c285
A
4620 }
4621 break;
4622 case PPC_RELOC_HA16_SECTDIFF:
4623 {
4624 if ( ! nextRelocIsPair ) {
55e3d2f6 4625 throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
d696c285
A
4626 }
4627 instruction = BigEndian::get32(*fixUpPtr);
4628 lowBits = (nextRelocAddress & 0x0000FFFF);
4629 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
4630 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
4631 }
4632 break;
4633 case PPC_RELOC_LO14:
4634 {
4635 if ( ! nextRelocIsPair ) {
55e3d2f6 4636 throw "PPC_RELOC_LO14 missing following pair";
d696c285
A
4637 }
4638 instruction = BigEndian::get32(*fixUpPtr);
4639 lowBits = (instruction & 0xFFFC);
4640 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4641 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
4642 }
4643 break;
4644 case PPC_RELOC_LO16:
4645 {
4646 if ( ! nextRelocIsPair ) {
55e3d2f6 4647 throw "PPC_RELOC_LO16 missing following pair";
d696c285
A
4648 }
4649 instruction = BigEndian::get32(*fixUpPtr);
4650 lowBits = (instruction & 0xFFFF);
4651 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
4652 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
4653 }
4654 break;
4655 case PPC_RELOC_HA16:
4656 {
4657 if ( ! nextRelocIsPair ) {
55e3d2f6 4658 throw "PPC_RELOC_HA16 missing following pair";
d696c285
A
4659 }
4660 instruction = BigEndian::get32(*fixUpPtr);
4661 lowBits = (nextRelocAddress & 0xFFFF);
4662 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
4663 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
4664 }
4665 break;
2f2f92e4
A
4666 case PPC_RELOC_HI16:
4667 {
4668 if ( ! nextRelocIsPair ) {
55e3d2f6 4669 throw "PPC_RELOC_HI16 missing following pair";
2f2f92e4
A
4670 }
4671 instruction = BigEndian::get32(*fixUpPtr);
4672 lowBits = (nextRelocAddress & 0xFFFF);
4673 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
4674 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
4675 }
4676 break;
d696c285
A
4677 case PPC_RELOC_SECTDIFF:
4678 case PPC_RELOC_LOCAL_SECTDIFF:
4679 {
4680 if ( ! nextRelocIsPair ) {
55e3d2f6 4681 throw "PPC_RELOC_SECTDIFF missing following pair";
d696c285 4682 }
2f2f92e4
A
4683 Kinds kind = A::kPointerDiff32;;
4684 uint32_t contentAddr = 0;
a61fdf0a
A
4685 switch ( sreloc->r_length() ) {
4686 case 0:
2f2f92e4 4687 throw "bad diff relocations r_length (0) for ppc architecture";
a61fdf0a 4688 case 1:
2f2f92e4
A
4689 kind = A::kPointerDiff16;
4690 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
a61fdf0a
A
4691 break;
4692 case 2:
2f2f92e4
A
4693 kind = A::kPointerDiff32;
4694 contentAddr = BigEndian::get32(*fixUpPtr);
a61fdf0a
A
4695 break;
4696 case 3:
2f2f92e4
A
4697 kind = A::kPointerDiff64;
4698 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
a61fdf0a
A
4699 break;
4700 }
2f2f92e4
A
4701 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4702 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4703 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4704 // check for addend encoded in the section content
4705 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4706 // dstAddr, nextRelocValue, contentAddr);
4707 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4708 if ( toao.atom == srcao.atom )
4709 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4710 else if ( fromao.atom == srcao.atom )
4711 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4712 else
4713 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4714 }
4715 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4716 // srcao.atom->getDisplayName(), srcao.offset,
4717 // fromao.atom->getDisplayName(), fromao.offset,
4718 // toao.atom->getDisplayName(), toao.offset);
4719 new Reference<A>(kind, srcao, fromao, toao);
d696c285
A
4720 }
4721 break;
4722 case PPC_RELOC_PAIR:
4723 break;
4724 case PPC_RELOC_HI16_SECTDIFF:
2f2f92e4 4725 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
d696c285
A
4726 break;
4727 default:
2f2f92e4 4728 warning("unknown scattered relocation type %d", sreloc->r_type());
d696c285
A
4729 }
4730 }
4731 return result;
4732}
4733
d696c285
A
4734
4735template <>
4736bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
4737{
4738 uint32_t srcAddr;
4739 uint32_t dstAddr;
4740 uint32_t* fixUpPtr;
4741 bool result = false;
4742 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
4743 srcAddr = sect->addr() + reloc->r_address();
4744 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
4745 switch ( reloc->r_type() ) {
4746 case GENERIC_RELOC_VANILLA:
4747 {
a61fdf0a 4748 x86::ReferenceKinds kind = x86::kPointer;
d696c285
A
4749 uint32_t pointerValue = E::get32(*fixUpPtr);
4750 if ( reloc->r_pcrel() ) {
a61fdf0a
A
4751 switch( reloc->r_length() ) {
4752 case 0:
2f2f92e4
A
4753 kind = x86::kPCRel8;
4754 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
4755 break;
a61fdf0a
A
4756 case 1:
4757 kind = x86::kPCRel16;
4758 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
4759 break;
4760 case 2:
4761 kind = x86::kPCRel32;
4762 pointerValue += srcAddr + sizeof(uint32_t);
4763 break;
2f2f92e4
A
4764 case 3:
4765 throw "bad pc-rel vanilla relocation length";
a61fdf0a 4766 }
d696c285 4767 }
69a49097
A
4768 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
4769 kind = x86::kAbsolute32;
a61fdf0a
A
4770 if ( reloc->r_length() != 2 )
4771 throw "bad vanilla relocation length";
69a49097 4772 }
d696c285
A
4773 else {
4774 kind = x86::kPointer;
a61fdf0a
A
4775 if ( reloc->r_length() != 2 )
4776 throw "bad vanilla relocation length";
d696c285
A
4777 }
4778 if ( reloc->r_extern() ) {
4779 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2f2f92e4
A
4780 if ( this->isWeakImportSymbol(targetSymbol) ) {
4781 if ( reloc->r_pcrel() )
4782 kind = x86::kPCRel32WeakImport;
4783 else
4784 kind = x86::kPointerWeakImport;
4785 }
d696c285 4786 const char* targetName = &fStrings[targetSymbol->n_strx()];
a61fdf0a
A
4787 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
4788 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4789 addDtraceExtraInfos(srcAddr, &targetName[16]);
4790 }
4791 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
4792 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4793 addDtraceExtraInfos(srcAddr, &targetName[20]);
4794 }
4795 else
4796 makeByNameReference(kind, srcAddr, targetName, pointerValue);
d696c285
A
4797 }
4798 else {
4be885f6
A
4799 AtomAndOffset targetAO = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
4800 const char* targetName = targetAO.atom->getName();
a61fdf0a
A
4801 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
4802 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
4803 addDtraceExtraInfos(srcAddr, &targetName[16]);
4804 }
4805 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
4806 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
4807 addDtraceExtraInfos(srcAddr, &targetName[20]);
4808 }
4be885f6
A
4809 // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol
4810 else if ( reloc->r_pcrel() && (targetAO.atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
4811 && ((AnonymousAtom<x86>*)targetAO.atom)->isWeakImportStub() )
4812 new Reference<x86>(x86::kPCRel32WeakImport, findAtomAndOffset(srcAddr), targetAO);
a61fdf0a 4813 else if ( reloc->r_symbolnum() != R_ABS )
4be885f6 4814 new Reference<x86>(kind, findAtomAndOffset(srcAddr), targetAO);
a61fdf0a
A
4815 else {
4816 // find absolute symbol that corresponds to pointerValue
2f2f92e4 4817 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
a61fdf0a
A
4818 if ( pos != fAddrToAbsoluteAtom.end() )
4819 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
4820 else
4821 throwf("R_ABS reloc but no absolute symbol at target address");
4822 }
d696c285
A
4823 }
4824 }
4825 break;
4826 default:
2f2f92e4 4827 warning("unknown relocation type %d", reloc->r_type());
d696c285
A
4828 }
4829 }
4830 else {
4831 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
4832 srcAddr = sect->addr() + sreloc->r_address();
4833 dstAddr = sreloc->r_value();
4834 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
4835 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
4836 const macho_relocation_info<P>* nextReloc = &reloc[1];
4837 pint_t betterDstAddr;
4838 // file format allows pair to be scattered or not
4839 bool nextRelocIsPair = false;
4840 uint32_t nextRelocAddress = 0;
4841 uint32_t nextRelocValue = 0;
2f2f92e4
A
4842 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
4843 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
d696c285
A
4844 nextRelocIsPair = true;
4845 nextRelocAddress = nextReloc->r_address();
4846 result = true;
4847 }
4848 }
4849 else {
2f2f92e4 4850 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
d696c285
A
4851 nextRelocIsPair = true;
4852 nextRelocAddress = nextSReloc->r_address();
4853 nextRelocValue = nextSReloc->r_value();
4854 }
4855 }
4856 switch (sreloc->r_type()) {
4857 case GENERIC_RELOC_VANILLA:
4858 betterDstAddr = LittleEndian::get32(*fixUpPtr);
4859 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
4860 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
4861 if ( sreloc->r_pcrel() ) {
55e3d2f6
A
4862 switch ( sreloc->r_length() ) {
4863 case 2:
4864 betterDstAddr += srcAddr + 4;
4865 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
4866 break;
4867 case 1:
4868 betterDstAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)) + srcAddr + 2;
4869 makeReferenceWithToBase(x86::kPCRel16, srcAddr, betterDstAddr, dstAddr);
4870 break;
4871 case 0:
4872 betterDstAddr = *((uint8_t*)fixUpPtr) + srcAddr + 1;
4873 makeReferenceWithToBase(x86::kPCRel8, srcAddr, betterDstAddr, dstAddr);
4874 break;
4875 case 3:
4876 throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc");
4877 break;
4878 }
d696c285
A
4879 }
4880 else {
55e3d2f6
A
4881 if ( sreloc->r_length() != 2 )
4882 throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
69a49097
A
4883 if ( strcmp(sect->segname(), "__TEXT") == 0 )
4884 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
4885 else
4886 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
d696c285
A
4887 }
4888 break;
4889 case GENERIC_RELOC_SECTDIFF:
4890 case GENERIC_RELOC_LOCAL_SECTDIFF:
4891 {
4892 if ( !nextRelocIsPair ) {
55e3d2f6 4893 throw "GENERIC_RELOC_SECTDIFF missing following pair";
d696c285 4894 }
a61fdf0a
A
4895 x86::ReferenceKinds kind = x86::kPointerDiff;
4896 uint32_t contentAddr = 0;
4897 switch ( sreloc->r_length() ) {
4898 case 0:
4899 case 3:
4900 throw "bad length for GENERIC_RELOC_SECTDIFF";
4901 case 1:
4902 kind = x86::kPointerDiff16;
4903 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
4904 break;
4905 case 2:
4906 kind = x86::kPointerDiff;
4907 contentAddr = LittleEndian::get32(*fixUpPtr);
4908 break;
4909 }
4910 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4911 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4912 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4913 // check for addend encoded in the section content
4914 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
4915 // dstAddr, nextRelocValue, contentAddr);
4916 if ( (dstAddr - nextRelocValue) != contentAddr ) {
4917 if ( toao.atom == srcao.atom )
4918 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4919 else if ( fromao.atom == srcao.atom )
4920 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
4921 else
4922 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
4923 }
4924 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
4925 // srcao.atom->getDisplayName(), srcao.offset,
4926 // fromao.atom->getDisplayName(), fromao.offset,
4927 // toao.atom->getDisplayName(), toao.offset);
4928 new Reference<x86>(kind, srcao, fromao, toao);
d696c285
A
4929 }
4930 break;
4931 case GENERIC_RELOC_PAIR:
4932 // do nothing, already used via a look ahead
4933 break;
4934 default:
2f2f92e4 4935 warning("unknown scattered relocation type %d", sreloc->r_type());
d696c285
A
4936 }
4937 }
4938 return result;
4939}
4940
69a49097
A
4941template <>
4942bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
4943{
4944 uint64_t srcAddr;
4945 uint64_t dstAddr = 0;
4946 uint64_t addend;
4947 uint32_t* fixUpPtr;
74cfe461 4948 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
69a49097
A
4949 bool result = false;
4950 const macho_nlist<P>* targetSymbol = NULL;
4951 const char* targetName = NULL;
4952 srcAddr = sect->addr() + reloc->r_address();
4953 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
55e3d2f6 4954 //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address());
69a49097
A
4955 if ( reloc->r_extern() ) {
4956 targetSymbol = &fSymbols[reloc->r_symbolnum()];
4957 targetName = &fStrings[targetSymbol->n_strx()];
4958 }
4959 switch ( reloc->r_type() ) {
4960 case X86_64_RELOC_UNSIGNED:
4961 if ( reloc->r_pcrel() )
4962 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
55e3d2f6
A
4963 switch ( reloc->r_length() ) {
4964 case 0:
4965 case 1:
4966 throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
4967 case 2:
4968 kind = x86_64::kPointer32;
4969 break;
4970 case 3:
fb24a050
A
4971 if ( reloc->r_extern() && isWeakImportSymbol(targetSymbol) )
4972 kind = x86_64::kPointerWeakImport;
4973 else
4974 kind = x86_64::kPointer;
55e3d2f6
A
4975 break;
4976 }
69a49097 4977 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
a61fdf0a 4978 if ( reloc->r_extern() ) {
55e3d2f6 4979 makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
a61fdf0a
A
4980 }
4981 else {
55e3d2f6 4982 makeReference(kind, srcAddr, dstAddr);
a61fdf0a
A
4983 // verify that dstAddr is in the section being targeted
4984 int sectNum = reloc->r_symbolnum();
4985 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
4986 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
4987 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
4988 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
4989 srcAddr, sect->sectname(), targetSection->sectname());
4990 }
4991 }
69a49097
A
4992 break;
4993 case X86_64_RELOC_SIGNED:
86b84c30
A
4994 case X86_64_RELOC_SIGNED_1:
4995 case X86_64_RELOC_SIGNED_2:
4996 case X86_64_RELOC_SIGNED_4:
69a49097 4997 if ( ! reloc->r_pcrel() )
74cfe461 4998 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
69a49097 4999 if ( reloc->r_length() != 2 )
74cfe461
A
5000 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
5001 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5002 if ( reloc->r_extern() ) {
5003 switch ( reloc->r_type() ) {
5004 case X86_64_RELOC_SIGNED:
5005 kind = x86_64::kPCRel32;
5006 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
5007 if ( addend == (uint64_t)(-1) ) {
5008 addend = 0;
86b84c30 5009 kind = x86_64::kPCRel32_1;
86b84c30 5010 }
74cfe461
A
5011 else if ( addend == (uint64_t)(-2) ) {
5012 addend = 0;
86b84c30 5013 kind = x86_64::kPCRel32_2;
86b84c30 5014 }
74cfe461
A
5015 else if ( addend == (uint64_t)(-4) ) {
5016 addend = 0;
86b84c30 5017 kind = x86_64::kPCRel32_4;
86b84c30 5018 }
74cfe461
A
5019 break;
5020 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
5021 case X86_64_RELOC_SIGNED_1:
5022 kind = x86_64::kPCRel32_1;
5023 addend += 1;
5024 break;
5025 case X86_64_RELOC_SIGNED_2:
5026 kind = x86_64::kPCRel32_2;
5027 addend += 2;
5028 break;
5029 case X86_64_RELOC_SIGNED_4:
5030 kind = x86_64::kPCRel32_4;
5031 addend += 4;
5032 break;
5033 }
5034 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
69a49097 5035 }
69a49097 5036 else {
74cfe461
A
5037 uint64_t ripRelativeOffset = addend;
5038 switch ( reloc->r_type() ) {
5039 case X86_64_RELOC_SIGNED:
5040 dstAddr = srcAddr + 4 + ripRelativeOffset;
5041 kind = x86_64::kPCRel32;
5042 break;
5043 case X86_64_RELOC_SIGNED_1:
5044 dstAddr = srcAddr + 5 + ripRelativeOffset;
5045 kind = x86_64::kPCRel32_1;
5046 break;
5047 case X86_64_RELOC_SIGNED_2:
5048 dstAddr = srcAddr + 6 + ripRelativeOffset;
5049 kind = x86_64::kPCRel32_2;
5050 break;
5051 case X86_64_RELOC_SIGNED_4:
5052 dstAddr = srcAddr + 8 + ripRelativeOffset;
5053 kind = x86_64::kPCRel32_4;
5054 break;
5055 }
5056 makeReference(kind, srcAddr, dstAddr);
a61fdf0a
A
5057 // verify that dstAddr is in the section being targeted
5058 int sectNum = reloc->r_symbolnum();
5059 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
5060 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
5061 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
5062 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
5063 srcAddr, sect->sectname(), targetSection->sectname());
5064 }
74cfe461 5065 }
69a49097
A
5066 break;
5067 case X86_64_RELOC_BRANCH:
5068 if ( ! reloc->r_pcrel() )
5069 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
2f2f92e4
A
5070 if ( reloc->r_length() == 2 ) {
5071 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5072 if ( reloc->r_extern() ) {
5073 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5074 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
5075 addDtraceExtraInfos(srcAddr, &targetName[16]);
5076 }
5077 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5078 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5079 addDtraceExtraInfos(srcAddr, &targetName[16]);
5080 }
5081 else if ( isWeakImportSymbol(targetSymbol) )
5082 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
5083 else
5084 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
a61fdf0a 5085 }
2f2f92e4
A
5086 else {
5087 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
5088 }
5089 }
5090 else if ( reloc->r_length() == 0 ) {
5091 dstAddr = *((int8_t*)fixUpPtr);
5092 if ( reloc->r_extern() ) {
5093 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
5094 }
5095 else {
5096 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
a61fdf0a 5097 }
69a49097
A
5098 }
5099 else {
2f2f92e4 5100 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
69a49097
A
5101 }
5102 break;
5103 case X86_64_RELOC_GOT:
5104 if ( ! reloc->r_extern() )
5105 throw "not extern and X86_64_RELOC_GOT not supported";
5106 if ( ! reloc->r_pcrel() )
5107 throw "not pcrel and X86_64_RELOC_GOT not supported";
5108 if ( reloc->r_length() != 2 )
5109 throw "length != 2 and X86_64_RELOC_GOT not supported";
5110 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5111 if ( isWeakImportSymbol(targetSymbol) )
5112 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
5113 else
5114 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
5115 break;
5116 case X86_64_RELOC_GOT_LOAD:
5117 if ( ! reloc->r_extern() )
5118 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
5119 if ( ! reloc->r_pcrel() )
5120 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
5121 if ( reloc->r_length() != 2 )
5122 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
5123 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
5124 if ( isWeakImportSymbol(targetSymbol) )
5125 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
5126 else
5127 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
5128 break;
5129 case X86_64_RELOC_SUBTRACTOR:
a61fdf0a 5130 {
69a49097
A
5131 if ( reloc->r_pcrel() )
5132 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
5133 if ( reloc->r_length() < 2 )
5134 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
5135 if ( !reloc->r_extern() )
5136 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
5137 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
5138 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
5139 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
5140 result = true;
5141 if ( nextReloc->r_pcrel() )
5142 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
5143 if ( nextReloc->r_length() != reloc->r_length() )
5144 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
5145 Reference<x86_64>* ref;
5146 bool negativeAddend;
5147 if ( reloc->r_length() == 2 ) {
5148 kind = x86_64::kPointerDiff32;
5149 dstAddr = E::get32(*fixUpPtr); // addend is in content
5150 negativeAddend = ((dstAddr & 0x80000000) != 0);
5151 }
5152 else {
5153 kind = x86_64::kPointerDiff;
5154 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
5155 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
5156 }
55e3d2f6
A
5157 AtomAndOffset inAtomAndOffset = this->findAtomAndOffset(srcAddr);
5158 ObjectFile::Atom* inAtom = inAtomAndOffset.atom;
69a49097
A
5159 // create reference with "to" target
5160 if ( nextReloc->r_extern() ) {
5161 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
5162 const char* targetName = &fStrings[targetSymbol->n_strx()];
5163 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
5164 // if "to" is in this atom, change by-name to a direct reference
5165 if ( strcmp(targetName, inAtom->getName()) == 0 )
5166 ref->setTarget(*inAtom, 0);
5167 }
5168 else {
5169 ref = makeReference(kind, srcAddr, dstAddr);
5170 }
5171 // add in "from" target
5172 if ( reloc->r_extern() ) {
5173 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
5174 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
5175 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
5176 // from target is translation unit scoped, so use a direct reference
5177 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
5178 }
5179 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
5180 // if "from" is in this atom, change by-name to a direct reference
5181 ref->setFromTarget(*inAtom);
5182 }
5183 else {
5184 // some non-static other atom
5185 ref->setFromTargetName(fromTargetName);
5186 }
5187 }
55e3d2f6
A
5188 else {
5189 throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0";
5190 }
69a49097
A
5191 // addend goes in from side iff negative
5192 if ( negativeAddend )
5193 ref->setFromTargetOffset(-dstAddr);
5194 else
5195 ref->setToTargetOffset(dstAddr);
5196 break;
a61fdf0a 5197 }
69a49097 5198 default:
2f2f92e4 5199 warning("unknown relocation type %d", reloc->r_type());
69a49097
A
5200 }
5201 return result;
5202}
d696c285
A
5203
5204
2f2f92e4
A
5205/// Reader<arm>::addRelocReference -
5206/// turns arm relocation entries into references. Returns true if the next
5207/// relocation should be skipped, false otherwise.
5208template <>
5209bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
5210 const macho_relocation_info<arm::P>* reloc)
5211{
5212 uint32_t * fixUpPtr;
5213 int32_t displacement;
5214 uint32_t instruction = 0;
5215 bool result = false;
5216 uint32_t srcAddr;
5217 uint32_t dstAddr;
5218 uint32_t pointerValue;
55e3d2f6 5219 arm::ReferenceKinds kind = arm::kNoFixUp;
2f2f92e4
A
5220
5221 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
5222 // non-scattered relocation
5223 const char* targetName = NULL;
5224 bool weakImport = false;
5225
5226 srcAddr = sect->addr() + reloc->r_address();
5227 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
5228 if ( reloc->r_type() != ARM_RELOC_PAIR )
5229 instruction = LittleEndian::get32(*fixUpPtr);
5230
5231 if ( reloc->r_extern() ) {
5232 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
5233 targetName = &fStrings[targetSymbol->n_strx()];
5234 weakImport = this->isWeakImportSymbol(targetSymbol);
5235 }
5236
5237 switch ( reloc->r_type() ) {
5238 case ARM_RELOC_BR24:
5239 // Sign-extend displacement
5240 displacement = (instruction & 0x00FFFFFF) << 2;
5241 if ( (displacement & 0x02000000) != 0 )
5242 displacement |= 0xFC000000;
5243 // The pc added will be +8 from the pc
5244 displacement += 8;
5245 // If this is BLX add H << 1
5246 if ((instruction & 0xFE000000) == 0xFA000000)
5247 displacement += ((instruction & 0x01000000) >> 23);
5248
5249 if ( reloc->r_extern() ) {
5250 uint32_t offsetInTarget = srcAddr + displacement;
5251 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5252 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5253 addDtraceExtraInfos(srcAddr, &targetName[16]);
5254 }
5255 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5256 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5257 addDtraceExtraInfos(srcAddr, &targetName[20]);
5258 }
5259 else if ( weakImport )
5260 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
5261 else
5262 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
5263 }
5264 else {
5265 dstAddr = srcAddr + displacement;
5266 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5267 // check for dtrace probes and weak_import stubs
5268 const char* targetName = atom->getName();
5269 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5270 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5271 addDtraceExtraInfos(srcAddr, &targetName[16]);
5272 }
5273 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5274 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5275 addDtraceExtraInfos(srcAddr, &targetName[20]);
5276 }
5277 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5278 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5279 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
5280 else if ( reloc->r_symbolnum() != R_ABS )
5281 makeReference(arm::kBranch24, srcAddr, dstAddr);
5282 else {
5283 // find absolute symbol that corresponds to pointerValue
5284 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5285 if ( pos != fAddrToAbsoluteAtom.end() )
5286 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
5287 else
5288 throwf("R_ABS reloc but no absolute symbol at target address");
5289 }
5290 }
5291 break;
5292
5293 case ARM_THUMB_RELOC_BR22:
55e3d2f6
A
5294 // thumb2 added two more bits to displacement, complicating the displacement decoding
5295 {
5296 uint32_t s = (instruction >> 10) & 0x1;
5297 uint32_t j1 = (instruction >> 29) & 0x1;
5298 uint32_t j2 = (instruction >> 27) & 0x1;
5299 uint32_t imm10 = instruction & 0x3FF;
5300 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5301 uint32_t i1 = (j1 == s);
5302 uint32_t i2 = (j2 == s);
5303 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5304 int32_t sdis = dis;
5305 if ( s )
5306 sdis |= 0xFE000000;
5307 displacement = sdis;
5308 }
2f2f92e4
A
5309 // The pc added will be +4 from the pc
5310 displacement += 4;
5311 // If the instruction was blx, force the low 2 bits to be clear
5312 dstAddr = srcAddr + displacement;
5313 if ((instruction & 0xF8000000) == 0xE8000000)
5314 dstAddr &= 0xFFFFFFFC;
5315
5316 if ( reloc->r_extern() ) {
5317 uint32_t offsetInTarget = dstAddr;
5318 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
5319 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5320 addDtraceExtraInfos(srcAddr, &targetName[16]);
5321 }
5322 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
5323 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5324 addDtraceExtraInfos(srcAddr, &targetName[20]);
5325 }
5326 else if ( weakImport )
5327 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
5328 else
5329 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
5330 }
5331 else {
5332 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
5333 // check for dtrace probes and weak_import stubs
5334 const char* targetName = atom->getName();
5335 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
5336 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
5337 addDtraceExtraInfos(srcAddr, &targetName[16]);
5338 }
5339 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
5340 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
5341 addDtraceExtraInfos(srcAddr, &targetName[20]);
5342 }
5343 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
5344 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
5345 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
5346 else if ( reloc->r_symbolnum() != R_ABS )
5347 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
5348 else {
5349 // find absolute symbol that corresponds to pointerValue
5350 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
5351 if ( pos != fAddrToAbsoluteAtom.end() )
5352 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
5353 else
5354 throwf("R_ABS reloc but no absolute symbol at target address");
5355 }
5356 }
5357 break;
5358
5359 case ARM_RELOC_VANILLA:
5360 if ( reloc->r_length() != 2 )
5361 throw "bad length for ARM_RELOC_VANILLA";
5362
5363 pointerValue = instruction;
55e3d2f6
A
5364 kind = arm::kPointer;
5365 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5366 kind = arm::kReadOnlyPointer;
5367 if ( weakImport )
5368 kind = arm::kPointerWeakImport;
2f2f92e4 5369 if ( reloc->r_extern() ) {
d9246299
A
5370 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
5371 if ( (targetSymbol->n_desc() & N_ARM_THUMB_DEF) && (pointerValue == 1) )
5372 pointerValue = 0;
55e3d2f6 5373 makeByNameReference(kind, srcAddr, targetName, pointerValue);
2f2f92e4
A
5374 }
5375 else {
55e3d2f6 5376 AtomAndOffset at = findAtomAndOffset(srcAddr);
4be885f6 5377 AtomAndOffset to = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
55e3d2f6
A
5378 if ( to.atom->isThumb() )
5379 to.offset &= -2;
5380 new Reference<arm>(kind, at, to);
2f2f92e4
A
5381 }
5382 break;
5383
55e3d2f6 5384 case ARM_THUMB_32BIT_BRANCH:
fb24a050 5385 // ignore old unnecessary relocs
55e3d2f6
A
5386 break;
5387
2f2f92e4
A
5388 default:
5389 warning("unexpected relocation type %u", reloc->r_type());
5390 break;
5391 }
5392 }
5393 else {
5394 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
5395 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
d9246299 5396 int32_t addend;
2f2f92e4
A
5397 srcAddr = sect->addr() + sreloc->r_address();
5398 dstAddr = sreloc->r_value();
5399 uint32_t betterDstAddr;
5400 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
5401 instruction = LittleEndian::get32(*fixUpPtr);
5402
5403 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
5404 // relocation types, and it is an error to see one otherwise.
5405 bool nextRelocIsPair = false;
5406 uint32_t nextRelocAddress = 0;
5407 uint32_t nextRelocValue = 0;
5408 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
5409 nextRelocIsPair = true;
5410 nextRelocAddress = nextSReloc->r_address();
5411 nextRelocValue = nextSReloc->r_value();
5412 result = true;
5413 }
5414
5415 switch (sreloc->r_type()) {
5416 case ARM_RELOC_VANILLA:
5417 if ( sreloc->r_length() != 2 )
5418 throw "bad length for ARM_RELOC_VANILLA";
5419
2f2f92e4 5420 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
55e3d2f6
A
5421 betterDstAddr = LittleEndian::get32(*fixUpPtr);
5422 kind = arm::kPointer;
5423 if ( strcmp(sect->segname(), "__TEXT") == 0 )
5424 kind = arm::kReadOnlyPointer;
2f2f92e4 5425 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
55e3d2f6 5426 makeReferenceWithToBase(kind, srcAddr, betterDstAddr, dstAddr);
2f2f92e4
A
5427 break;
5428
5429 case ARM_RELOC_BR24:
5430 // Sign-extend displacement
5431 displacement = (instruction & 0x00FFFFFF) << 2;
5432 if ( (displacement & 0x02000000) != 0 )
5433 displacement |= 0xFC000000;
5434 // The pc added will be +8 from the pc
5435 displacement += 8;
5436 // If this is BLX add H << 1
5437 if ((instruction & 0xFE000000) == 0xFA000000)
5438 displacement += ((instruction & 0x01000000) >> 23);
5439 betterDstAddr = srcAddr+displacement;
5440 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
5441 break;
5442
5443 case ARM_THUMB_RELOC_BR22:
55e3d2f6
A
5444 // thumb2 added two more bits to displacement, complicating the displacement decoding
5445 {
5446 uint32_t s = (instruction >> 10) & 0x1;
5447 uint32_t j1 = (instruction >> 29) & 0x1;
5448 uint32_t j2 = (instruction >> 27) & 0x1;
5449 uint32_t imm10 = instruction & 0x3FF;
5450 uint32_t imm11 = (instruction >> 16) & 0x7FF;
5451 uint32_t i1 = (j1 == s);
5452 uint32_t i2 = (j2 == s);
5453 uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
5454 int32_t sdis = dis;
5455 if ( s )
5456 sdis |= 0xFE000000;
5457 displacement = sdis;
5458 }
2f2f92e4
A
5459 // The pc added will be +4 from the pc
5460 displacement += 4;
5461 betterDstAddr = srcAddr+displacement;
5462 // If the instruction was blx, force the low 2 bits to be clear
5463 if ((instruction & 0xF8000000) == 0xE8000000)
5464 betterDstAddr &= 0xFFFFFFFC;
5465 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
5466 break;
5467
5468 case ARM_RELOC_SECTDIFF:
5469 case ARM_RELOC_LOCAL_SECTDIFF:
5470 if ( !nextRelocIsPair ) {
55e3d2f6 5471 throw "ARM_RELOC_SECTDIFF missing following pair";
2f2f92e4
A
5472 }
5473 if ( sreloc->r_length() != 2 )
5474 throw "bad length for ARM_RELOC_SECTDIFF";
5475 {
5476 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
5477 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
5478 AtomAndOffset toao = findAtomAndOffset(dstAddr);
5479 // check for addend encoded in the section content
5480 pointerValue = LittleEndian::get32(*fixUpPtr);
d9246299
A
5481 addend = pointerValue - (dstAddr - nextRelocValue);
5482 if ( toao.atom->isThumb() && (addend & 1) )
5483 addend &= -2; // remove thumb bit
2f2f92e4 5484 if ( (dstAddr - nextRelocValue) != pointerValue ) {
d9246299
A
5485 if ( fromao.atom == srcao.atom ) {
5486 if ( ((const macho_section<P>*)(((BaseAtom*)(srcao.atom))->getSectionRecord()))->flags() & S_ATTR_PURE_INSTRUCTIONS ) {
5487 int pcBaseOffset = srcao.atom->isThumb() ? 4 : 8;
5488 if ( addend == -pcBaseOffset ) {
5489 fromao.offset -= addend;
5490 }
5491 else {
5492 toao.offset += addend;
5493 }
5494 }
5495 else {
5496 toao.offset += addend;
5497 }
5498 }
5499 else if ( toao.atom == srcao.atom )
5500 toao.offset += addend;
2f2f92e4 5501 else
d9246299 5502 fromao.offset -= addend;
2f2f92e4
A
5503 }
5504 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
5505 }
5506 break;
5507
5508 default:
5509 warning("unexpected srelocation type %u", sreloc->r_type());
5510 break;
5511 }
5512 }
5513 return result;
5514}
5515
a61fdf0a
A
5516template <typename A>
5517void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
5518{
5519 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
5520 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
5521 switch ( sect->flags() & SECTION_TYPE ) {
5522 case S_SYMBOL_STUBS:
5523 case S_LAZY_SYMBOL_POINTERS:
5524 // we ignore compiler generated stubs, so ignore those relocs too
5525 break;
5526 default:
55e3d2f6
A
5527 // ignore all relocations in __eh_frame section
5528 if ( sect == fehFrameSection )
5529 return;
a61fdf0a
A
5530 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
5531 const uint32_t relocCount = sect->nreloc();
5532 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
5533 for (uint32_t r = 0; r < relocCount; ++r) {
5534 try {
5535 if ( addRelocReference(sect, &relocs[r]) )
5536 ++r; // skip next
5537 }
5538 catch (const char* msg) {
2f2f92e4 5539 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
a61fdf0a
A
5540 }
5541 }
5542 }
5543 }
5544}
5545
5546
d696c285
A
5547template <>
5548const char* Reference<x86>::getDescription() const
5549{
69a49097 5550 static char temp[2048];
d696c285
A
5551 switch( fKind ) {
5552 case x86::kNoFixUp:
5553 sprintf(temp, "reference to ");
5554 break;
5555 case x86::kFollowOn:
5556 sprintf(temp, "followed by ");
5557 break;
2f2f92e4
A
5558 case x86::kGroupSubordinate:
5559 sprintf(temp, "group subordinate ");
5560 break;
d696c285
A
5561 case x86::kPointerWeakImport:
5562 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5563 break;
5564 case x86::kPointer:
5565 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5566 break;
5567 case x86::kPointerDiff:
5568 {
5569 // by-name references have quoted names
5570 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5571 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5572 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
55e3d2f6
A
5573 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5574 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
d696c285
A
5575 return temp;
5576 }
5577 break;
a61fdf0a
A
5578 case x86::kPointerDiff16:
5579 {
5580 // by-name references have quoted names
5581 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5582 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5583 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
55e3d2f6
A
5584 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5585 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
a61fdf0a
A
5586 return temp;
5587 }
5588 break;
d696c285
A
5589 case x86::kPCRel32WeakImport:
5590 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
5591 break;
5592 case x86::kPCRel32:
5593 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
5594 break;
a61fdf0a
A
5595 case x86::kPCRel16:
5596 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
5597 break;
2f2f92e4
A
5598 case x86::kPCRel8:
5599 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
5600 break;
69a49097
A
5601 case x86::kAbsolute32:
5602 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
5603 break;
55e3d2f6 5604 case x86::kImageOffset32:
fb24a050 5605 sprintf(temp, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc);
55e3d2f6
A
5606 break;
5607 case x86::kPointerDiff24:
5608 sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5609 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5610 this->getFromTargetDisplayName(), fFromTarget.offset );
5611 return temp;
5612 break;
fb24a050
A
5613 case x86::kSectionOffset24:
5614 sprintf(temp, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc);
5615 break;
a61fdf0a
A
5616 case x86::kDtraceProbe:
5617 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5618 break;
5619 case x86::kDtraceProbeSite:
5620 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5621 break;
5622 case x86::kDtraceIsEnabledSite:
5623 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5624 break;
5625 case x86::kDtraceTypeReference:
5626 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
5627 break;
d696c285
A
5628 }
5629 // always quote by-name references
5630 if ( fToTargetName != NULL ) {
5631 strcat(temp, "\"");
5632 strcat(temp, fToTargetName);
5633 strcat(temp, "\"");
5634 }
5635 else if ( fToTarget.atom != NULL ) {
5636 strcat(temp, fToTarget.atom->getDisplayName());
5637 }
5638 else {
5639 strcat(temp, "NULL target");
5640 }
5641 if ( fToTarget.offset != 0 )
5642 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5643
5644 return temp;
5645}
5646
5647
5648template <>
5649const char* Reference<ppc>::getDescription() const
5650{
69a49097 5651 static char temp[2048];
d696c285
A
5652 switch( fKind ) {
5653 case ppc::kNoFixUp:
5654 sprintf(temp, "reference to ");
5655 break;
5656 case ppc::kFollowOn:
5657 sprintf(temp, "followed by ");
5658 break;
2f2f92e4
A
5659 case ppc::kGroupSubordinate:
5660 sprintf(temp, "group subordinate ");
5661 break;
d696c285
A
5662 case ppc::kPointerWeakImport:
5663 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5664 break;
5665 case ppc::kPointer:
5666 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5667 break;
a61fdf0a
A
5668 case ppc::kPointerDiff16:
5669 {
5670 // by-name references have quoted names
5671 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5672 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5673 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
55e3d2f6
A
5674 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5675 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
a61fdf0a
A
5676 return temp;
5677 }
d696c285
A
5678 case ppc::kPointerDiff32:
5679 {
5680 // by-name references have quoted names
5681 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5682 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5683 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
55e3d2f6
A
5684 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5685 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
d696c285
A
5686 return temp;
5687 }
5688 case ppc::kPointerDiff64:
5689 throw "unsupported refrence kind";
5690 break;
5691 case ppc::kBranch24WeakImport:
5692 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5693 break;
5694 case ppc::kBranch24:
5695 case ppc::kBranch14:
5696 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5697 break;
5698 case ppc::kPICBaseLow16:
a61fdf0a 5699 sprintf(temp, "offset 0x%04X, low 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
d696c285
A
5700 break;
5701 case ppc::kPICBaseLow14:
a61fdf0a 5702 sprintf(temp, "offset 0x%04X, low 14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
d696c285
A
5703 break;
5704 case ppc::kPICBaseHigh16:
a61fdf0a 5705 sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
d696c285
A
5706 break;
5707 case ppc::kAbsLow16:
5708 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5709 break;
5710 case ppc::kAbsLow14:
5711 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5712 break;
5713 case ppc::kAbsHigh16:
a61fdf0a 5714 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
d696c285
A
5715 break;
5716 case ppc::kAbsHigh16AddLow:
a61fdf0a
A
5717 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5718 break;
5719 case ppc::kDtraceProbe:
5720 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
5721 break;
5722 case ppc::kDtraceProbeSite:
5723 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
5724 break;
5725 case ppc::kDtraceIsEnabledSite:
5726 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5727 break;
5728 case ppc::kDtraceTypeReference:
5729 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
d696c285
A
5730 break;
5731 }
5732 // always quote by-name references
5733 if ( fToTargetName != NULL ) {
5734 strcat(temp, "\"");
5735 strcat(temp, fToTargetName);
5736 strcat(temp, "\"");
5737 }
5738 else if ( fToTarget.atom != NULL ) {
5739 strcat(temp, fToTarget.atom->getDisplayName());
5740 }
5741 else {
5742 strcat(temp, "NULL target");
5743 }
5744 if ( fToTarget.offset != 0 )
5745 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
5746
5747 return temp;
5748}
5749
5750template <>
5751const char* Reference<ppc64>::getDescription() const
5752{
69a49097 5753 static char temp[2048];
d696c285
A
5754 switch( fKind ) {
5755 case ppc64::kNoFixUp:
5756 sprintf(temp, "reference to ");
5757 break;
5758 case ppc64::kFollowOn:
5759 sprintf(temp, "followed by ");
5760 break;
2f2f92e4
A
5761 case ppc64::kGroupSubordinate:
5762 sprintf(temp, "group subordinate ");
5763 break;
d696c285
A
5764 case ppc64::kPointerWeakImport:
5765 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5766 break;
5767 case ppc64::kPointer:
5768 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5769 break;
5770 case ppc64::kPointerDiff64:
5771 {
5772 // by-name references have quoted names
5773 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5774 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5775 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
55e3d2f6
A
5776 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5777 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
d696c285
A
5778 return temp;
5779 }
5780 case ppc64::kPointerDiff32:
5781 {
5782 // by-name references have quoted names
5783 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5784 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5785 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
55e3d2f6
A
5786 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5787 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
d696c285
A
5788 return temp;
5789 }
a61fdf0a
A
5790 case ppc64::kPointerDiff16:
5791 {
5792 // by-name references have quoted names
5793 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5794 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5795 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
55e3d2f6
A
5796 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5797 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
a61fdf0a
A
5798 return temp;
5799 }
d696c285
A
5800 case ppc64::kBranch24WeakImport:
5801 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
5802 break;
5803 case ppc64::kBranch24:
5804 case ppc64::kBranch14:
5805 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
5806 break;
5807 case ppc64::kPICBaseLow16:
5808 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5809 break;
5810 case ppc64::kPICBaseLow14:
5811 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5812 break;
5813 case ppc64::kPICBaseHigh16:
5814 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
5815 break;
5816 case ppc64::kAbsLow16:
5817 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
5818 break;
5819 case ppc64::kAbsLow14:
5820 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
5821 break;
5822 case ppc64::kAbsHigh16:
a61fdf0a 5823 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
d696c285
A
5824 break;
5825 case ppc64::kAbsHigh16AddLow:
a61fdf0a
A
5826 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
5827 break;
5828 case ppc64::kDtraceProbe:
5829 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5830 break;
5831 case ppc64::kDtraceProbeSite:
5832 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5833 break;
5834 case ppc64::kDtraceIsEnabledSite:
5835 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5836 break;
5837 case ppc64::kDtraceTypeReference:
5838 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
d696c285
A
5839 break;
5840 }
5841 // always quote by-name references
5842 if ( fToTargetName != NULL ) {
5843 strcat(temp, "\"");
5844 strcat(temp, fToTargetName);
5845 strcat(temp, "\"");
5846 }
5847 else if ( fToTarget.atom != NULL ) {
5848 strcat(temp, fToTarget.atom->getDisplayName());
5849 }
5850 else {
5851 strcat(temp, "NULL target");
5852 }
5853 if ( fToTarget.offset != 0 )
69a49097 5854 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
d696c285
A
5855
5856 return temp;
5857}
5858
5859
69a49097
A
5860template <>
5861const char* Reference<x86_64>::getDescription() const
5862{
5863 static char temp[2048];
5864 switch( fKind ) {
5865 case x86_64::kNoFixUp:
5866 sprintf(temp, "reference to ");
5867 break;
5868 case x86_64::kFollowOn:
5869 sprintf(temp, "followed by ");
5870 break;
2f2f92e4
A
5871 case x86_64::kGroupSubordinate:
5872 sprintf(temp, "group subordinate ");
5873 break;
69a49097
A
5874 case x86_64::kPointerWeakImport:
5875 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
5876 break;
5877 case x86_64::kPointer:
5878 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
5879 break;
55e3d2f6
A
5880 case x86_64::kPointer32:
5881 sprintf(temp, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc);
5882 break;
69a49097
A
5883 case x86_64::kPointerDiff32:
5884 case x86_64::kPointerDiff:
5885 {
5886 // by-name references have quoted names
5887 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5888 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
5889 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
5890 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
55e3d2f6
A
5891 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
5892 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
69a49097
A
5893 return temp;
5894 }
5895 break;
5896 case x86_64::kPCRel32:
5897 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
5898 break;
5899 case x86_64::kPCRel32_1:
5900 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
5901 break;
5902 case x86_64::kPCRel32_2:
5903 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
5904 break;
5905 case x86_64::kPCRel32_4:
5906 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
5907 break;
5908 case x86_64::kBranchPCRel32:
5909 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
5910 break;
5911 case x86_64::kBranchPCRel32WeakImport:
5912 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
5913 break;
5914 case x86_64::kPCRel32GOT:
5915 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5916 break;
5917 case x86_64::kPCRel32GOTWeakImport:
5918 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5919 break;
5920 case x86_64::kPCRel32GOTLoad:
5921 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
5922 break;
5923 case x86_64::kPCRel32GOTLoadWeakImport:
5924 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
5925 break;
55e3d2f6
A
5926 case x86_64::kGOTNoFixUp:
5927 sprintf(temp, "reference to GOT entry for ");
5928 break;
2f2f92e4
A
5929 case x86_64::kBranchPCRel8:
5930 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
5931 break;
55e3d2f6
A
5932 case x86_64::kPointerDiff24:
5933 sprintf(temp, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
5934 fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
5935 this->getFromTargetDisplayName(), fFromTarget.offset );
5936 return temp;
5937 case x86_64::kImageOffset32:
5938 sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc);
5939 break;
fb24a050
A
5940 case x86_64::kSectionOffset24:
5941 sprintf(temp, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc);
5942 break;
a61fdf0a
A
5943 case x86_64::kDtraceProbe:
5944 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
5945 break;
5946 case x86_64::kDtraceProbeSite:
5947 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
5948 break;
5949 case x86_64::kDtraceIsEnabledSite:
5950 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
5951 break;
5952 case x86_64::kDtraceTypeReference:
5953 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
5954 break;
69a49097
A
5955 }
5956 // always quote by-name references
5957 if ( fToTargetName != NULL ) {
5958 strcat(temp, "\"");
5959 strcat(temp, fToTargetName);
5960 strcat(temp, "\"");
5961 }
5962 else if ( fToTarget.atom != NULL ) {
5963 strcat(temp, fToTarget.atom->getDisplayName());
5964 }
5965 else {
5966 strcat(temp, "NULL target");
5967 }
5968 if ( fToTarget.offset != 0 )
5969 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
5970
5971 return temp;
5972}
d696c285 5973
55e3d2f6 5974
2f2f92e4
A
5975template <>
5976const char* Reference<arm>::getDescription() const
5977{
5978 static char temp[2048];
5979 switch( fKind ) {
5980 case arm::kNoFixUp:
5981 sprintf(temp, "reference to ");
5982 break;
5983 case arm::kFollowOn:
5984 sprintf(temp, "followed by ");
5985 break;
5986 case arm::kGroupSubordinate:
5987 sprintf(temp, "group subordinate ");
5988 break;
5989 case arm::kPointer:
5990 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
5991 break;
5992 case arm::kPointerWeakImport:
5993 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
5994 break;
5995 case arm::kPointerDiff:
5996 {
5997 // by-name references have quoted names
5998 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
5999 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
6000 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
55e3d2f6
A
6001 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
6002 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
2f2f92e4
A
6003 return temp;
6004 }
fb24a050
A
6005 case arm::kPointerDiff12:
6006 {
6007 // by-name references have quoted names
6008 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
6009 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
6010 sprintf(temp, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
6011 fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
6012 fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
6013 return temp;
6014 }
77cc3118
A
6015 case arm::kReadOnlyPointer:
6016 sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc);
6017 break;
2f2f92e4
A
6018 case arm::kBranch24:
6019 case arm::kThumbBranch22:
6020 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
6021 break;
6022 case arm::kBranch24WeakImport:
6023 case arm::kThumbBranch22WeakImport:
6024 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
6025 break;
6026 case arm::kDtraceProbe:
6027 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
6028 break;
6029 case arm::kDtraceProbeSite:
6030 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
6031 break;
6032 case arm::kDtraceIsEnabledSite:
6033 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
6034 break;
6035 case arm::kDtraceTypeReference:
6036 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
6037 break;
6038 }
6039 // always quote by-name references
6040 if ( fToTargetName != NULL ) {
6041 strcat(temp, "\"");
6042 strcat(temp, fToTargetName);
6043 strcat(temp, "\"");
6044 }
6045 else if ( fToTarget.atom != NULL ) {
6046 strcat(temp, fToTarget.atom->getDisplayName());
6047 }
6048 else {
6049 strcat(temp, "NULL target");
6050 }
6051 if ( fToTarget.offset != 0 )
6052 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
d696c285 6053
2f2f92e4
A
6054 return temp;
6055}
86b84c30 6056
55e3d2f6
A
6057
6058template <>
6059bool Reference<x86>::isBranch() const
6060{
6061 switch ( fKind ) {
6062 case x86::kPCRel32:
6063 case x86::kPCRel32WeakImport:
6064 return true;
6065 default:
6066 return false;
6067 }
6068}
6069
6070template <>
6071bool Reference<x86_64>::isBranch() const
6072{
6073 switch ( fKind ) {
6074 case x86_64::kBranchPCRel32:
6075 case x86_64::kBranchPCRel32WeakImport:
6076 return true;
6077 default:
6078 return false;
6079 }
6080}
6081
6082template <>
6083bool Reference<ppc>::isBranch() const
6084{
6085 switch ( fKind ) {
6086 case ppc::kBranch24:
6087 case ppc::kBranch24WeakImport:
6088 return true;
6089 default:
6090 return false;
6091 }
6092}
6093
6094template <>
6095bool Reference<ppc64>::isBranch() const
6096{
6097 switch ( fKind ) {
6098 case ppc64::kBranch24:
6099 case ppc64::kBranch24WeakImport:
6100 return true;
6101 default:
6102 return false;
6103 }
6104}
6105
6106template <>
6107bool Reference<arm>::isBranch() const
6108{
6109 switch ( fKind ) {
6110 case arm::kBranch24:
6111 case arm::kBranch24WeakImport:
6112 case arm::kThumbBranch22:
6113 case arm::kThumbBranch22WeakImport:
6114 return true;
6115 default:
6116 return false;
6117 }
6118}
6119
6120
6121
d696c285
A
6122}; // namespace relocatable
6123}; // namespace mach_o
6124
6125#endif // __OBJECT_FILE_MACH_O__