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