]> git.saurik.com Git - apple/ld64.git/blame - src/MachOReaderRelocatable.hpp
ld64-85.2.2.tar.gz
[apple/ld64.git] / src / MachOReaderRelocatable.hpp
CommitLineData
d696c285
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
2f2f92e4 3 * Copyright (c) 2005-2008 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
43
44//
45//
46// To implement architecture xxx, you must write template specializations for the following six methods:
47// Reader<xxx>::validFile()
48// Reader<xxx>::validSectionType()
49// Reader<xxx>::addRelocReference()
50// Reference<xxx>::getDescription()
51//
52//
53
54
55
56extern __attribute__((noreturn)) void throwf(const char* format, ...);
2f2f92e4 57extern void warning(const char* format, ...);
d696c285
A
58
59namespace mach_o {
60namespace relocatable {
61
62
63
74cfe461
A
64class ReferenceSorter
65{
66public:
67 bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
68 {
69 return ( left->getFixUpOffset() < right->getFixUpOffset() );
70 }
71};
72
73
d696c285
A
74// forward reference
75template <typename A> class Reader;
d696c285
A
76
77struct AtomAndOffset
78{
79 AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
80 AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
81 ObjectFile::Atom* atom;
82 uint32_t offset;
83};
84
85
86template <typename A>
87class Reference : public ObjectFile::Reference
88{
89public:
90 typedef typename A::P P;
91 typedef typename A::P::uint_t pint_t;
92 typedef typename A::ReferenceKinds Kinds;
93
94 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
95 Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
96 Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
97
98 virtual ~Reference() {}
99
100
a61fdf0a
A
101 virtual ObjectFile::Reference::TargetBinding getTargetBinding() const;
102 virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const;
d696c285
A
103 virtual uint8_t getKind() const { return (uint8_t)fKind; }
104 virtual uint64_t getFixUpOffset() const { return fFixUpOffsetInSrc; }
105 virtual const char* getTargetName() const { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); }
106 virtual ObjectFile::Atom& getTarget() const { return *fToTarget.atom; }
69a49097 107 virtual uint64_t getTargetOffset() const { return (int64_t)((int32_t)fToTarget.offset); }
d696c285
A
108 virtual ObjectFile::Atom& getFromTarget() const { return *fFromTarget.atom; }
109 virtual const char* getFromTargetName() const { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); }
110 virtual void setTarget(ObjectFile::Atom& target, uint64_t offset) { fToTarget.atom = &target; fToTarget.offset = offset; }
111 virtual void setToTargetOffset(uint64_t offset) { fToTarget.offset = offset; }
112 virtual void setFromTarget(ObjectFile::Atom& target) { fFromTarget.atom = &target; }
113 virtual void setFromTargetName(const char* name) { fFromTargetName = name; }
114 virtual void setFromTargetOffset(uint64_t offset) { fFromTarget.offset = offset; }
115 virtual const char* getDescription() const;
116 virtual uint64_t getFromTargetOffset() const { return fFromTarget.offset; }
117
a61fdf0a 118 static bool fgForFinalLinkedImage;
d696c285
A
119
120private:
121 pint_t fFixUpOffsetInSrc;
122 AtomAndOffset fToTarget;
123 AtomAndOffset fFromTarget;
124 const char* fToTargetName;
125 const char* fFromTargetName;
126 Kinds fKind;
a61fdf0a 127
d696c285
A
128};
129
a61fdf0a 130template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
d696c285
A
131
132template <typename A>
133Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
134 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
135 fKind(kind)
136{
69a49097
A
137 // make reference a by-name unless:
138 // - the reference type is only used with direct references
139 // - the target is translation unit scoped
a61fdf0a 140 // - the target kind is not regular (is weak or tentative)
2f2f92e4 141 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
a61fdf0a 142 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
77cc3118
A
143 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
144 && (toTarget.atom != at.atom) ) {
69a49097 145 fToTargetName = toTarget.atom->getName();
a61fdf0a 146 //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
147 fToTarget.atom = NULL;
148 }
149 ((class BaseAtom*)at.atom)->addReference(this);
150 //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
151}
152
153template <typename A>
154Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
155 : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
156 fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
157{
158 // make reference a by-name where needed
2f2f92e4 159 if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
d696c285 160 && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
a61fdf0a 161 && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
d696c285
A
162 && (toTarget.atom != at.atom) ) {
163 fToTargetName = toTarget.atom->getName();
164 fToTarget.atom = NULL;
165 }
166 ((class BaseAtom*)at.atom)->addReference(this);
167 //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
168 // this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
169}
170
171template <typename A>
172Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
173 : fFixUpOffsetInSrc(at.offset),
174 fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
175{
176 fToTarget.offset = toOffset;
177 ((class BaseAtom*)at.atom)->addReference(this);
178}
179
a61fdf0a
A
180template <typename A>
181ObjectFile::Reference::TargetBinding Reference<A>::getTargetBinding() const
182{
183 if ( fgForFinalLinkedImage ) {
184 if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) )
185 return ObjectFile::Reference::kDontBind;
186 }
187 if ( fToTarget.atom == NULL )
188 return ObjectFile::Reference::kUnboundByName;
189 if ( fToTargetName == NULL )
190 return ObjectFile::Reference::kBoundDirectly;
191 else
192 return ObjectFile::Reference::kBoundByName;
193}
194
195template <typename A>
196ObjectFile::Reference::TargetBinding Reference<A>::getFromTargetBinding() const
197{
198 if ( fFromTarget.atom == NULL ) {
199 if ( fFromTargetName == NULL )
200 return ObjectFile::Reference::kDontBind;
201 else
202 return ObjectFile::Reference::kUnboundByName;
203 }
204 else {
205 if ( fFromTargetName == NULL )
206 return ObjectFile::Reference::kBoundDirectly;
207 else
208 return ObjectFile::Reference::kBoundByName;
209 }
210}
211
212
d696c285
A
213
214template <typename A>
215class Segment : public ObjectFile::Segment
216{
217public:
218 Segment(const macho_section<typename A::P>* sect);
219 virtual const char* getName() const { return fSection->segname(); }
220 virtual bool isContentReadable() const { return true; }
221 virtual bool isContentWritable() const { return fWritable; }
222 virtual bool isContentExecutable() const { return fExecutable; }
223private:
224 const macho_section<typename A::P>* fSection;
225 bool fWritable;
226 bool fExecutable;
227};
228
229template <typename A>
230Segment<A>::Segment(const macho_section<typename A::P>* sect)
69a49097 231 : fSection(sect), fWritable(true), fExecutable(false)
d696c285 232{
69a49097
A
233 if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
234 fWritable = false;
d696c285
A
235 fExecutable = true;
236 }
237 else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
238 fWritable = true;
239 fExecutable = true;
240 }
241}
242
243
244class DataSegment : public ObjectFile::Segment
245{
246public:
247 virtual const char* getName() const { return "__DATA"; }
248 virtual bool isContentReadable() const { return true; }
249 virtual bool isContentWritable() const { return true; }
250 virtual bool isContentExecutable() const { return false; }
251
252 static DataSegment fgSingleton;
253};
254
255DataSegment DataSegment::fgSingleton;
256
a61fdf0a
A
257class LinkEditSegment : public ObjectFile::Segment
258{
259public:
260 virtual const char* getName() const { return "__LINKEDIT"; }
261 virtual bool isContentReadable() const { return true; }
262 virtual bool isContentWritable() const { return false; }
263 virtual bool isContentExecutable() const { return false; }
264
265 static LinkEditSegment fgSingleton;
266};
267
268LinkEditSegment LinkEditSegment::fgSingleton;
d696c285
A
269
270class BaseAtom : public ObjectFile::Atom
271{
272public:
273 BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
274
275 virtual void setSize(uint64_t size) = 0;
276 virtual void addReference(ObjectFile::Reference* ref) = 0;
74cfe461 277 virtual void sortReferences() = 0;
d696c285 278 virtual void addLineInfo(const ObjectFile::LineInfo& info) = 0;
a61fdf0a
A
279 virtual uint64_t getObjectAddress() const = 0;
280 virtual uint32_t getOrdinal() const { return fOrdinal; }
281 virtual void setOrdinal(uint32_t value) { fOrdinal = value; }
282 virtual const void* getSectionRecord() const = 0;
283 virtual bool isAlias() const { return false; }
d696c285
A
284
285 uint32_t fStabsStartIndex;
286 uint32_t fStabsCount;
a61fdf0a
A
287 uint32_t fOrdinal;
288};
289
290class BaseAtomSorter
291{
292public:
293 bool operator()(const class BaseAtom* left, const class BaseAtom* right) {
294 if ( left == right )
295 return false;
296 uint64_t leftAddr = left->getObjectAddress();
297 uint64_t rightAddr = right->getObjectAddress();
298 if ( leftAddr < rightAddr ) {
299 return true;
300 }
301 else if ( leftAddr > rightAddr ) {
302 return false;
303 }
304 else {
305 // if they have same address, one might be the end of a section and the other the start of the next section
306 const void* leftSection = left->getSectionRecord();
307 const void* rightSection = right->getSectionRecord();
308 if ( leftSection != rightSection ) {
309 return ( leftSection < rightSection );
310 }
311 // if they have same address and section, one might be an alias
312 bool leftAlias = left->isAlias();
313 bool rightAlias = right->isAlias();
314 if ( leftAlias && rightAlias ) {
315 // sort multiple aliases for same address first by scope
316 ObjectFile::Atom::Scope leftScope = left->getScope();
317 ObjectFile::Atom::Scope rightScope = right->getScope();
318 if ( leftScope != rightScope ) {
319 return ( leftScope < rightScope );
320 }
321 // sort multiple aliases for same address then by name
322 return ( strcmp(left->getName(), right->getName()) < 0 );
323 }
324 else if ( leftAlias ) {
325 return true;
326 }
327 else if ( rightAlias ) {
328 return false;
329 }
330 else {
331 // they must be tentative defintions
332 switch ( left->getDefinitionKind() ) {
333 case ObjectFile::Atom::kTentativeDefinition:
334 // sort tentative definitions by name
335 return ( strcmp(left->getName(), right->getName()) < 0 );
336 case ObjectFile::Atom::kAbsoluteSymbol:
337 // sort absolute symbols with same address by name
338 return ( strcmp(left->getName(), right->getName()) < 0 );
339 default:
340 // hack for rdar://problem/5102873
341 if ( !left->isZeroFill() || !right->isZeroFill() )
2f2f92e4 342 warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath());
a61fdf0a
A
343 break;
344 }
345 }
346 }
347 return false;
348 }
d696c285
A
349};
350
351
352//
353// A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
354// pointing to it. A C function or global variable is represented by one of these atoms.
355//
356//
357template <typename A>
358class SymbolAtom : public BaseAtom
359{
360public:
361 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
362 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
363 { return fOwner.getTranslationUnitSource(dir, name); }
364 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
365 virtual const char* getDisplayName() const { return getName(); }
366 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
367 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
368 ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
69a49097 369 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
a61fdf0a 370 virtual bool dontDeadStrip() const;
d696c285 371 virtual bool isZeroFill() const { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
2f2f92e4 372 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
d696c285
A
373 virtual uint64_t getSize() const { return fSize; }
374 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
375 virtual bool mustRemainInSection() const { return true; }
376 virtual const char* getSectionName() const;
377 virtual Segment<A>& getSegment() const { return *fSegment; }
d696c285
A
378 virtual ObjectFile::Atom& getFollowOnAtom() const;
379 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
74cfe461 380 virtual ObjectFile::Alignment getAlignment() const { return fAlignment; }
d696c285
A
381 virtual void copyRawContent(uint8_t buffer[]) const;
382 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
a61fdf0a 383 virtual void setSize(uint64_t size);
74cfe461
A
384 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
385 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
d696c285 386 virtual void addLineInfo(const ObjectFile::LineInfo& info) { fLineInfo.push_back(info); }
a61fdf0a
A
387 virtual uint64_t getObjectAddress() const { return fAddress; }
388 virtual const void* getSectionRecord() const { return (const void*)fSection; }
d696c285
A
389
390protected:
391 typedef typename A::P P;
392 typedef typename A::P::E E;
393 typedef typename A::P::uint_t pint_t;
394 typedef typename A::ReferenceKinds Kinds;
395 typedef typename std::vector<Reference<A>*> ReferenceVector;
396 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
397 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
398 friend class Reader<A>;
d696c285
A
399
400 SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
401 virtual ~SymbolAtom() {}
402
403 Reader<A>& fOwner;
404 const macho_nlist<P>* fSymbol;
405 pint_t fAddress;
406 pint_t fSize;
407 const macho_section<P>* fSection;
408 Segment<A>* fSegment;
409 ReferenceVector fReferences;
410 std::vector<ObjectFile::LineInfo> fLineInfo;
411 ObjectFile::Atom::Scope fScope;
69a49097 412 SymbolTableInclusion fSymbolTableInclusion;
74cfe461 413 ObjectFile::Alignment fAlignment;
d696c285
A
414};
415
416
417template <typename A>
418SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
419 : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fAlignment(0)
420{
421 uint8_t type = symbol->n_type();
422 if ( (type & N_EXT) == 0 )
423 fScope = ObjectFile::Atom::scopeTranslationUnit;
424 else if ( (type & N_PEXT) != 0 )
425 fScope = ObjectFile::Atom::scopeLinkageUnit;
426 else
427 fScope = ObjectFile::Atom::scopeGlobal;
428 if ( (type & N_TYPE) == N_SECT ) {
429 // real definition
430 fSegment = new Segment<A>(fSection);
431 fAddress = fSymbol->n_value();
2f2f92e4
A
432 pint_t sectionStartAddr = section->addr();
433 pint_t sectionEndAddr = section->addr()+section->size();
434 if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) {
435 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",
436 this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(),
437 (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) );
438 }
69a49097 439 }
d696c285 440 else {
2f2f92e4 441 warning("unknown symbol type: %d", type);
d696c285 442 }
2f2f92e4 443
d696c285
A
444 //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
445 // support for .o files built with old ld64
446 if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
447 const char* name = this->getName();
448 const int nameLen = strlen(name);
449 if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
450 // switch symbol to point at name that does not have trailing $stub
451 char correctName[nameLen];
452 strncpy(correctName, name, nameLen-5);
453 correctName[nameLen-5] = '\0';
454 const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
455 const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
456 for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
457 if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
458 fSymbol = s;
459 break;
460 }
461 }
462 }
463 }
464 // support for labeled stubs
465 switch ( section->flags() & SECTION_TYPE ) {
466 case S_SYMBOL_STUBS:
467 setSize(section->reserved2());
468 break;
469 case S_LAZY_SYMBOL_POINTERS:
470 case S_NON_LAZY_SYMBOL_POINTERS:
471 setSize(sizeof(pint_t));
472 break;
473 case S_4BYTE_LITERALS:
474 setSize(4);
475 break;
476 case S_8BYTE_LITERALS:
477 setSize(8);
478 break;
69a49097
A
479 case S_16BYTE_LITERALS:
480 setSize(16);
481 break;
d696c285
A
482 case S_CSTRING_LITERALS:
483 setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
69a49097 484 break;
d696c285
A
485 case S_REGULAR:
486 case S_ZEROFILL:
487 case S_COALESCED:
488 // size calculate later after next atom is found
489 break;
490 }
69a49097 491
77cc3118
A
492 // compute alignment
493 fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
494
69a49097
A
495 // compute whether this atom needs to be in symbol table
496 if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
497 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
498 }
499 else if ( fOwner.fOptions.fForFinalLinkedImage
500 && ((section->flags() & SECTION_TYPE) == S_COALESCED)
501 && ((section->flags() & S_ATTR_NO_TOC) == S_ATTR_NO_TOC)
502 && ((section->flags() & S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS)
503 && (strcmp(section->sectname(), "__eh_frame") == 0) ) {
504 // .eh symbols exist so the linker can associate them with functions
505 // removing them from final linked images is a big space savings rdar://problem/4180168
506 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
77cc3118
A
507 // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
508 fAlignment = ObjectFile::Alignment(0);
69a49097
A
509 }
510 else if ( fOwner.fOptions.fForFinalLinkedImage
511 && ((section->flags() & SECTION_TYPE) == S_REGULAR)
512 && (strncmp(section->sectname(), "__gcc_except_tab", 16) == 0)
513 && (strncmp(this->getName(), "GCC_except_table", 16) == 0) ) {
514 // GCC_except_table* symbols don't need to exist in final linked image
515 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
516 }
a61fdf0a
A
517 else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) {
518 // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
519 // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
520 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
521 }
69a49097
A
522 else {
523 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
524 }
a61fdf0a
A
525
526 // work around malformed icc generated .o files <rdar://problem/5349847>
527 // if section starts with a symbol and that symbol address does not match section alignment, then force it to
528 if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) )
529 fAlignment.modulus = 0;
530}
531
532template <typename A>
533bool SymbolAtom<A>::dontDeadStrip() const
534{
535 // the symbol can have a no-dead-strip bit
536 if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 )
537 return true;
538 // or the section can have a no-dead-strip bit
539 return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP );
d696c285
A
540}
541
542
543template <typename A>
544const char* SymbolAtom<A>::getSectionName() const
545{
a61fdf0a
A
546 if ( fOwner.fOptions.fForFinalLinkedImage && (strcmp(fSection->sectname(), "__textcoal_nt") == 0) )
547 return "__text";
548
d696c285
A
549 if ( strlen(fSection->sectname()) > 15 ) {
550 static char temp[18];
551 strncpy(temp, fSection->sectname(), 16);
552 temp[17] = '\0';
553 return temp;
554 }
555 return fSection->sectname();
556}
557
d696c285
A
558template <typename A>
559ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
560{
561 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
562 Reference<A>* ref = *it;
563 if ( ref->getKind() == A::kFollowOn )
564 return ref->getTarget();
565 }
566 return *((ObjectFile::Atom*)NULL);
567}
568
569
a61fdf0a
A
570class Beyond
571{
572public:
573 Beyond(uint64_t offset) : fOffset(offset) {}
574 bool operator()(ObjectFile::Reference* ref) const {
575 return ( ref->getFixUpOffset() >= fOffset );
576 }
577private:
578 uint64_t fOffset;
579};
580
d696c285 581
a61fdf0a
A
582template <typename A>
583void SymbolAtom<A>::setSize(uint64_t size)
584{
585 // when resizing, any references beyond the new size are tossed
586 if ( (fSize != 0) && (fReferences.size() > 0) )
587 fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end());
588 // set new size
589 fSize = size;
590}
d696c285
A
591
592template <typename A>
593void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
594{
595 // copy base bytes
596 if ( isZeroFill() )
597 bzero(buffer, fSize);
598 else {
599 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
600 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
601 }
602}
603
a61fdf0a
A
604//
605// A SymbolAliasAtom represents an alternate name for a SymbolAtom
606//
607//
d696c285 608template <typename A>
a61fdf0a 609class SymbolAliasAtom : public BaseAtom
d696c285
A
610{
611public:
a61fdf0a
A
612 virtual ObjectFile::Reader* getFile() const { return fAliasOf.getFile(); }
613 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
614 { return fAliasOf.getTranslationUnitSource(dir, name); }
615 virtual const char* getName() const { return fName; }
616 virtual const char* getDisplayName() const { return fName; }
617 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
618 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fAliasOf.getDefinitionKind(); }
619 virtual SymbolTableInclusion getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); }
620 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
621 virtual bool isZeroFill() const { return fAliasOf.isZeroFill(); }
2f2f92e4 622 virtual bool isThumb() const { return fAliasOf.isThumb(); }
a61fdf0a
A
623 virtual uint64_t getSize() const { return 0; }
624 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
625 virtual bool mustRemainInSection() const { return true; }
626 virtual const char* getSectionName() const { return fAliasOf.getSectionName(); }
627 virtual Segment<A>& getSegment() const { return (Segment<A>&)fAliasOf.getSegment(); }
628 virtual ObjectFile::Atom& getFollowOnAtom() const { return (ObjectFile::Atom&)fAliasOf; }
629 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
630 virtual ObjectFile::Alignment getAlignment() const { return fAliasOf.getAlignment(); }
631 virtual void copyRawContent(uint8_t buffer[]) const {}
632 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
633 virtual void setSize(uint64_t size) { }
634 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
635 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
636 virtual void addLineInfo(const ObjectFile::LineInfo& info) { }
637 virtual uint64_t getObjectAddress() const { return fAliasOf.getObjectAddress(); }
638 virtual const void* getSectionRecord() const { return fAliasOf.getSectionRecord(); }
639 virtual bool isAlias() const { return true; }
640
641protected:
642 typedef typename A::P P;
643 typedef typename std::vector<Reference<A>*> ReferenceVector;
644 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
645 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
646 friend class Reader<A>;
647
648 SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
649 virtual ~SymbolAliasAtom() {}
650
651 const char* fName;
652 const BaseAtom& fAliasOf;
653 ObjectFile::Atom::Scope fScope;
654 bool fDontDeadStrip;
655 ReferenceVector fReferences;
d696c285
A
656};
657
658
a61fdf0a
A
659template <typename A>
660SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
661 : fName(name), fAliasOf(aliasOf)
662{
663 //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
664 if ( symbol != NULL ) {
665 uint8_t type = symbol->n_type();
666 if ( (type & N_EXT) == 0 )
667 fScope = ObjectFile::Atom::scopeTranslationUnit;
668 else if ( (type & N_PEXT) != 0 )
669 fScope = ObjectFile::Atom::scopeLinkageUnit;
670 else
671 fScope = ObjectFile::Atom::scopeGlobal;
672 fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
673 }
674 else {
675 // aliases defined on the command line are initially global scope
676 fScope = ObjectFile::Atom::scopeGlobal;
677 fDontDeadStrip = false;
678 }
679 // add follow-on reference to real atom
680 new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
681}
682
683
d696c285
A
684//
685// A TentativeAtom represents a C "common" or "tentative" defintion of data.
686// For instance, "int foo;" is neither a declaration or a definition and
687// is represented by a TentativeAtom.
688//
689template <typename A>
690class TentativeAtom : public BaseAtom
691{
692public:
693 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
694 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
695 { return fOwner.getTranslationUnitSource(dir, name); }
696 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
697 virtual const char* getDisplayName() const { return getName(); }
698 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
699 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kTentativeDefinition; }
700 virtual bool isZeroFill() const { return true; }
2f2f92e4 701 virtual bool isThumb() const { return false; }
d696c285
A
702 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
703 ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
69a49097 704 virtual bool dontDeadStrip() const { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
d696c285
A
705 virtual uint64_t getSize() const { return fSymbol->n_value(); }
706 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
707 virtual bool mustRemainInSection() const { return true; }
a61fdf0a 708 virtual const char* getSectionName() const;
d696c285 709 virtual ObjectFile::Segment& getSegment() const { return DataSegment::fgSingleton; }
d696c285
A
710 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
711 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
74cfe461 712 virtual ObjectFile::Alignment getAlignment() const;
d696c285
A
713 virtual void copyRawContent(uint8_t buffer[]) const;
714 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
715 virtual void setSize(uint64_t size) { }
a61fdf0a 716 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
74cfe461 717 virtual void sortReferences() { }
a61fdf0a
A
718 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
719 virtual uint64_t getObjectAddress() const { return ULLONG_MAX; }
720 virtual const void* getSectionRecord() const { return NULL; }
d696c285
A
721
722protected:
723 typedef typename A::P P;
724 typedef typename A::P::E E;
725 typedef typename A::P::uint_t pint_t;
726 typedef typename A::ReferenceKinds Kinds;
727 friend class Reader<A>;
728
729 TentativeAtom(Reader<A>&, const macho_nlist<P>*);
730 virtual ~TentativeAtom() {}
731
732 Reader<A>& fOwner;
733 const macho_nlist<P>* fSymbol;
734 ObjectFile::Atom::Scope fScope;
735 static std::vector<ObjectFile::Reference*> fgNoReferences;
736};
737
738template <typename A>
739std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
740
741template <typename A>
742TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
743 : fOwner(owner), fSymbol(symbol)
744{
745 uint8_t type = symbol->n_type();
746 if ( (type & N_EXT) == 0 )
747 fScope = ObjectFile::Atom::scopeTranslationUnit;
748 else if ( (type & N_PEXT) != 0 )
749 fScope = ObjectFile::Atom::scopeLinkageUnit;
750 else
751 fScope = ObjectFile::Atom::scopeGlobal;
752 if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
753 // tentative definition
754 }
755 else {
2f2f92e4 756 warning("unknown symbol type: %d", type);
d696c285
A
757 }
758 //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
759}
760
761
762template <typename A>
74cfe461 763ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
d696c285 764{
a61fdf0a
A
765 uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc());
766 if ( alignment == 0 ) {
767 // common symbols align to their size
768 // that is, a 4-byte common aligns to 4-bytes
769 // if this size is not a power of two,
770 // then round up to the next power of two
771 uint64_t size = this->getSize();
772 alignment = 63 - (uint8_t)__builtin_clzll(size);
773 if ( size != (1ULL << alignment) )
774 ++alignment;
775 }
d696c285 776 // limit alignment of extremely large commons to 2^15 bytes (8-page)
a61fdf0a 777 if ( alignment < 12 )
74cfe461 778 return ObjectFile::Alignment(alignment);
d696c285 779 else
a61fdf0a
A
780 return ObjectFile::Alignment(12);
781}
782
783template <typename A>
784const char* TentativeAtom<A>::getSectionName() const
785{
786 if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
787 return "__common";
788 else
789 return "._tentdef";
d696c285
A
790}
791
a61fdf0a 792
d696c285
A
793template <typename A>
794void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
795{
796 bzero(buffer, getSize());
797}
798
799
800//
801// An AnonymousAtom represents compiler generated data that has no name.
802// For instance, a literal C-string or a 64-bit floating point constant
803// is represented by an AnonymousAtom.
804//
805template <typename A>
806class AnonymousAtom : public BaseAtom
807{
808public:
809 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
810 virtual bool getTranslationUnitSource(const char** dir, const char** name) const { return false; }
811 virtual const char* getName() const { return fSynthesizedName; }
812 virtual const char* getDisplayName() const;
813 virtual ObjectFile::Atom::Scope getScope() const;
2f2f92e4 814 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return fKind; }
69a49097
A
815 virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const { return fSymbolTableInclusion; }
816 virtual bool dontDeadStrip() const { return fDontDeadStrip; }
d696c285 817 virtual bool isZeroFill() const;
2f2f92e4 818 virtual bool isThumb() const { return false; }
d696c285
A
819 virtual uint64_t getSize() const { return fSize; }
820 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
821 virtual bool mustRemainInSection() const { return true; }
822 virtual const char* getSectionName() const;
823 virtual Segment<A>& getSegment() const { return *fSegment; }
d696c285
A
824 virtual ObjectFile::Atom& getFollowOnAtom() const;
825 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
74cfe461 826 virtual ObjectFile::Alignment getAlignment() const;
d696c285 827 virtual void copyRawContent(uint8_t buffer[]) const;
69a49097 828 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
d696c285 829 virtual void setSize(uint64_t size) { fSize = size; }
74cfe461
A
830 virtual void addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
831 virtual void sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
2f2f92e4 832 virtual void addLineInfo(const ObjectFile::LineInfo& info) { warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); }
a61fdf0a
A
833 virtual uint64_t getObjectAddress() const { return fAddress; }
834 virtual const void* getSectionRecord() const { return (const void*)fSection; }
d696c285
A
835 BaseAtom* redirectTo() { return fRedirect; }
836 bool isWeakImportStub() { return fWeakImportStub; }
a61fdf0a
A
837 void resolveName();
838
d696c285
A
839protected:
840 typedef typename A::P P;
841 typedef typename A::P::E E;
842 typedef typename A::P::uint_t pint_t;
843 typedef typename A::ReferenceKinds Kinds;
844 typedef typename std::vector<Reference<A>*> ReferenceVector;
845 typedef typename ReferenceVector::iterator ReferenceVectorIterator; // seems to help C++ parser
846 typedef typename ReferenceVector::const_iterator ReferenceVectorConstIterator; // seems to help C++ parser
847 friend class Reader<A>;
848
2f2f92e4 849 AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
d696c285 850 virtual ~AnonymousAtom() {}
a61fdf0a 851 static bool cstringsHaveLabels();
d696c285
A
852
853 Reader<A>& fOwner;
854 const char* fSynthesizedName;
a61fdf0a 855 const char* fDisplayName;
d696c285 856 const macho_section<P>* fSection;
2f2f92e4
A
857 pint_t fAddress;
858 pint_t fSize;
d696c285
A
859 Segment<A>* fSegment;
860 ReferenceVector fReferences;
861 BaseAtom* fRedirect;
69a49097 862 bool fDontDeadStrip;
d696c285 863 bool fWeakImportStub;
69a49097
A
864 ObjectFile::Atom::SymbolTableInclusion fSymbolTableInclusion;
865 ObjectFile::Atom::Scope fScope;
2f2f92e4 866 ObjectFile::Atom::DefinitionKind fKind;
d696c285
A
867};
868
869template <typename A>
2f2f92e4 870AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
a61fdf0a
A
871 : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size),
872 fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
2f2f92e4 873 fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition)
d696c285
A
874{
875 fSegment = new Segment<A>(fSection);
876 fRedirect = this;
877 uint8_t type = fSection->flags() & SECTION_TYPE;
2f2f92e4 878 //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
d696c285
A
879 switch ( type ) {
880 case S_ZEROFILL:
881 {
882 asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
883 }
884 break;
a61fdf0a 885 case S_COALESCED:
d696c285 886 case S_REGULAR:
69a49097
A
887 if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
888 // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
a61fdf0a
A
889 fSynthesizedName = ".objc_class_name_PENDING";
890 owner.fAtomsPendingAName.push_back(this);
891 owner.fSectionsWithAtomsPendingAName.insert(fSection);
69a49097
A
892 if ( fOwner.fOptions.fForFinalLinkedImage )
893 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
894 else
895 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
896 fScope = ObjectFile::Atom::scopeGlobal;
897 }
898 else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
899 // handle .o files created by old ld64 -r that are missing cstring section type
900 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
901 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
902 }
2f2f92e4
A
903 else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) {
904 fSynthesizedName = "cfstring-pointer-name-PENDING";
905 fScope = ObjectFile::Atom::scopeLinkageUnit;
906 owner.fAtomsPendingAName.push_back(this);
907 owner.fSectionsWithAtomsPendingAName.insert(fSection);
908 fDontDeadStrip = false;
909 fKind = ObjectFile::Atom::kWeakDefinition;
910 }
69a49097 911 break;
d696c285
A
912 case S_CSTRING_LITERALS:
913 {
914 const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
915 asprintf((char**)&fSynthesizedName, "cstring=%s", str);
69a49097 916 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 917 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097 918 fDontDeadStrip = false;
a61fdf0a
A
919 if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() )
920 fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
d696c285
A
921 }
922 break;
923 case S_4BYTE_LITERALS:
924 {
925 uint32_t value = E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
926 asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
69a49097 927 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 928 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097 929 fDontDeadStrip = false;
d696c285
A
930 }
931 break;
932 case S_8BYTE_LITERALS:
933 {
934 uint64_t value = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
935 asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
69a49097 936 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 937 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097
A
938 fDontDeadStrip = false;
939 }
940 break;
941 case S_16BYTE_LITERALS:
942 {
943 uint64_t value1 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
944 uint64_t value2 = E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
945 asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
946 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4 947 fKind = ObjectFile::Atom::kWeakDefinition;
69a49097 948 fDontDeadStrip = false;
d696c285
A
949 }
950 break;
951 case S_LITERAL_POINTERS:
952 {
a61fdf0a
A
953 //uint32_t literalNameAddr = P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
954 //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
955 //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
956 fSynthesizedName = "literal-pointer-name-PENDING";
69a49097 957 fScope = ObjectFile::Atom::scopeLinkageUnit;
2f2f92e4
A
958 fKind = ObjectFile::Atom::kWeakDefinition;
959 fDontDeadStrip = false;
a61fdf0a
A
960 owner.fAtomsPendingAName.push_back(this);
961 owner.fSectionsWithAtomsPendingAName.insert(fSection);
d696c285
A
962 }
963 break;
964 case S_MOD_INIT_FUNC_POINTERS:
965 asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
966 break;
967 case S_MOD_TERM_FUNC_POINTERS:
968 asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
969 break;
970 case S_SYMBOL_STUBS:
971 {
972 uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
973 index += fSection->reserved1();
974 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
975 const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
976 uint32_t strOffset = sym->n_strx();
977 // want name to not have $stub suffix, this is what automatic stub generation expects
978 fSynthesizedName = &fOwner.fStrings[strOffset];
979 // check for weak import
980 fWeakImportStub = fOwner.isWeakImportSymbol(sym);
981 // sometimes the compiler gets confused and generates a stub to a static function
982 // if so, we should redirect any call to the stub to be calls to the real static function atom
a61fdf0a 983 if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
d696c285 984 BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
a61fdf0a 985 if ( staticAtom != NULL )
d696c285
A
986 fRedirect = staticAtom;
987 }
2f2f92e4 988 fKind = ObjectFile::Atom::kWeakDefinition;
a61fdf0a
A
989 // might be a spurious stub for a static function, make stub static too
990 if ( (sym->n_type() & N_EXT) == 0 )
991 fScope = ObjectFile::Atom::scopeTranslationUnit;
992 else
993 fScope = ObjectFile::Atom::scopeLinkageUnit;
d696c285
A
994 }
995 break;
996 case S_LAZY_SYMBOL_POINTERS:
997 case S_NON_LAZY_SYMBOL_POINTERS:
998 {
69a49097
A
999 fDontDeadStrip = false;
1000 fScope = ObjectFile::Atom::scopeLinkageUnit;
d696c285
A
1001 uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
1002 index += fSection->reserved1();
1003 uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
1004 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1005 // Silly codegen with non-lazy pointer to a local symbol
d696c285
A
1006 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1007 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
69a49097 1008 // All atoms not created yet, so we need to scan symbol table
a61fdf0a 1009 const macho_nlist<P>* closestSym = NULL;
d696c285
A
1010 const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
1011 for (const macho_nlist<P>* sym = fOwner.fSymbols; sym < end; ++sym) {
69a49097 1012 if ( ((sym->n_type() & N_TYPE) == N_SECT)
a61fdf0a
A
1013 && ((sym->n_type() & N_STAB) == 0) ) {
1014 if ( sym->n_value() == nonLazyPtrValue ) {
1015 const char* name = &fOwner.fStrings[sym->n_strx()];
1016 char* str = new char[strlen(name)+16];
1017 strcpy(str, name);
1018 strcat(str, "$non_lazy_ptr");
1019 fSynthesizedName = str;
1020 // add direct reference to target later, because its atom may not be constructed yet
1021 fOwner.fLocalNonLazys.push_back(this);
1022 fScope = ObjectFile::Atom::scopeTranslationUnit;
1023 return;
1024 }
1025 else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
1026 closestSym = sym;
1027 }
d696c285
A
1028 }
1029 }
a61fdf0a
A
1030 // add direct reference to target later, because its atom may not be constructed yet
1031 if ( closestSym != NULL ) {
1032 const char* name = &fOwner.fStrings[closestSym->n_strx()];
1033 char* str;
1034 asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
1035 fSynthesizedName = str;
1036 }
1037 else {
1038 fSynthesizedName = "$interior$non_lazy_ptr";
1039 }
1040 fScope = ObjectFile::Atom::scopeTranslationUnit;
1041 fOwner.fLocalNonLazys.push_back(this);
1042 return;
d696c285
A
1043 }
1044 const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
1045 const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
1046 char* str = new char[strlen(name)+16];
1047 strcpy(str, name);
1048 if ( type == S_LAZY_SYMBOL_POINTERS )
1049 strcat(str, "$lazy_ptr");
1050 else
1051 strcat(str, "$non_lazy_ptr");
1052 fSynthesizedName = str;
1053
2f2f92e4
A
1054 // optimize __IMPORT segment out of i386 dyld or if -slow_stubs is used
1055 if ( (fOwner.fOptions.fForDyld || fOwner.fOptions.fSlowx86Stubs) && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
a61fdf0a
A
1056 macho_section<P>* dummySection = new macho_section<P>(*fSection);
1057 dummySection->set_segname("__DATA");
2f2f92e4 1058 dummySection->set_sectname("__nl_symbol_ptr");
a61fdf0a
A
1059 fSection = dummySection;
1060 fSegment = new Segment<A>(fSection);
1061 }
1062
2f2f92e4
A
1063 if ( type == S_NON_LAZY_SYMBOL_POINTERS )
1064 fKind = ObjectFile::Atom::kWeakDefinition;
1065
69a49097
A
1066 if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
1067 // target is translation unit scoped, so add direct reference to target
1068 //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
1069 new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
1070 }
1071 else {
1072 if ( fOwner.isWeakImportSymbol(targetSymbol) )
1073 new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
1074 else
1075 new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
1076 }
d696c285
A
1077 }
1078 break;
1079 default:
1080 throwf("section type %d not supported with address=0x%08X", type, addr);
1081 }
1082 //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
1083}
1084
a61fdf0a
A
1085// x86_64 uses L labels on cstrings to allow relocs with addends
1086template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
1087template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
1088
1089
1090template <typename A>
1091void AnonymousAtom<A>::resolveName()
1092{
1093 if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
1094 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1095 // references are not yet sorted, so scan the vector
1096 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1097 if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1098 const char* superStr = (*rit)->getTargetName();
1099 if ( strncmp(superStr, "cstring=", 8) == 0 ) {
1100 const char* superClassName;
1101 asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
1102 new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
1103 }
1104 break;
1105 }
1106 }
1107 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1108 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1109 const char* classStr = (*rit)->getTargetName();
1110 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
1111 asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
1112 }
1113 break;
1114 }
1115 }
1116 }
1117 else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
2f2f92e4
A
1118 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1119 if ( references.size() < 1 )
1120 throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
1121 ObjectFile::Reference* ref = references[0];
a61fdf0a
A
1122 const char* str = ref->getTargetName();
1123 if ( strncmp(str, "cstring=", 8) == 0 ) {
1124 asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
1125 }
1126 }
2f2f92e4
A
1127 else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
1128 // references are not yet sorted, so scan the vector
1129 std::vector<ObjectFile::Reference*>& references = this->getReferences();
1130 for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
1131 if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
1132 const char* superStr = (*rit)->getTargetName();
1133 if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
1134 asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
1135 }
1136 else {
1137 // compiled with -fwritable-strings or a non-ASCII string
1138 ObjectFile::Atom& stringDataAtom = (*rit)->getTarget();
1139 uint8_t buffer[stringDataAtom.getSize()];
1140 stringDataAtom.copyRawContent(buffer);
1141 fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
1142 fScope = ObjectFile::Atom::scopeTranslationUnit;
1143 fSynthesizedName = "cfstring-not-coalesable";
1144 }
1145 break;
1146 }
1147 }
1148 }
a61fdf0a
A
1149}
1150
d696c285
A
1151
1152template <typename A>
1153const char* AnonymousAtom<A>::getDisplayName() const
1154{
1155 if ( fSynthesizedName != NULL )
1156 return fSynthesizedName;
1157
a61fdf0a
A
1158 if ( fDisplayName != NULL )
1159 return fDisplayName;
1160
d696c285
A
1161 if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
1162 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
a61fdf0a 1163 asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
d696c285
A
1164 }
1165 else {
a61fdf0a 1166 asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
d696c285 1167 }
a61fdf0a 1168 return fDisplayName;
d696c285
A
1169}
1170
a61fdf0a 1171
d696c285
A
1172template <typename A>
1173ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
1174{
74cfe461 1175 return fScope;
d696c285
A
1176}
1177
d696c285
A
1178
1179template <typename A>
1180bool AnonymousAtom<A>::isZeroFill() const
1181{
1182 return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
1183}
1184
1185
1186template <typename A>
1187const char* AnonymousAtom<A>::getSectionName() const
1188{
d696c285
A
1189 if ( strlen(fSection->sectname()) > 15 ) {
1190 static char temp[18];
1191 strncpy(temp, fSection->sectname(), 16);
1192 temp[17] = '\0';
1193 return temp;
1194 }
1195 return fSection->sectname();
1196}
1197
1198template <typename A>
74cfe461 1199ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
d696c285 1200{
d696c285
A
1201 switch ( fSection->flags() & SECTION_TYPE ) {
1202 case S_4BYTE_LITERALS:
74cfe461 1203 return ObjectFile::Alignment(2);
d696c285 1204 case S_8BYTE_LITERALS:
74cfe461 1205 return ObjectFile::Alignment(3);
69a49097 1206 case S_16BYTE_LITERALS:
74cfe461 1207 return ObjectFile::Alignment(4);
d696c285 1208 case S_NON_LAZY_SYMBOL_POINTERS:
74cfe461 1209 return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
a61fdf0a
A
1210 case S_CSTRING_LITERALS:
1211 if ( ! fOwner.fOptions.fForFinalLinkedImage )
1212 return ObjectFile::Alignment(fSection->align());
d696c285 1213 default:
74cfe461 1214 return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
d696c285
A
1215 }
1216}
1217
d696c285
A
1218
1219template <typename A>
1220ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
1221{
1222 for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
1223 Reference<A>* ref = *it;
1224 if ( ref->getKind() == A::kFollowOn )
1225 return ref->getTarget();
1226 }
1227 return *((ObjectFile::Atom*)NULL);
1228}
1229
1230template <typename A>
1231void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
1232{
1233 // copy base bytes
1234 if ( isZeroFill() )
1235 bzero(buffer, fSize);
1236 else {
1237 uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
1238 memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
1239 }
1240}
1241
1242
a61fdf0a
A
1243//
1244// An AbsoluteAtom represents an N_ABS symbol which can only be created in
1245// assembly language and usable by static executables such as the kernel/
1246//
1247template <typename A>
1248class AbsoluteAtom : public BaseAtom
1249{
1250public:
1251 virtual ObjectFile::Reader* getFile() const { return &fOwner; }
1252 virtual bool getTranslationUnitSource(const char** dir, const char** name) const
1253 { return fOwner.getTranslationUnitSource(dir, name); }
1254 virtual const char* getName() const { return &fOwner.fStrings[fSymbol->n_strx()]; }
1255 virtual const char* getDisplayName() const { return getName(); }
1256 virtual ObjectFile::Atom::Scope getScope() const { return fScope; }
1257 virtual ObjectFile::Atom::DefinitionKind getDefinitionKind() const { return ObjectFile::Atom::kAbsoluteSymbol; }
1258 virtual bool isZeroFill() const { return false; }
2f2f92e4 1259 virtual bool isThumb() const { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
a61fdf0a
A
1260 virtual SymbolTableInclusion getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
1261 virtual bool dontDeadStrip() const { return false; }
1262 virtual uint64_t getSize() const { return 0; }
1263 virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgNoReferences; }
1264 virtual bool mustRemainInSection() const { return true; }
1265 virtual const char* getSectionName() const { return "._absolute"; }
1266 virtual ObjectFile::Segment& getSegment() const { return LinkEditSegment::fgSingleton; }
1267 virtual ObjectFile::Atom& getFollowOnAtom() const { return *(ObjectFile::Atom*)NULL; }
1268 virtual std::vector<ObjectFile::LineInfo>* getLineInfo() const { return NULL; }
1269 virtual ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); }
1270 virtual void copyRawContent(uint8_t buffer[]) const { }
1271 virtual void setScope(ObjectFile::Atom::Scope newScope) { fScope = newScope; }
1272 virtual void setSize(uint64_t size) { }
1273 virtual void addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
1274 virtual void sortReferences() { }
1275 virtual void addLineInfo(const ObjectFile::LineInfo& info) { throw "ld: can't add line info to tentative definition"; }
1276 virtual uint64_t getObjectAddress() const { return fSymbol->n_value(); }
1277 virtual void setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
1278 virtual const void* getSectionRecord() const { return NULL; }
1279
1280protected:
1281 typedef typename A::P P;
1282 typedef typename A::P::E E;
1283 typedef typename A::P::uint_t pint_t;
1284 typedef typename A::ReferenceKinds Kinds;
1285 friend class Reader<A>;
1286
1287 AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
1288 virtual ~AbsoluteAtom() {}
1289
1290 Reader<A>& fOwner;
1291 const macho_nlist<P>* fSymbol;
1292 ObjectFile::Atom::Scope fScope;
1293 static std::vector<ObjectFile::Reference*> fgNoReferences;
1294};
1295
1296template <typename A>
1297std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
1298
1299template <typename A>
1300AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
1301 : fOwner(owner), fSymbol(symbol)
1302{
1303 // store absolute adress in fSectionOffset
1304 fSectionOffset = symbol->n_value();
1305 // compute scope
1306 uint8_t type = symbol->n_type();
1307 if ( (type & N_EXT) == 0 )
1308 fScope = ObjectFile::Atom::scopeTranslationUnit;
1309 else if ( (type & N_PEXT) != 0 )
1310 fScope = ObjectFile::Atom::scopeLinkageUnit;
1311 else
1312 fScope = ObjectFile::Atom::scopeGlobal;
1313 //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
1314}
1315
d696c285
A
1316
1317
1318template <typename A>
1319class Reader : public ObjectFile::Reader
1320{
1321public:
1322 static bool validFile(const uint8_t* fileContent);
a61fdf0a
A
1323 Reader(const uint8_t* fileContent, const char* path, time_t modTime,
1324 const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
d696c285
A
1325 virtual ~Reader() {}
1326
1327 virtual const char* getPath() { return fPath; }
1328 virtual time_t getModificationTime() { return fModTime; }
1329 virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return fDebugInfo; }
1330 virtual std::vector<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
1331 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name) { return NULL; }
1332 virtual std::vector<Stab>* getStabs() { return &fStabs; }
a61fdf0a 1333 virtual ObjectFile::Reader::ObjcConstraint getObjCConstraint() { return fObjConstraint; }
2f2f92e4 1334 virtual uint32_t updateCpuConstraint(uint32_t current);
a61fdf0a
A
1335 virtual bool canScatterAtoms() { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
1336 virtual bool objcReplacementClasses(){ return fReplacementClasses; }
2f2f92e4 1337 virtual bool hasLongBranchStubs() { return fHasLongBranchStubs; }
d696c285
A
1338
1339 bool getTranslationUnitSource(const char** dir, const char** name) const;
1340
1341private:
1342 typedef typename A::P P;
1343 typedef typename A::P::E E;
1344 typedef typename A::P::uint_t pint_t;
1345 //typedef typename std::vector<Atom<A>*> AtomVector;
1346 //typedef typename AtomVector::iterator AtomVectorIterator; // seems to help C++ parser
1347 typedef typename A::ReferenceKinds Kinds;
1348 friend class AnonymousAtom<A>;
1349 friend class TentativeAtom<A>;
a61fdf0a 1350 friend class AbsoluteAtom<A>;
d696c285 1351 friend class SymbolAtom<A>;
2f2f92e4 1352 typedef std::map<pint_t, BaseAtom*> AddrToAtomMap;
a61fdf0a
A
1353
1354 void addReferencesForSection(const macho_section<P>* sect);
d696c285
A
1355 bool addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
1356 bool addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
d696c285
A
1357 bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
1358 static bool isWeakImportSymbol(const macho_nlist<P>* sym);
1359 static bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
1360 static const char* assureFullPath(const char* path);
2f2f92e4
A
1361 AtomAndOffset findAtomAndOffset(pint_t addr);
1362 AtomAndOffset findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
1363 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
1364 Reference<A>* makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
1365 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
1366 Reference<A>* makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
1367 Reference<A>* makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
d696c285 1368 Reference<A>* makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
2f2f92e4 1369 Reference<A>* makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
d696c285 1370 void validSectionType(uint8_t type);
a61fdf0a
A
1371 void addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
1372 void setCpuConstraint(uint32_t cpusubtype);
d696c285
A
1373
1374 BaseAtom* findAtomByName(const char*);
1375
1376 const char* fPath;
1377 time_t fModTime;
a61fdf0a 1378 uint32_t fOrdinalBase;
d696c285
A
1379 const ObjectFile::ReaderOptions& fOptions;
1380 const macho_header<P>* fHeader;
1381 const char* fStrings;
1382 const macho_nlist<P>* fSymbols;
1383 uint32_t fSymbolCount;
1384 const macho_segment_command<P>* fSegment;
1385 const uint32_t* fIndirectTable;
a61fdf0a 1386 std::vector<BaseAtom*> fAtoms;
2f2f92e4
A
1387 AddrToAtomMap fAddrToAtom;
1388 AddrToAtomMap fAddrToAbsoluteAtom;
d696c285 1389 std::vector<class AnonymousAtom<A>*> fLocalNonLazys;
a61fdf0a
A
1390 std::vector<class AnonymousAtom<A>*> fAtomsPendingAName;
1391 std::set<const macho_section<P>*> fSectionsWithAtomsPendingAName;
1392 std::vector<const char*> fDtraceProviderInfo;
d696c285 1393 ObjectFile::Reader::DebugInfoKind fDebugInfo;
69a49097 1394 bool fHasUUID;
d696c285
A
1395 const macho_section<P>* fDwarfDebugInfoSect;
1396 const macho_section<P>* fDwarfDebugAbbrevSect;
1397 const macho_section<P>* fDwarfDebugLineSect;
1398 const char* fDwarfTranslationUnitDir;
1399 const char* fDwarfTranslationUnitFile;
1400 std::map<uint32_t,const char*> fDwarfIndexToFile;
1401 std::vector<Stab> fStabs;
69a49097 1402 bool fAppleObjc;
a61fdf0a
A
1403 bool fHasDTraceProbes;
1404 bool fHaveIndirectSymbols;
1405 bool fReplacementClasses;
2f2f92e4 1406 bool fHasLongBranchStubs;
a61fdf0a 1407 ObjectFile::Reader::ObjcConstraint fObjConstraint;
2f2f92e4 1408 uint32_t fCpuConstraint;
d696c285
A
1409};
1410
d696c285 1411template <typename A>
a61fdf0a
A
1412Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
1413 : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
d696c285 1414 fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
a61fdf0a
A
1415 fDebugInfo(kDebugInfoNone), fHasUUID(false), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
1416 fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
2f2f92e4 1417 fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
a61fdf0a 1418 fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny)
d696c285
A
1419{
1420 // sanity check
1421 if ( ! validFile(fileContent) )
1422 throw "not a valid mach-o object file";
1423
a61fdf0a
A
1424 Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
1425
1426 // write out path for -t or -whatsloaded option
1427 if ( options.fLogObjectFiles || options.fLogAllFiles )
1428 printf("%s\n", path);
1429
d696c285
A
1430 // cache intersting pointers
1431 const macho_header<P>* header = (const macho_header<P>*)fileContent;
a61fdf0a 1432 this->setCpuConstraint(header->cpusubtype());
d696c285
A
1433 const uint32_t cmd_count = header->ncmds();
1434 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
2f2f92e4 1435 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
d696c285 1436 const macho_load_command<P>* cmd = cmds;
69a49097
A
1437 uint32_t undefinedStartIndex = 0;
1438 uint32_t undefinedEndIndex = 0;
d696c285
A
1439 for (uint32_t i = 0; i < cmd_count; ++i) {
1440 switch (cmd->cmd()) {
1441 case LC_SYMTAB:
1442 {
1443 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
1444 fSymbolCount = symtab->nsyms();
1445 fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
1446 fStrings = (char*)header + symtab->stroff();
a61fdf0a
A
1447 if ( undefinedEndIndex == 0 ) {
1448 undefinedStartIndex = 0;
1449 undefinedEndIndex = symtab->nsyms();
1450 }
d696c285
A
1451 }
1452 break;
1453 case LC_DYSYMTAB:
1454 {
1455 const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
1456 fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
69a49097
A
1457 undefinedStartIndex = dsymtab->iundefsym();
1458 undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
d696c285
A
1459 }
1460 break;
1461 case LC_UUID:
69a49097 1462 fHasUUID = true;
d696c285
A
1463 break;
1464
1465 default:
1466 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1467 fSegment = (macho_segment_command<P>*)cmd;
1468 }
1469 break;
1470 }
1471 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
2f2f92e4
A
1472 if ( cmd > cmdsEnd )
1473 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
d696c285 1474 }
2f2f92e4
A
1475
1476 // if there are no load commands, then this file has no content, so no atoms
1477 if ( header->ncmds() < 1 )
1478 return;
1479
d696c285
A
1480 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
1481 const macho_section<P>* const sectionsEnd = &sectionsStart[fSegment->nsects()];
1482
1483 // inital guess for number of atoms
1484 fAtoms.reserve(fSymbolCount);
1485
1486 // add all atoms that have entries in symbol table
1487 const macho_section<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
a61fdf0a
A
1488 for (int i=fSymbolCount-1; i >= 0 ; --i) {
1489 // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the reaal name
d696c285
A
1490 const macho_nlist<P>& sym = fSymbols[i];
1491 if ( (sym.n_type() & N_STAB) == 0 ) {
1492 uint8_t type = (sym.n_type() & N_TYPE);
1493 if ( type == N_SECT ) {
1494 const macho_section<P>* section = &sections[sym.n_sect()-1];
a61fdf0a 1495 pint_t sectionEndAddr = section->addr() + section->size();
d696c285
A
1496 bool suppress = false;
1497 // ignore atoms in debugger sections
1498 if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
a61fdf0a
A
1499 if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
1500 // ignore dtrace probe labels
1501 fHasDTraceProbes = true;
1502 }
1503 else if ( fStrings[sym.n_strx()] == 'L' ) {
1504 // ignore L labels, <rdar://problem/3962731>
1505 }
1506 else {
1507 // ignore labels for atoms in other sections
1508 switch ( section->flags() & SECTION_TYPE ) {
1509 case S_REGULAR:
1510 if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
1511 suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
1512 case S_ZEROFILL:
1513 case S_COALESCED:
1514 case S_4BYTE_LITERALS:
1515 case S_8BYTE_LITERALS:
1516 case S_16BYTE_LITERALS:
1517 case S_CSTRING_LITERALS:
1518 {
1519 BaseAtom* newAtom;
2f2f92e4 1520 typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
a61fdf0a
A
1521 if ( (pos != fAddrToAtom.end()) && (strcmp(pos->second->getSectionName(), section->sectname())==0) ) {
1522 // another label to an existing address in the same section, make this an alias
1523 newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
1524 }
1525 else {
1526 // make SymbolAtom atom for this address
1527 newAtom = new SymbolAtom<A>(*this, &sym, section);
1528 // don't add symbols at end of section to addr->atom map
1529 if ( sym.n_value() != sectionEndAddr )
2f2f92e4 1530 fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
a61fdf0a
A
1531 }
1532 if ( ! suppress )
1533 fAtoms.push_back(newAtom);
1534 }
1535 break;
1536 case S_SYMBOL_STUBS:
1537 case S_LAZY_SYMBOL_POINTERS:
1538 case S_NON_LAZY_SYMBOL_POINTERS:
1539 // ignore symboled stubs produces by old ld64
1540 break;
1541 default:
2f2f92e4 1542 warning("symbol %s found in unsupported section in %s",
a61fdf0a
A
1543 &fStrings[sym.n_strx()], this->getPath());
1544 }
d696c285
A
1545 }
1546 }
1547 }
1548 else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
1549 fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
1550 }
a61fdf0a
A
1551 else if ( type == N_ABS ) {
1552 const char* symName = &fStrings[sym.n_strx()];
2f2f92e4 1553 if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
a61fdf0a
A
1554 // ignore .objc_class_name_* symbols
1555 fAppleObjc = true;
1556 }
1557 else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
1558 // ignore empty *.eh symbols
1559 }
1560 else {
1561 BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
1562 fAtoms.push_back(abAtom);
1563 fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
1564 }
1565 }
1566 else if ( type == N_INDR ) {
1567 fHaveIndirectSymbols = true;
69a49097 1568 }
d696c285
A
1569 }
1570 }
1571
d696c285
A
1572 // add all fixed size anonymous atoms from special sections
1573 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2f2f92e4 1574 pint_t atomSize = 0;
d696c285
A
1575 uint8_t type (sect->flags() & SECTION_TYPE);
1576 validSectionType(type);
1577 bool suppress = false;
1578 switch ( type ) {
1579 case S_SYMBOL_STUBS:
1580 suppress = true;
1581 atomSize = sect->reserved2();
1582 break;
1583 case S_LAZY_SYMBOL_POINTERS:
1584 suppress = true;
1585 atomSize = sizeof(pint_t);
1586 break;
1587 case S_NON_LAZY_SYMBOL_POINTERS:
1588 case S_LITERAL_POINTERS:
1589 case S_MOD_INIT_FUNC_POINTERS:
1590 case S_MOD_TERM_FUNC_POINTERS:
1591 atomSize = sizeof(pint_t);
1592 break;
1593 case S_INTERPOSING:
1594 atomSize = sizeof(pint_t)*2;
1595 break;
1596 case S_4BYTE_LITERALS:
1597 atomSize = 4;
1598 break;
1599 case S_8BYTE_LITERALS:
1600 atomSize = 8;
1601 break;
69a49097
A
1602 case S_16BYTE_LITERALS:
1603 atomSize = 16;
1604 break;
1605 case S_REGULAR:
1606 // special case ObjC classes to synthesize .objc_class_name_* symbols
1607 if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
1608 // gcc sometimes over aligns class structure
1609 uint32_t align = 1 << sect->align();
1610 atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
a61fdf0a
A
1611 }
1612 // get objc Garbage Collection info
1613 else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
1614 || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
1615 // struct objc_image_info {
1616 // uint32_t version; // initially 0
1617 // uint32_t flags;
1618 // };
1619 // #define OBJC_IMAGE_SUPPORTS_GC 2
1620 // #define OBJC_IMAGE_GC_ONLY 4
1621 //
1622 const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
1623 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
1624 uint32_t flags = E::get32(contents[1]);
1625 if ( (flags & 4) == 4 )
1626 fObjConstraint = ObjectFile::Reader::kObjcGC;
1627 else if ( (flags & 2) == 2 )
1628 fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
1629 else
1630 fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
1631 if ( (flags & 1) == 1 )
1632 fReplacementClasses = true;
1633 // don't make atom for this section
1634 atomSize = sect->size();
1635 suppress = true;
69a49097 1636 }
a61fdf0a 1637 else {
2f2f92e4 1638 warning("can't parse __OBJC/__image_info section in %s", fPath);
a61fdf0a
A
1639 }
1640 }
2f2f92e4
A
1641 // special case constant NS/CFString literals and make an atom out of each one
1642 else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
1643 atomSize = 4 * sizeof(pint_t);
1644 }
69a49097 1645 break;
d696c285
A
1646 }
1647 if ( atomSize != 0 ) {
2f2f92e4
A
1648 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
1649 pint_t atomAddr = sect->addr() + sectOffset;
d696c285
A
1650 // add if not already an atom at that address
1651 if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
1652 AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
1653 if ( !suppress )
1654 fAtoms.push_back(newAtom);
1655 fAddrToAtom[atomAddr] = newAtom->redirectTo();
1656 }
1657 }
1658 }
1659 }
1660
1661 // add all c-string anonymous atoms
1662 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1663 if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
1664 uint32_t stringLen;
2f2f92e4 1665 pint_t stringAddr;
a61fdf0a
A
1666 BaseAtom* mostAlignedEmptyString = NULL;
1667 uint32_t mostAlignedEmptyStringTrailingZeros = 0;
2f2f92e4
A
1668 std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
1669 for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
d696c285
A
1670 stringAddr = sect->addr() + sectOffset;
1671 stringLen = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
1672 // add if not already an atom at that address
1673 if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) {
1674 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
1675 if ( stringLen == 1 ) {
a61fdf0a 1676 // because of padding it may look like there are lots of empty strings, keep track of all
2f2f92e4 1677 emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
a61fdf0a
A
1678 // record empty string with greatest alignment requirement
1679 uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
1680 if ( (mostAlignedEmptyString == NULL)
1681 || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
1682 mostAlignedEmptyString = newAtom;
1683 mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
d696c285 1684 }
d696c285
A
1685 }
1686 else {
1687 fAtoms.push_back(newAtom);
1688 fAddrToAtom[stringAddr] = newAtom;
1689 }
1690 }
1691 }
a61fdf0a
A
1692 // map all uses of empty strings to the most aligned one
1693 if ( mostAlignedEmptyString != NULL ) {
1694 // make most aligned atom a real atom
1695 fAtoms.push_back(mostAlignedEmptyString);
1696 // map all other empty atoms to this one
2f2f92e4 1697 for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
a61fdf0a
A
1698 fAddrToAtom[it->first] = mostAlignedEmptyString;
1699 }
1700 }
d696c285
A
1701 }
1702 }
1703
a61fdf0a
A
1704 // sort all atoms so far by address and section
1705 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
1706
1707 //fprintf(stderr, "sorted atoms:\n");
1708 //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++)
1709 // fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
1710
d696c285
A
1711 // create atoms to cover any non-debug ranges not handled above
1712 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1713 pint_t sectionStartAddr = sect->addr();
1714 pint_t sectionEndAddr = sect->addr() + sect->size();
a61fdf0a 1715 const bool setFollowOnAtom = ! this->canScatterAtoms();
d696c285
A
1716 if ( sect->size() != 0 ) {
1717 // ignore dwarf sections. If ld every supports processing dwarf, this logic will need to change
1718 if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
1719 fDebugInfo = kDebugInfoDwarf;
1720 if ( strcmp(sect->sectname(), "__debug_info") == 0 )
1721 fDwarfDebugInfoSect = sect;
1722 else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
1723 fDwarfDebugAbbrevSect = sect;
1724 else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
1725 fDwarfDebugLineSect = sect;
1726 }
1727 else {
1728 if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
1729 throw "object file contains old DWARF debug info - rebuild with newer compiler";
1730 }
1731 uint8_t type (sect->flags() & SECTION_TYPE);
1732 switch ( type ) {
1733 case S_REGULAR:
1734 case S_ZEROFILL:
1735 case S_COALESCED:
69a49097 1736 // if there is not an atom already at the start of this section, add an anonymous one
2f2f92e4 1737 pint_t previousAtomAddr = 0;
d696c285
A
1738 BaseAtom* previousAtom = NULL;
1739 if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
d696c285 1740 BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
d696c285 1741 fAddrToAtom[sect->addr()] = newAtom;
a61fdf0a 1742 fAtoms.push_back(newAtom);
d696c285
A
1743 previousAtomAddr = sectionStartAddr;
1744 previousAtom = newAtom;
a61fdf0a 1745 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
d696c285
A
1746 }
1747 // calculate size of all atoms in this section and add follow-on references
a61fdf0a
A
1748 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
1749 BaseAtom* atom = (BaseAtom*)(*it);
2f2f92e4 1750 pint_t atomAddr = atom->getObjectAddress();
a61fdf0a 1751 if ( atom->getSectionRecord() == sect ) {
2f2f92e4 1752 //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
a61fdf0a
A
1753 if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
1754 previousAtom->setSize(atomAddr - previousAtomAddr);
1755 if ( setFollowOnAtom && (atom != previousAtom) )
1756 new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
d696c285 1757 }
a61fdf0a
A
1758 previousAtomAddr = atomAddr;
1759 previousAtom = atom;
1760 }
d696c285
A
1761 }
1762 if ( previousAtom != NULL ) {
1763 // set last atom in section
1764 previousAtom->setSize(sectionEndAddr - previousAtomAddr);
1765 }
1766 break;
1767 }
1768 }
1769 }
1770 }
1771
a61fdf0a
A
1772 // check for object file that defines no objc classes, but uses objc classes
1773 // check for dtrace provider info
1774 for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
1775 const macho_nlist<P>& sym = fSymbols[i];
1776 if ( (sym.n_type() & N_STAB) == 0 ) {
1777 if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
1778 const char* undefinedName = &fStrings[sym.n_strx()];
2f2f92e4 1779 if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
a61fdf0a
A
1780 fAppleObjc = true;
1781 }
1782 else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
1783 if ( strchr(undefinedName, '$') != NULL ) {
1784 if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
1785 // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
1786 // is extra provider info
1787 fDtraceProviderInfo.push_back(undefinedName);
d696c285
A
1788 }
1789 }
a61fdf0a 1790 }
d696c285
A
1791 }
1792 }
1793 }
a61fdf0a
A
1794
1795 // add relocation based references to sections that have atoms with pending names
1796 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1797 if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
1798 addReferencesForSection(sect);
1799 }
1800
1801 // update any anonymous atoms that need references built in order to name themselves
1802 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
1803 (*it)->resolveName();
1804 }
d696c285 1805
a61fdf0a
A
1806 // add relocation based references to other sections
1807 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1808 if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
1809 addReferencesForSection(sect);
69a49097
A
1810 }
1811
1812 // add objective-c references
1813 if ( fAppleObjc ) {
1814 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
a61fdf0a 1815 if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
69a49097 1816 for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
a61fdf0a
A
1817 AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
1818 ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
1819 if ( classRef->getFixUpOffset() == 0 ) {
1820 const char* classStr = classRef->getTargetName();
1821 if ( strncmp(classStr, "cstring=", 8) == 0 ) {
1822 const char* className;
1823 asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
1824 new Reference<A>(A::kNoFixUp, ao, className, 0);
1825 }
1826 }
69a49097
A
1827 }
1828 }
1829 }
1830 }
1831
d696c285
A
1832 // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
1833 for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
1834 AnonymousAtom<A>* localNonLazy = *it;
1835 uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
1836 pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
1837 makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
1838 }
a61fdf0a 1839
d696c285
A
1840 // add implicit direct reference from each C++ function to its eh info
1841 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1842 if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
2f2f92e4 1843 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
d696c285
A
1844 // note: this algorithm depens on the map iterator returning entries in address order
1845 if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) {
2f2f92e4 1846 pint_t ehAtomAddress = it->first;
d696c285
A
1847 BaseAtom* ehAtom = it->second;
1848 const char* ehName = ehAtom->getName();
2f2f92e4 1849 if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) ) {
d696c285 1850 makeReferenceToEH(ehName, ehAtomAddress, sect);
2f2f92e4
A
1851 // make EH symbol static so linker does not try to coalesce
1852 if ( fOptions.fForFinalLinkedImage )
1853 ehAtom->setScope(ObjectFile::Atom::scopeTranslationUnit);
1854 // if it has a reference to a LSDA, add a group reference
1855 std::vector<class ObjectFile::Reference*>& ehrefs = ehAtom->getReferences();
1856 // all FDE's have at least 2 references (to CIE and to function)
1857 if ( ehrefs.size() > 2 ) {
1858 // a third reference means there is a LSDA
1859 ObjectFile::Atom* lsdaAtom = NULL;
1860 for (std::vector<ObjectFile::Reference*>::iterator rit=ehrefs.begin(); rit != ehrefs.end(); rit++) {
1861 ObjectFile::Reference* ref = *rit;
1862 switch ( ref->getFixUpOffset() ) {
1863 case 4:
1864 case 8:
1865 // these are CIE and function references
1866 break;
1867 default:
1868 // this is LSDA reference
1869 lsdaAtom = &ref->getTarget();
1870 }
1871 }
1872 if ( lsdaAtom != NULL ) {
1873 new Reference<A>(A::kGroupSubordinate, AtomAndOffset(ehAtom), AtomAndOffset(lsdaAtom));
1874 }
1875 }
1876 }
d696c285
A
1877 }
1878 }
1879 }
1880 }
1881
a61fdf0a
A
1882 // add command line aliases
1883 for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) {
1884 BaseAtom* target = this->findAtomByName(it->realName);
1885 if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
1886 fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
1887 }
1888
1889 // add dtrace probe locations
1890 if ( fHasDTraceProbes ) {
1891 for (uint32_t i=0; i < fSymbolCount; ++i) {
1892 const macho_nlist<P>& sym = fSymbols[i];
1893 if ( (sym.n_type() & N_STAB) == 0 ) {
1894 if ( (sym.n_type() & N_TYPE) == N_SECT ) {
1895 const char* symbolName = &fStrings[sym.n_strx()];
1896 if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
1897 //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
1898 makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
1899 }
1900 }
1901 }
1902 }
1903 }
1904
1905 // turn indirect symbols int SymbolAliasAtom
1906 if ( fHaveIndirectSymbols ) {
1907 for (uint32_t i=0; i < fSymbolCount; ++i) {
1908 const macho_nlist<P>& sym = fSymbols[i];
1909 if ( (sym.n_type() & N_STAB) == 0 ) {
1910 if ( (sym.n_type() & N_TYPE) == N_INDR ) {
1911 const char* aliasName = &fStrings[sym.n_strx()];
1912 const char* targetName = &fStrings[sym.n_value()];
1913 //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
1914 BaseAtom* target = this->findAtomByName(targetName);
1915 // only currently support N_INDR based aliases to something in the same .o file
1916 if ( target != NULL ) {
1917 fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
1918 //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
1919 }
1920 }
1921 }
1922 }
1923 }
d696c285 1924
2f2f92e4 1925 //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
d696c285
A
1926 // fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
1927 //}
1928
1929 // add translation unit info from dwarf
1930 uint64_t stmtList;
1931 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
69a49097
A
1932 // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
1933 if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
1934 if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
1935 // if can't parse dwarf, warn and give up
1936 fDwarfTranslationUnitFile = NULL;
1937 fDwarfTranslationUnitDir = NULL;
2f2f92e4 1938 warning("can't parse dwarf compilation unit info in %s", this->getPath());
69a49097
A
1939 fDebugInfo = kDebugInfoNone;
1940 }
d696c285
A
1941 }
1942 }
1943
1944 // add line number info to atoms from dwarf
1945 if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
1946 // file with just data will have no __debug_line info
a61fdf0a
A
1947 if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
1948 && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
d696c285
A
1949 // validate stmt_list
1950 if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
1951 const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
1952 if ( debug_line != NULL ) {
1953 struct line_reader_data* lines = line_open(&debug_line[stmtList],
1954 fDwarfDebugLineSect->size() - stmtList, E::little_endian);
1955 struct line_info result;
1956 ObjectFile::Atom* curAtom = NULL;
1957 uint32_t curAtomOffset = 0;
1958 uint32_t curAtomAddress = 0;
1959 uint32_t curAtomSize = 0;
69a49097 1960 while ( line_next (lines, &result, line_stop_pc) ) {
a61fdf0a
A
1961 //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
1962 // curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
74cfe461
A
1963 // work around weird debug line table compiler generates if no functions in __text section
1964 if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
1965 continue;
d696c285 1966 // for performance, see if in next pc is in current atom
69a49097
A
1967 if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
1968 curAtomOffset = result.pc - curAtomAddress;
1969 }
1970 // or pc at end of current atom
1971 else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
d696c285
A
1972 curAtomOffset = result.pc - curAtomAddress;
1973 }
1974 else {
1975 // do slow look up of atom by address
1976 AtomAndOffset ao = this->findAtomAndOffset(result.pc);
1977 curAtom = ao.atom;
1978 if ( curAtom == NULL )
1979 break; // file has line info but no functions
a61fdf0a
A
1980 if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {
1981 // a one line function can be returned by line_next() as one entry with pc at end of blob
1982 // look for alt atom starting at end of previous atom
1983 uint32_t previousEnd = curAtomAddress+curAtomSize;
1984 AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
1985 if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
1986 curAtom = alt.atom;
1987 curAtomOffset = alt.offset;
1988 curAtomAddress = previousEnd - alt.offset;
1989 curAtomSize = curAtom->getSize();
1990 }
1991 else {
1992 curAtomOffset = ao.offset;
1993 curAtomAddress = result.pc - ao.offset;
1994 curAtomSize = curAtom->getSize();
1995 }
1996 }
1997 else {
1998 curAtomOffset = ao.offset;
1999 curAtomAddress = result.pc - ao.offset;
2000 curAtomSize = curAtom->getSize();
2001 }
d696c285
A
2002 }
2003 const char* filename;
2004 std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
2005 if ( pos == fDwarfIndexToFile.end() ) {
2006 filename = line_file(lines, result.file);
2007 fDwarfIndexToFile[result.file] = filename;
2008 }
2009 else {
2010 filename = pos->second;
2011 }
2012 ObjectFile::LineInfo info;
2013 info.atomOffset = curAtomOffset;
2014 info.fileName = filename;
2015 info.lineNumber = result.line;
69a49097
A
2016 //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n",
2017 // result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
d696c285 2018 ((BaseAtom*)curAtom)->addLineInfo(info);
69a49097
A
2019 if ( result.end_of_sequence ) {
2020 curAtom = NULL;
2021 }
d696c285
A
2022 }
2023 line_free(lines);
2024 }
2025 else {
2f2f92e4 2026 warning("could not parse dwarf line number info in %s", this->getPath());
d696c285
A
2027 }
2028 }
2029 }
2030 }
2031
2032 // if no dwarf, try processing stabs debugging info
2033 if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
2034 // scan symbol table for stabs entries
2035 fStabs.reserve(fSymbolCount); // reduce re-allocations
2036 BaseAtom* currentAtom = NULL;
2037 pint_t currentAtomAddress = 0;
2038 enum { start, inBeginEnd, inFun } state = start;
2039 for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
2040 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
69a49097 2041 bool useStab = true;
d696c285
A
2042 uint8_t type = sym->n_type();
2043 const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
2044 if ( (type & N_STAB) != 0 ) {
69a49097 2045 fDebugInfo = (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
d696c285
A
2046 Stab stab;
2047 stab.atom = NULL;
2048 stab.type = type;
2049 stab.other = sym->n_sect();
2050 stab.desc = sym->n_desc();
2051 stab.value = sym->n_value();
2052 stab.string = NULL;
2053 switch (state) {
2054 case start:
2055 switch (type) {
2056 case N_BNSYM:
2057 // beginning of function block
2058 state = inBeginEnd;
2059 // fall into case to lookup atom by addresss
2060 case N_LCSYM:
2061 case N_STSYM:
2062 currentAtomAddress = sym->n_value();
2063 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2064 if ( currentAtom != NULL ) {
2065 stab.atom = currentAtom;
2066 stab.string = symString;
2067 }
2068 else {
2f2f92e4 2069 fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
d696c285
A
2070 (uint64_t)sym->n_value(), path);
2071 }
2072 break;
2073 case N_SO:
2074 case N_OSO:
2075 case N_OPT:
2076 case N_LSYM:
a61fdf0a
A
2077 case N_RSYM:
2078 case N_PSYM:
d696c285
A
2079 // not associated with an atom, just copy
2080 stab.string = symString;
2081 break;
2082 case N_GSYM:
a61fdf0a 2083 {
d696c285
A
2084 // n_value field is NOT atom address ;-(
2085 // need to find atom by name match
2086 const char* colon = strchr(symString, ':');
2087 if ( colon != NULL ) {
2088 // build underscore leading name
2089 int nameLen = colon - symString;
2090 char symName[nameLen+2];
2091 strlcpy(&symName[1], symString, nameLen+1);
2092 symName[0] = '_';
2093 symName[nameLen+1] = '\0';
2094 currentAtom = findAtomByName(symName);
2095 if ( currentAtom != NULL ) {
2096 stab.atom = currentAtom;
2097 stab.string = symString;
2098 }
2099 }
74cfe461
A
2100 else {
2101 // might be a debug-note without trailing :G()
2102 currentAtom = findAtomByName(symString);
2103 if ( currentAtom != NULL ) {
2104 stab.atom = currentAtom;
2105 stab.string = symString;
2106 }
2107 }
d696c285 2108 if ( stab.atom == NULL ) {
2f2f92e4 2109 warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
69a49097 2110 useStab = false;
d696c285
A
2111 }
2112 break;
a61fdf0a 2113 }
d696c285
A
2114 case N_FUN:
2115 // old style stabs without BNSYM
2116 state = inFun;
2117 currentAtomAddress = sym->n_value();
2118 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2119 if ( currentAtom != NULL ) {
2120 stab.atom = currentAtom;
2121 stab.string = symString;
2122 }
2123 else {
2f2f92e4 2124 warning("can't find atom for stabs FUN at %08llX in %s",
d696c285
A
2125 (uint64_t)currentAtomAddress, path);
2126 }
2127 break;
2128 case N_SOL:
2129 case N_SLINE:
2130 stab.string = symString;
2131 // old stabs
2132 break;
2133 case N_BINCL:
2134 case N_EINCL:
2135 case N_EXCL:
2136 stab.string = symString;
2137 // -gfull built .o file
2138 break;
2139 default:
2f2f92e4 2140 warning("unknown stabs type 0x%X in %s", type, path);
d696c285
A
2141 }
2142 break;
2143 case inBeginEnd:
2144 stab.atom = currentAtom;
2145 switch (type) {
2146 case N_ENSYM:
2147 state = start;
2148 currentAtom = NULL;
2149 break;
2150 case N_LCSYM:
2151 case N_STSYM:
a61fdf0a 2152 {
d696c285
A
2153 BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
2154 if ( nestedAtom != NULL ) {
2155 stab.atom = nestedAtom;
2156 stab.string = symString;
2157 }
2158 else {
2f2f92e4 2159 warning("can't find atom for stabs 0x%X at %08llX in %s",
d696c285
A
2160 type, (uint64_t)sym->n_value(), path);
2161 }
2162 break;
a61fdf0a 2163 }
d696c285
A
2164 case N_LBRAC:
2165 case N_RBRAC:
2166 case N_SLINE:
2167 // adjust value to be offset in atom
2168 stab.value -= currentAtomAddress;
2169 default:
2170 stab.string = symString;
2171 break;
2172 }
2173 break;
2174 case inFun:
2175 switch (type) {
2176 case N_FUN:
2177 if ( sym->n_sect() != 0 ) {
2178 // found another start stab, must be really old stabs...
2179 currentAtomAddress = sym->n_value();
2180 currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
2181 if ( currentAtom != NULL ) {
2182 stab.atom = currentAtom;
2183 stab.string = symString;
2184 }
2185 else {
2f2f92e4 2186 warning("can't find atom for stabs FUN at %08llX in %s",
d696c285
A
2187 (uint64_t)currentAtomAddress, path);
2188 }
2189 }
2190 else {
2191 // found ending stab, switch back to start state
2192 stab.string = symString;
2193 stab.atom = currentAtom;
2194 state = start;
2195 currentAtom = NULL;
2196 }
2197 break;
2198 case N_LBRAC:
2199 case N_RBRAC:
2200 case N_SLINE:
2201 // adjust value to be offset in atom
2202 stab.value -= currentAtomAddress;
2203 stab.atom = currentAtom;
2204 break;
2205 case N_SO:
2206 stab.string = symString;
2207 state = start;
2208 break;
2209 default:
2210 stab.atom = currentAtom;
2211 stab.string = symString;
2212 break;
2213 }
2214 break;
2215 }
2216 // add to list of stabs for this .o file
69a49097
A
2217 if ( useStab )
2218 fStabs.push_back(stab);
d696c285
A
2219 }
2220 }
2221 }
2222
d696c285
A
2223#if 0
2224 // special case precompiled header .o file (which has no content) to have one empty atom
2225 if ( fAtoms.size() == 0 ) {
2226 int pathLen = strlen(path);
2227 if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
2228 ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
2229 //phony->fSynthesizedName = ".gch.o";
2230 fAtoms.push_back(phony);
2231 }
2232 }
2233#endif
a61fdf0a
A
2234
2235 // sort all atoms by address
2236 std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
2237
2238 // set ordinal and sort references in each atom
2239 uint32_t index = fOrdinalBase;
2240 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
2241 BaseAtom* atom = (BaseAtom*)(*it);
2242 atom->setOrdinal(index++);
2243 atom->sortReferences();
2244 }
2245
2246}
2247
2248
2249template <>
2250void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
2251{
2252 switch (cpusubtype) {
2253 case CPU_SUBTYPE_POWERPC_ALL:
a61fdf0a 2254 case CPU_SUBTYPE_POWERPC_750:
a61fdf0a
A
2255 case CPU_SUBTYPE_POWERPC_7400:
2256 case CPU_SUBTYPE_POWERPC_7450:
a61fdf0a 2257 case CPU_SUBTYPE_POWERPC_970:
2f2f92e4 2258 fCpuConstraint = cpusubtype;
a61fdf0a
A
2259 break;
2260 default:
2f2f92e4
A
2261 warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
2262 fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
2263 break;
a61fdf0a
A
2264 }
2265}
2266
2f2f92e4
A
2267template <>
2268void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
2269{
2270 switch (cpusubtype) {
2271 case CPU_SUBTYPE_ARM_ALL:
2272 case CPU_SUBTYPE_ARM_V4T:
2273 case CPU_SUBTYPE_ARM_V5TEJ:
2274 case CPU_SUBTYPE_ARM_V6:
2275 case CPU_SUBTYPE_ARM_XSCALE:
77cc3118 2276 case CPU_SUBTYPE_ARM_V7:
2f2f92e4
A
2277 fCpuConstraint = cpusubtype;
2278 break;
2279 default:
2280 warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
2281 fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
2282 break;
2283 }
2284}
a61fdf0a
A
2285
2286template <typename A>
2287void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
2288{
2289 // no cpu sub types for this architecture
2290}
2291
2f2f92e4
A
2292template <>
2293uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
2294{
2295 switch ( previous ) {
2296 case CPU_SUBTYPE_POWERPC_ALL:
2297 return fCpuConstraint;
2298 break;
2299 case CPU_SUBTYPE_POWERPC_750:
2300 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
2301 fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
2302 fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
2303 return fCpuConstraint;
2304 break;
2305 case CPU_SUBTYPE_POWERPC_7400:
2306 case CPU_SUBTYPE_POWERPC_7450:
2307 if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
2308 return fCpuConstraint;
2309 break;
2310 case CPU_SUBTYPE_POWERPC_970:
2311 // G5 can run everything
2312 break;
2313 default:
2314 throw "Unhandled PPC cpu subtype!";
2315 break;
2316 }
2317 return previous;
2318}
2319
2320
2321
2322template <>
2323uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
2324{
2325 switch (previous) {
2326 case CPU_SUBTYPE_ARM_ALL:
2327 return fCpuConstraint;
2328 break;
2329 case CPU_SUBTYPE_ARM_V5TEJ:
77cc3118 2330 // v6, v7, and xscale are more constrained than previous file (v5), so use it
2f2f92e4 2331 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
77cc3118 2332 || (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
2f2f92e4
A
2333 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
2334 return fCpuConstraint;
2335 break;
2336 case CPU_SUBTYPE_ARM_V4T:
77cc3118
A
2337 // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
2338 if ( (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
2339 || (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
2f2f92e4
A
2340 || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
2341 || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
2342 return fCpuConstraint;
2343 break;
2344 case CPU_SUBTYPE_ARM_V6:
77cc3118 2345 // v6 can run everything except xscale and v7
2f2f92e4
A
2346 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
2347 throw "can't mix xscale and v6 code";
77cc3118
A
2348 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
2349 return fCpuConstraint;
2f2f92e4
A
2350 break;
2351 case CPU_SUBTYPE_ARM_XSCALE:
77cc3118 2352 // xscale can run everything except v6 and v7
2f2f92e4
A
2353 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
2354 throw "can't mix xscale and v6 code";
77cc3118
A
2355 if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
2356 throw "can't mix xscale and v7 code";
2357 break;
2358 case CPU_SUBTYPE_ARM_V7:
2359 // v7 can run everything except xscale
2360 if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
2361 throw "can't mix xscale and v7 code";
2f2f92e4
A
2362 break;
2363 default:
2364 throw "Unhandled ARM cpu subtype!";
2365 }
2366 return previous;
2367}
2368
2369template <typename A>
2370uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
2371{
2372 // no cpu sub types for this architecture
2373 return current;
2374}
2375
a61fdf0a
A
2376template <typename A>
2377void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
2378{
2379 // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
2380 // a matching provider name, add a by-name kDtraceTypeReference at probe site
2381 const char* dollar = strchr(providerName, '$');
2382 if ( dollar != NULL ) {
2383 int providerNameLen = dollar-providerName+1;
2384 for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
2385 const char* typeDollar = strchr(*it, '$');
2386 if ( typeDollar != NULL ) {
2387 if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
2388 makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
2389 }
2390 }
2391 }
2392 }
d696c285
A
2393}
2394
a61fdf0a 2395
69a49097
A
2396template <>
2397void Reader<x86_64>::validSectionType(uint8_t type)
2398{
2399 switch ( type ) {
2400 case S_SYMBOL_STUBS:
2401 throw "symbol_stub sections not valid in x86_64 object files";
2402 case S_LAZY_SYMBOL_POINTERS:
2403 throw "lazy pointer sections not valid in x86_64 object files";
2404 case S_NON_LAZY_SYMBOL_POINTERS:
2405 throw "non lazy pointer sections not valid in x86_64 object files";
2406 }
2407}
d696c285
A
2408
2409template <typename A>
2410void Reader<A>::validSectionType(uint8_t type)
2411{
2412}
2413
2414template <typename A>
2415bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
2416{
2417 if ( fDebugInfo == kDebugInfoDwarf ) {
2418 *dir = fDwarfTranslationUnitDir;
2419 *name = fDwarfTranslationUnitFile;
a61fdf0a 2420 return (fDwarfTranslationUnitFile != NULL);
d696c285
A
2421 }
2422 return false;
2423}
2424
2425template <typename A>
2426BaseAtom* Reader<A>::findAtomByName(const char* name)
2427{
2428 // first search the more important atoms
2f2f92e4 2429 for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
d696c285
A
2430 const char* atomName = it->second->getName();
2431 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
2432 return it->second;
2433 }
2434 }
2435 // try all atoms, because this might have been a tentative definition
a61fdf0a 2436 for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
d696c285
A
2437 BaseAtom* atom = (BaseAtom*)(*it);
2438 const char* atomName = atom->getName();
2439 if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
2440 return atom;
2441 }
2442 }
2443 return NULL;
2444}
2445
2446template <typename A>
2f2f92e4 2447Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
d696c285
A
2448{
2449 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
2450}
2451
2452template <typename A>
2f2f92e4 2453Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
d696c285
A
2454{
2455 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
2456}
2457
2458template <typename A>
2f2f92e4 2459Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
d696c285
A
2460{
2461 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
2462}
2463
2464template <typename A>
2f2f92e4 2465Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
d696c285
A
2466{
2467 return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
2468}
2469
2470template <typename A>
2f2f92e4 2471Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
d696c285
A
2472{
2473 return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
2474}
2475
2476template <typename A>
2477Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
2478{
2479 // add a direct reference from function atom to its eh frame atom
2480 const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
2481 int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8])); // offset 8 in eh info is delta to function
2f2f92e4
A
2482 pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
2483 return makeReference(A::kGroupSubordinate, funcAddr, ehAtomAddress);
d696c285
A
2484}
2485
2486
69a49097 2487template <>
2f2f92e4 2488Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
69a49097
A
2489{
2490 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
2491 // instead check scope of target
2492 BaseAtom* target = findAtomByName(toName);
2493 if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
2494 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
2495 else
2496 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
2497}
2498
2499template <>
2f2f92e4 2500Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
69a49097
A
2501{
2502 // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
2503 // instead check scope of target
a61fdf0a
A
2504 const char* symbolName = &fStrings[toSymbol->n_strx()];
2505 if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) )
69a49097
A
2506 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset));
2507 else
a61fdf0a 2508 return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
69a49097
A
2509}
2510
2511
2512template <>
2513Reference<x86_64>* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
2514{
2515 // add a direct reference from function atom to its eh frame atom
2516 // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
2517 uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
2518 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
2519 const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
2520 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
2521 if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
2f2f92e4
A
2522 pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
2523 return makeReference(x86_64::kGroupSubordinate, funcAddr, ehAtomAddress);
69a49097
A
2524 }
2525 }
2f2f92e4 2526 warning("can't find matching function for eh symbol %s", ehName);
69a49097
A
2527 return NULL;
2528}
d696c285 2529
86b84c30 2530
d696c285 2531template <typename A>
2f2f92e4 2532AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
d696c285
A
2533{
2534 // STL has no built-in for "find largest key that is same or less than"
2f2f92e4
A
2535 typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
2536 // if no atoms up to this address return none found
2537 if ( it == fAddrToAtom.begin() )
2538 return AtomAndOffset(NULL);
2539 // otherwise upper_bound gets us next key, so we back up one
2540 --it;
d696c285
A
2541 AtomAndOffset result;
2542 result.atom = it->second;
2543 result.offset = addr - it->first;
2f2f92e4
A
2544 //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
2545 // (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
d696c285
A
2546 return result;
2547}
2548
2549// "scattered" relocations enable you to offset into an atom past the end of it
2550// baseAddr is the address of the target atom,
2551// realAddr is the points into it
2552template <typename A>
2f2f92e4 2553AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
d696c285 2554{
2f2f92e4 2555 typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
d696c285
A
2556 if ( it != fAddrToAtom.end() ) {
2557 AtomAndOffset result;
2558 result.atom = it->second;
2559 result.offset = realAddr - it->first;
2560 //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
2561 return result;
2562 }
2563 // getting here means we have a scattered relocation to an address without a label
2564 // we should never get here...
2565 // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
2566 return findAtomAndOffset(realAddr);
2567}
2568
2569
2570/* Skip over a LEB128 value (signed or unsigned). */
2571static void
2572skip_leb128 (const uint8_t ** offset, const uint8_t * end)
2573{
2574 while (*offset != end && **offset >= 0x80)
2575 (*offset)++;
2576 if (*offset != end)
2577 (*offset)++;
2578}
2579
2580/* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
2581 or error. On overflow, skip past the rest of the uleb128. */
2582static uint64_t
2583read_uleb128 (const uint8_t ** offset, const uint8_t * end)
2584{
2585 uint64_t result = 0;
2586 int bit = 0;
2587
2588 do {
2589 uint64_t b;
2590
2591 if (*offset == end)
2592 return (uint64_t) -1;
2593
2594 b = **offset & 0x7f;
2595
2596 if (bit >= 64 || b << bit >> bit != b)
2597 result = (uint64_t) -1;
2598 else
2599 result |= b << bit, bit += 7;
2600 } while (*(*offset)++ >= 0x80);
2601 return result;
2602}
2603
2604
2605/* Skip over a DWARF attribute of form FORM. */
2606template <typename A>
2607bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
2608 uint8_t addr_size, bool dwarf64)
2609{
2610 int64_t sz=0;
2611
2612 switch (form)
2613 {
2614 case DW_FORM_addr:
2615 sz = addr_size;
2616 break;
2617
2618 case DW_FORM_block2:
2619 if (end - *offset < 2)
2620 return false;
2621 sz = 2 + A::P::E::get16(*(uint16_t*)offset);
2622 break;
2623
2624 case DW_FORM_block4:
2625 if (end - *offset < 4)
2626 return false;
2627 sz = 2 + A::P::E::get32(*(uint32_t*)offset);
2628 break;
2629
2630 case DW_FORM_data2:
2631 case DW_FORM_ref2:
2632 sz = 2;
2633 break;
2634
2635 case DW_FORM_data4:
2636 case DW_FORM_ref4:
2637 sz = 4;
2638 break;
2639
2640 case DW_FORM_data8:
2641 case DW_FORM_ref8:
2642 sz = 8;
2643 break;
2644
2645 case DW_FORM_string:
2646 while (*offset != end && **offset)
2647 ++*offset;
2648 case DW_FORM_data1:
2649 case DW_FORM_flag:
2650 case DW_FORM_ref1:
2651 sz = 1;
2652 break;
2653
2654 case DW_FORM_block:
2655 sz = read_uleb128 (offset, end);
2656 break;
2657
2658 case DW_FORM_block1:
2659 if (*offset == end)
2660 return false;
2661 sz = 1 + **offset;
2662 break;
2663
2664 case DW_FORM_sdata:
2665 case DW_FORM_udata:
2666 case DW_FORM_ref_udata:
2667 skip_leb128 (offset, end);
2668 return true;
2669
2670 case DW_FORM_strp:
2671 case DW_FORM_ref_addr:
2672 sz = dwarf64 ? 8 : 4;
2673 break;
2674
2675 default:
2676 return false;
2677 }
2678 if (end - *offset < sz)
2679 return false;
2680 *offset += sz;
2681 return true;
2682}
2683
2684// Look at the compilation unit DIE and determine
2685// its NAME, compilation directory (in COMP_DIR) and its
2686// line number information offset (in STMT_LIST). NAME and COMP_DIR
2687// may be NULL (especially COMP_DIR) if they are not in the .o file;
2688// STMT_LIST will be (uint64_t) -1.
2689//
2690// At present this assumes that there's only one compilation unit DIE.
2691//
2692template <typename A>
2693bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
2694 uint64_t *stmt_list)
2695{
2696 const uint8_t * debug_info;
2697 const uint8_t * debug_abbrev;
2698 const uint8_t * di;
2699 const uint8_t * da;
2700 const uint8_t * end;
2701 const uint8_t * enda;
2702 uint64_t sz;
2703 uint16_t vers;
2704 uint64_t abbrev_base;
2705 uint64_t abbrev;
2706 uint8_t address_size;
2707 bool dwarf64;
2708
2709 *name = NULL;
2710 *comp_dir = NULL;
2711 *stmt_list = (uint64_t) -1;
2712
2713 if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
2714 return false;
2715
2716 debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
2717 debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
2718 di = debug_info;
2719
2720 if (fDwarfDebugInfoSect->size() < 12)
2721 /* Too small to be a real debug_info section. */
2722 return false;
2723 sz = A::P::E::get32(*(uint32_t*)di);
2724 di += 4;
2725 dwarf64 = sz == 0xffffffff;
2726 if (dwarf64)
2727 sz = A::P::E::get64(*(uint64_t*)di), di += 8;
2728 else if (sz > 0xffffff00)
2729 /* Unknown dwarf format. */
2730 return false;
2731
2732 /* Verify claimed size. */
2733 if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
2734 return false;
2735
2736 vers = A::P::E::get16(*(uint16_t*)di);
2737 if (vers < 2 || vers > 3)
2738 /* DWARF version wrong for this code.
2739 Chances are we could continue anyway, but we don't know for sure. */
2740 return false;
2741 di += 2;
2742
2743 /* Find the debug_abbrev section. */
2744 abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
2745 di += dwarf64 ? 8 : 4;
2746
2747 if (abbrev_base > fDwarfDebugAbbrevSect->size())
2748 return false;
2749 da = debug_abbrev + abbrev_base;
2750 enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
2751
2752 address_size = *di++;
2753
2754 /* Find the abbrev number we're looking for. */
2755 end = di + sz;
2756 abbrev = read_uleb128 (&di, end);
2757 if (abbrev == (uint64_t) -1)
2758 return false;
2759
2760 /* Skip through the debug_abbrev section looking for that abbrev. */
2761 for (;;)
2762 {
2763 uint64_t this_abbrev = read_uleb128 (&da, enda);
2764 uint64_t attr;
2765
2766 if (this_abbrev == abbrev)
2767 /* This is almost always taken. */
2768 break;
2769 skip_leb128 (&da, enda); /* Skip the tag. */
2770 if (da == enda)
2771 return false;
2772 da++; /* Skip the DW_CHILDREN_* value. */
2773
2774 do {
2775 attr = read_uleb128 (&da, enda);
2776 skip_leb128 (&da, enda);
2777 } while (attr != 0 && attr != (uint64_t) -1);
2778 if (attr != 0)
2779 return false;
2780 }
2781
2782 /* Check that the abbrev is one for a DW_TAG_compile_unit. */
2783 if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
2784 return false;
2785 if (da == enda)
2786 return false;
2787 da++; /* Skip the DW_CHILDREN_* value. */
2788
2789 /* Now, go through the DIE looking for DW_AT_name,
2790 DW_AT_comp_dir, and DW_AT_stmt_list. */
2791 for (;;)
2792 {
2793 uint64_t attr = read_uleb128 (&da, enda);
2794 uint64_t form = read_uleb128 (&da, enda);
2795
2796 if (attr == (uint64_t) -1)
2797 return false;
2798 else if (attr == 0)
2799 return true;
2800
2801 if (form == DW_FORM_indirect)
2802 form = read_uleb128 (&di, end);
2803
2804 if (attr == DW_AT_name && form == DW_FORM_string)
2805 *name = (const char *) di;
2806 else if (attr == DW_AT_comp_dir && form == DW_FORM_string)
2807 *comp_dir = (const char *) di;
2808 /* Really we should support DW_FORM_strp here, too, but
2809 there's usually no reason for the producer to use that form
2810 for the DW_AT_name and DW_AT_comp_dir attributes. */
2811 else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
2812 *stmt_list = A::P::E::get32(*(uint32_t*)di);
2813 else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
2814 *stmt_list = A::P::E::get64(*(uint64_t*)di);
2815 if (! skip_form (&di, end, form, address_size, dwarf64))
2816 return false;
2817 }
2818}
2819
2820template <typename A>
2821const char* Reader<A>::assureFullPath(const char* path)
2822{
2823 if ( path[0] == '/' )
2824 return path;
2825 char cwdbuff[MAXPATHLEN];
2826 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
2827 char* result;
2828 asprintf(&result, "%s/%s", cwdbuff, path);
2829 if ( result != NULL )
2830 return result;
2831 }
2832 return path;
2833}
2834
2835
2836//
2837//
2838// To implement architecture xxx, you must write template specializations for the following six methods:
2839// Reader<xxx>::validFile()
2840// Reader<xxx>::addRelocReference()
2841// Reference<xxx>::getDescription()
2842//
2843//
2844
2845
2846template <>
2847bool Reader<ppc>::validFile(const uint8_t* fileContent)
2848{
2849 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2850 if ( header->magic() != MH_MAGIC )
2851 return false;
2852 if ( header->cputype() != CPU_TYPE_POWERPC )
2853 return false;
2854 if ( header->filetype() != MH_OBJECT )
2855 return false;
2856 return true;
2857}
2858
2859template <>
2860bool Reader<ppc64>::validFile(const uint8_t* fileContent)
2861{
2862 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2863 if ( header->magic() != MH_MAGIC_64 )
2864 return false;
2865 if ( header->cputype() != CPU_TYPE_POWERPC64 )
2866 return false;
2867 if ( header->filetype() != MH_OBJECT )
2868 return false;
2869 return true;
2870}
2871
2872template <>
2873bool Reader<x86>::validFile(const uint8_t* fileContent)
2874{
2875 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2876 if ( header->magic() != MH_MAGIC )
2877 return false;
2878 if ( header->cputype() != CPU_TYPE_I386 )
2879 return false;
2880 if ( header->filetype() != MH_OBJECT )
2881 return false;
2882 return true;
2883}
2884
69a49097
A
2885template <>
2886bool Reader<x86_64>::validFile(const uint8_t* fileContent)
2887{
2888 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2889 if ( header->magic() != MH_MAGIC_64 )
2890 return false;
2891 if ( header->cputype() != CPU_TYPE_X86_64 )
2892 return false;
2893 if ( header->filetype() != MH_OBJECT )
2894 return false;
2895 return true;
2896}
d696c285 2897
2f2f92e4
A
2898template <>
2899bool Reader<arm>::validFile(const uint8_t* fileContent)
2900{
2901 const macho_header<P>* header = (const macho_header<P>*)fileContent;
2902 if ( header->magic() != MH_MAGIC )
2903 return false;
2904 if ( header->cputype() != CPU_TYPE_ARM )
2905 return false;
2906 if ( header->filetype() != MH_OBJECT )
2907 return false;
2908 return true;
2909}
d696c285
A
2910
2911template <typename A>
2912bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
2913{
2914 return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
2915}
2916
2917template <>
2918bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
2919{
2920 return addRelocReference_powerpc(sect, reloc);
2921}
2922
2923template <>
2924bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
2925{
2926 return addRelocReference_powerpc(sect, reloc);
2927}
2928
2929
2930//
2931// ppc and ppc64 both use the same relocations, so process them in one common routine
2932//
2933template <typename A>
2934bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
2935 const macho_relocation_info<typename A::P>* reloc)
2936{
2937 uint32_t srcAddr;
2938 uint32_t dstAddr;
2939 uint32_t* fixUpPtr;
2940 int32_t displacement = 0;
2941 uint32_t instruction = 0;
2942 uint32_t offsetInTarget;
2943 int16_t lowBits;
2944 bool result = false;
2945 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2946 const macho_relocation_info<P>* nextReloc = &reloc[1];
2947 const char* targetName = NULL;
2948 bool weakImport = false;
2949 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
2950 if ( reloc->r_type() != PPC_RELOC_PAIR )
2951 instruction = BigEndian::get32(*fixUpPtr);
2952 srcAddr = sect->addr() + reloc->r_address();
2953 if ( reloc->r_extern() ) {
2954 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2955 targetName = &fStrings[targetSymbol->n_strx()];
2956 weakImport = this->isWeakImportSymbol(targetSymbol);
2957 }
2958 switch ( reloc->r_type() ) {
2959 case PPC_RELOC_BR24:
2960 {
2961 if ( (instruction & 0x4C000000) == 0x48000000 ) {
2962 displacement = (instruction & 0x03FFFFFC);
2963 if ( (displacement & 0x02000000) != 0 )
2964 displacement |= 0xFC000000;
2965 }
2966 else {
2967 printf("bad instruction for BR24 reloc");
2968 }
2969 if ( reloc->r_extern() ) {
2970 offsetInTarget = srcAddr + displacement;
a61fdf0a
A
2971 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
2972 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
2973 addDtraceExtraInfos(srcAddr, &targetName[16]);
2974 }
2975 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
2976 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
2977 addDtraceExtraInfos(srcAddr, &targetName[20]);
2978 }
2979 else if ( weakImport )
d696c285
A
2980 makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
2981 else
2982 makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
2983 }
2984 else {
2985 dstAddr = srcAddr + displacement;
2986 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
2987 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
a61fdf0a
A
2988 targetName = atom->getName();
2989 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
2990 makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
2991 addDtraceExtraInfos(srcAddr, &targetName[16]);
2992 }
2993 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
2994 makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
2995 addDtraceExtraInfos(srcAddr, &targetName[20]);
2996 }
2997 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
d696c285
A
2998 && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
2999 makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
3000 else
3001 makeReference(A::kBranch24, srcAddr, dstAddr);
3002 }
3003 }
3004 break;
3005 case PPC_RELOC_BR14:
3006 {
3007 displacement = (instruction & 0x0000FFFC);
3008 if ( (displacement & 0x00008000) != 0 )
3009 displacement |= 0xFFFF0000;
3010 if ( reloc->r_extern() ) {
3011 offsetInTarget = srcAddr + displacement;
3012 makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
3013 }
3014 else {
3015 dstAddr = srcAddr + displacement;
3016 makeReference(A::kBranch14, srcAddr, dstAddr);
3017 }
3018 }
3019 break;
3020 case PPC_RELOC_PAIR:
3021 // skip, processed by a previous look ahead
3022 break;
3023 case PPC_RELOC_LO16:
3024 {
3025 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2f2f92e4 3026 warning("PPC_RELOC_LO16 missing following pair");
d696c285
A
3027 break;
3028 }
3029 result = true;
3030 lowBits = (instruction & 0xFFFF);
3031 if ( reloc->r_extern() ) {
3032 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3033 makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
3034 }
3035 else {
3036 dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
a61fdf0a
A
3037 if ( reloc->r_symbolnum() == R_ABS ) {
3038 // find absolute symbol that corresponds to pointerValue
2f2f92e4 3039 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
3040 if ( pos != fAddrToAbsoluteAtom.end() )
3041 makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
3042 else
3043 makeReference(A::kAbsLow16, srcAddr, dstAddr);
3044 }
3045 else {
3046 makeReference(A::kAbsLow16, srcAddr, dstAddr);
3047 }
d696c285
A
3048 }
3049 }
3050 break;
3051 case PPC_RELOC_LO14:
3052 {
3053 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2f2f92e4 3054 warning("PPC_RELOC_LO14 missing following pair");
d696c285
A
3055 break;
3056 }
3057 result = true;
3058 lowBits = (instruction & 0xFFFC);
3059 if ( reloc->r_extern() ) {
3060 offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3061 makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
3062 }
3063 else {
3064 dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
a61fdf0a
A
3065 if ( reloc->r_symbolnum() == R_ABS ) {
3066 // find absolute symbol that corresponds to pointerValue
2f2f92e4 3067 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
3068 if ( pos != fAddrToAbsoluteAtom.end() )
3069 makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
3070 else
3071 makeReference(A::kAbsLow14, srcAddr, dstAddr);
3072 }
3073 else {
3074 makeReference(A::kAbsLow14, srcAddr, dstAddr);
3075 }
d696c285
A
3076 }
3077 }
3078 break;
3079 case PPC_RELOC_HI16:
3080 {
3081 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2f2f92e4 3082 warning("PPC_RELOC_HI16 missing following pair");
d696c285
A
3083 break;
3084 }
3085 result = true;
3086 if ( reloc->r_extern() ) {
3087 offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
3088 makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
3089 }
3090 else {
3091 dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
a61fdf0a
A
3092 if ( reloc->r_symbolnum() == R_ABS ) {
3093 // find absolute symbol that corresponds to pointerValue
2f2f92e4 3094 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
3095 if ( pos != fAddrToAbsoluteAtom.end() )
3096 makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
3097 else
3098 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
3099 }
3100 else {
3101 makeReference(A::kAbsHigh16, srcAddr, dstAddr);
3102 }
d696c285
A
3103 }
3104 }
3105 break;
3106 case PPC_RELOC_HA16:
3107 {
3108 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2f2f92e4 3109 warning("PPC_RELOC_HA16 missing following pair");
d696c285
A
3110 break;
3111 }
3112 result = true;
3113 lowBits = (nextReloc->r_address() & 0x0000FFFF);
3114 if ( reloc->r_extern() ) {
3115 offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3116 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
3117 }
3118 else {
3119 dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
a61fdf0a
A
3120 if ( reloc->r_symbolnum() == R_ABS ) {
3121 // find absolute symbol that corresponds to pointerValue
2f2f92e4 3122 typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
a61fdf0a
A
3123 if ( pos != fAddrToAbsoluteAtom.end() )
3124 makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
3125 else
3126 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
3127 }
3128 else {
3129 makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
3130 }
d696c285
A
3131 }
3132 }
3133 break;
3134 case PPC_RELOC_VANILLA:
3135 {
3136 pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
3137 if ( reloc->r_extern() ) {
3138 if ( weakImport )
3139 makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
3140 else
3141 makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
3142 }
3143 else {
3144 makeReference(A::kPointer, srcAddr, pointerValue);
3145 }
3146 }
3147 break;
3148 case PPC_RELOC_JBSR:
a61fdf0a 3149 // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target
d696c285 3150 if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
2f2f92e4 3151 warning("PPC_RELOC_JBSR missing following pair");
d696c285
A
3152 break;
3153 }
2f2f92e4 3154 fHasLongBranchStubs = true;
d696c285
A
3155 result = true;
3156 makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
a61fdf0a
A
3157 if ( (instruction & 0x4C000000) == 0x48000000 ) {
3158 displacement = (instruction & 0x03FFFFFC);
3159 if ( (displacement & 0x02000000) != 0 )
3160 displacement |= 0xFC000000;
3161 }
3162 else {
3163 fprintf(stderr, "bad instruction for BR24 reloc");
3164 }
3165 if ( reloc->r_extern() ) {
3166 fprintf(stderr, "PPC_RELOC_JBSR should not be using an external relocation");
3167 }
d696c285
A
3168 break;
3169 default:
2f2f92e4 3170 warning("unknown relocation type %d", reloc->r_type());
d696c285
A
3171 }
3172 }
3173 else {
3174 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3175 srcAddr = sect->addr() + sreloc->r_address();
3176 dstAddr = sreloc->r_value();
3177 uint32_t betterDstAddr;
3178 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3179 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3180 const macho_relocation_info<P>* nextReloc = &reloc[1];
3181 // file format allows pair to be scattered or not
3182 bool nextRelocIsPair = false;
3183 uint32_t nextRelocAddress = 0;
3184 uint32_t nextRelocValue = 0;
3185 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
3186 if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
3187 nextRelocIsPair = true;
3188 nextRelocAddress = nextReloc->r_address();
3189 result = true;
3190 }
3191 }
3192 else {
3193 if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
3194 nextRelocIsPair = true;
3195 nextRelocAddress = nextSReloc->r_address();
3196 nextRelocValue = nextSReloc->r_value();
3197 result = true;
3198 }
3199 }
3200 switch (sreloc->r_type()) {
3201 case PPC_RELOC_VANILLA:
3202 {
3203 betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
3204 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
3205 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3206 makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
3207 }
3208 break;
3209 case PPC_RELOC_BR14:
3210 {
3211 instruction = BigEndian::get32(*fixUpPtr);
3212 displacement = (instruction & 0x0000FFFC);
3213 if ( (displacement & 0x00008000) != 0 )
3214 displacement |= 0xFFFF0000;
3215 betterDstAddr = srcAddr+displacement;
3216 //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n", betterDstAddr, srcAddr, displacement);
3217 makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
3218 }
3219 break;
3220 case PPC_RELOC_BR24:
3221 {
3222 instruction = BigEndian::get32(*fixUpPtr);
3223 if ( (instruction & 0x4C000000) == 0x48000000 ) {
3224 displacement = (instruction & 0x03FFFFFC);
3225 if ( (displacement & 0x02000000) != 0 )
3226 displacement |= 0xFC000000;
3227 betterDstAddr = srcAddr+displacement;
3228 makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
3229 }
3230 }
3231 break;
3232 case PPC_RELOC_LO16_SECTDIFF:
3233 {
3234 if ( ! nextRelocIsPair ) {
2f2f92e4 3235 warning("PPC_RELOC_LO16_SECTDIFF missing following PAIR");
d696c285
A
3236 break;
3237 }
3238 instruction = BigEndian::get32(*fixUpPtr);
3239 lowBits = (instruction & 0xFFFF);
3240 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
3241 makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3242 }
3243 break;
3244 case PPC_RELOC_LO14_SECTDIFF:
3245 {
3246 if ( ! nextRelocIsPair ) {
2f2f92e4 3247 warning("PPC_RELOC_LO14_SECTDIFF missing following PAIR");
d696c285
A
3248 break;
3249 }
3250 instruction = BigEndian::get32(*fixUpPtr);
3251 lowBits = (instruction & 0xFFFC);
3252 displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
74cfe461 3253 makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
d696c285
A
3254 }
3255 break;
3256 case PPC_RELOC_HA16_SECTDIFF:
3257 {
3258 if ( ! nextRelocIsPair ) {
2f2f92e4 3259 warning("PPC_RELOC_HA16_SECTDIFF missing following PAIR");
d696c285
A
3260 break;
3261 }
3262 instruction = BigEndian::get32(*fixUpPtr);
3263 lowBits = (nextRelocAddress & 0x0000FFFF);
3264 displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
3265 makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
3266 }
3267 break;
3268 case PPC_RELOC_LO14:
3269 {
3270 if ( ! nextRelocIsPair ) {
2f2f92e4 3271 warning("PPC_RELOC_LO14 missing following PAIR");
d696c285
A
3272 break;
3273 }
3274 instruction = BigEndian::get32(*fixUpPtr);
3275 lowBits = (instruction & 0xFFFC);
3276 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3277 makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
3278 }
3279 break;
3280 case PPC_RELOC_LO16:
3281 {
3282 if ( ! nextRelocIsPair ) {
2f2f92e4 3283 warning("PPC_RELOC_LO16 missing following PAIR");
d696c285
A
3284 break;
3285 }
3286 instruction = BigEndian::get32(*fixUpPtr);
3287 lowBits = (instruction & 0xFFFF);
3288 betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
3289 makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
3290 }
3291 break;
3292 case PPC_RELOC_HA16:
3293 {
3294 if ( ! nextRelocIsPair ) {
2f2f92e4 3295 warning("PPC_RELOC_HA16 missing following PAIR");
d696c285
A
3296 break;
3297 }
3298 instruction = BigEndian::get32(*fixUpPtr);
3299 lowBits = (nextRelocAddress & 0xFFFF);
3300 betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
3301 makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
3302 }
3303 break;
2f2f92e4
A
3304 case PPC_RELOC_HI16:
3305 {
3306 if ( ! nextRelocIsPair ) {
3307 warning("PPC_RELOC_HI16 missing following PAIR");
3308 break;
3309 }
3310 instruction = BigEndian::get32(*fixUpPtr);
3311 lowBits = (nextRelocAddress & 0xFFFF);
3312 betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
3313 makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
3314 }
3315 break;
d696c285
A
3316 case PPC_RELOC_SECTDIFF:
3317 case PPC_RELOC_LOCAL_SECTDIFF:
3318 {
3319 if ( ! nextRelocIsPair ) {
2f2f92e4 3320 warning("PPC_RELOC_SECTDIFF missing following pair");
d696c285
A
3321 break;
3322 }
2f2f92e4
A
3323 Kinds kind = A::kPointerDiff32;;
3324 uint32_t contentAddr = 0;
a61fdf0a
A
3325 switch ( sreloc->r_length() ) {
3326 case 0:
2f2f92e4 3327 throw "bad diff relocations r_length (0) for ppc architecture";
a61fdf0a 3328 case 1:
2f2f92e4
A
3329 kind = A::kPointerDiff16;
3330 contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
a61fdf0a
A
3331 break;
3332 case 2:
2f2f92e4
A
3333 kind = A::kPointerDiff32;
3334 contentAddr = BigEndian::get32(*fixUpPtr);
a61fdf0a
A
3335 break;
3336 case 3:
2f2f92e4
A
3337 kind = A::kPointerDiff64;
3338 contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
a61fdf0a
A
3339 break;
3340 }
2f2f92e4
A
3341 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
3342 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
3343 AtomAndOffset toao = findAtomAndOffset(dstAddr);
3344 // check for addend encoded in the section content
3345 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
3346 // dstAddr, nextRelocValue, contentAddr);
3347 if ( (dstAddr - nextRelocValue) != contentAddr ) {
3348 if ( toao.atom == srcao.atom )
3349 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3350 else if ( fromao.atom == srcao.atom )
3351 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3352 else
3353 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
3354 }
3355 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
3356 // srcao.atom->getDisplayName(), srcao.offset,
3357 // fromao.atom->getDisplayName(), fromao.offset,
3358 // toao.atom->getDisplayName(), toao.offset);
3359 new Reference<A>(kind, srcao, fromao, toao);
d696c285
A
3360 }
3361 break;
3362 case PPC_RELOC_PAIR:
3363 break;
3364 case PPC_RELOC_HI16_SECTDIFF:
2f2f92e4 3365 warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
d696c285
A
3366 break;
3367 default:
2f2f92e4 3368 warning("unknown scattered relocation type %d", sreloc->r_type());
d696c285
A
3369 }
3370 }
3371 return result;
3372}
3373
d696c285
A
3374
3375template <>
3376bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
3377{
3378 uint32_t srcAddr;
3379 uint32_t dstAddr;
3380 uint32_t* fixUpPtr;
3381 bool result = false;
3382 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3383 srcAddr = sect->addr() + reloc->r_address();
3384 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3385 switch ( reloc->r_type() ) {
3386 case GENERIC_RELOC_VANILLA:
3387 {
a61fdf0a 3388 x86::ReferenceKinds kind = x86::kPointer;
d696c285
A
3389 uint32_t pointerValue = E::get32(*fixUpPtr);
3390 if ( reloc->r_pcrel() ) {
a61fdf0a
A
3391 switch( reloc->r_length() ) {
3392 case 0:
2f2f92e4
A
3393 kind = x86::kPCRel8;
3394 pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
3395 break;
a61fdf0a
A
3396 case 1:
3397 kind = x86::kPCRel16;
3398 pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
3399 break;
3400 case 2:
3401 kind = x86::kPCRel32;
3402 pointerValue += srcAddr + sizeof(uint32_t);
3403 break;
2f2f92e4
A
3404 case 3:
3405 throw "bad pc-rel vanilla relocation length";
a61fdf0a 3406 }
d696c285 3407 }
69a49097
A
3408 else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
3409 kind = x86::kAbsolute32;
a61fdf0a
A
3410 if ( reloc->r_length() != 2 )
3411 throw "bad vanilla relocation length";
69a49097 3412 }
d696c285
A
3413 else {
3414 kind = x86::kPointer;
a61fdf0a
A
3415 if ( reloc->r_length() != 2 )
3416 throw "bad vanilla relocation length";
d696c285
A
3417 }
3418 if ( reloc->r_extern() ) {
3419 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
2f2f92e4
A
3420 if ( this->isWeakImportSymbol(targetSymbol) ) {
3421 if ( reloc->r_pcrel() )
3422 kind = x86::kPCRel32WeakImport;
3423 else
3424 kind = x86::kPointerWeakImport;
3425 }
d696c285 3426 const char* targetName = &fStrings[targetSymbol->n_strx()];
a61fdf0a
A
3427 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3428 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
3429 addDtraceExtraInfos(srcAddr, &targetName[16]);
3430 }
3431 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3432 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3433 addDtraceExtraInfos(srcAddr, &targetName[20]);
3434 }
3435 else
3436 makeByNameReference(kind, srcAddr, targetName, pointerValue);
d696c285
A
3437 }
3438 else {
3439 // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
3440 ObjectFile::Atom* atom = findAtomAndOffset(pointerValue).atom;
a61fdf0a
A
3441 const char* targetName = atom->getName();
3442 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3443 makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
3444 addDtraceExtraInfos(srcAddr, &targetName[16]);
3445 }
3446 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3447 makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3448 addDtraceExtraInfos(srcAddr, &targetName[20]);
3449 }
3450 else if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
d696c285
A
3451 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3452 makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
a61fdf0a 3453 else if ( reloc->r_symbolnum() != R_ABS )
d696c285 3454 makeReference(kind, srcAddr, pointerValue);
a61fdf0a
A
3455 else {
3456 // find absolute symbol that corresponds to pointerValue
2f2f92e4 3457 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
a61fdf0a
A
3458 if ( pos != fAddrToAbsoluteAtom.end() )
3459 makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
3460 else
3461 throwf("R_ABS reloc but no absolute symbol at target address");
3462 }
d696c285
A
3463 }
3464 }
3465 break;
3466 default:
2f2f92e4 3467 warning("unknown relocation type %d", reloc->r_type());
d696c285
A
3468 }
3469 }
3470 else {
3471 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3472 srcAddr = sect->addr() + sreloc->r_address();
3473 dstAddr = sreloc->r_value();
3474 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3475 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3476 const macho_relocation_info<P>* nextReloc = &reloc[1];
3477 pint_t betterDstAddr;
3478 // file format allows pair to be scattered or not
3479 bool nextRelocIsPair = false;
3480 uint32_t nextRelocAddress = 0;
3481 uint32_t nextRelocValue = 0;
2f2f92e4
A
3482 if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
3483 if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
d696c285
A
3484 nextRelocIsPair = true;
3485 nextRelocAddress = nextReloc->r_address();
3486 result = true;
3487 }
3488 }
3489 else {
2f2f92e4 3490 if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
d696c285
A
3491 nextRelocIsPair = true;
3492 nextRelocAddress = nextSReloc->r_address();
3493 nextRelocValue = nextSReloc->r_value();
3494 }
3495 }
3496 switch (sreloc->r_type()) {
3497 case GENERIC_RELOC_VANILLA:
3498 betterDstAddr = LittleEndian::get32(*fixUpPtr);
3499 //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
3500 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
3501 if ( sreloc->r_pcrel() ) {
3502 betterDstAddr += srcAddr + 4;
3503 makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
3504 }
3505 else {
69a49097
A
3506 if ( strcmp(sect->segname(), "__TEXT") == 0 )
3507 makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
3508 else
3509 makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
d696c285
A
3510 }
3511 break;
3512 case GENERIC_RELOC_SECTDIFF:
3513 case GENERIC_RELOC_LOCAL_SECTDIFF:
3514 {
3515 if ( !nextRelocIsPair ) {
2f2f92e4 3516 warning("GENERIC_RELOC_SECTDIFF missing following pair");
d696c285
A
3517 break;
3518 }
a61fdf0a
A
3519 x86::ReferenceKinds kind = x86::kPointerDiff;
3520 uint32_t contentAddr = 0;
3521 switch ( sreloc->r_length() ) {
3522 case 0:
3523 case 3:
3524 throw "bad length for GENERIC_RELOC_SECTDIFF";
3525 case 1:
3526 kind = x86::kPointerDiff16;
3527 contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
3528 break;
3529 case 2:
3530 kind = x86::kPointerDiff;
3531 contentAddr = LittleEndian::get32(*fixUpPtr);
3532 break;
3533 }
3534 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
3535 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
3536 AtomAndOffset toao = findAtomAndOffset(dstAddr);
3537 // check for addend encoded in the section content
3538 //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
3539 // dstAddr, nextRelocValue, contentAddr);
3540 if ( (dstAddr - nextRelocValue) != contentAddr ) {
3541 if ( toao.atom == srcao.atom )
3542 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3543 else if ( fromao.atom == srcao.atom )
3544 toao.offset += (contentAddr + nextRelocValue) - dstAddr;
3545 else
3546 fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
3547 }
3548 //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
3549 // srcao.atom->getDisplayName(), srcao.offset,
3550 // fromao.atom->getDisplayName(), fromao.offset,
3551 // toao.atom->getDisplayName(), toao.offset);
3552 new Reference<x86>(kind, srcao, fromao, toao);
d696c285
A
3553 }
3554 break;
3555 case GENERIC_RELOC_PAIR:
3556 // do nothing, already used via a look ahead
3557 break;
3558 default:
2f2f92e4 3559 warning("unknown scattered relocation type %d", sreloc->r_type());
d696c285
A
3560 }
3561 }
3562 return result;
3563}
3564
69a49097
A
3565template <>
3566bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
3567{
3568 uint64_t srcAddr;
3569 uint64_t dstAddr = 0;
3570 uint64_t addend;
3571 uint32_t* fixUpPtr;
74cfe461 3572 x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
69a49097
A
3573 bool result = false;
3574 const macho_nlist<P>* targetSymbol = NULL;
3575 const char* targetName = NULL;
3576 srcAddr = sect->addr() + reloc->r_address();
3577 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3578 //fprintf(stderr, "addReloc type=%d\n", reloc->r_type());
3579 if ( reloc->r_extern() ) {
3580 targetSymbol = &fSymbols[reloc->r_symbolnum()];
3581 targetName = &fStrings[targetSymbol->n_strx()];
3582 }
3583 switch ( reloc->r_type() ) {
3584 case X86_64_RELOC_UNSIGNED:
3585 if ( reloc->r_pcrel() )
3586 throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
3587 if ( reloc->r_length() != 3 )
3588 throw "length < 3 and X86_64_RELOC_UNSIGNED not supported";
3589 dstAddr = E::get64(*((uint64_t*)fixUpPtr));
a61fdf0a 3590 if ( reloc->r_extern() ) {
69a49097 3591 makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr);
a61fdf0a
A
3592 }
3593 else {
69a49097 3594 makeReference(x86_64::kPointer, srcAddr, dstAddr);
a61fdf0a
A
3595 // verify that dstAddr is in the section being targeted
3596 int sectNum = reloc->r_symbolnum();
3597 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
3598 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
3599 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
3600 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
3601 srcAddr, sect->sectname(), targetSection->sectname());
3602 }
3603 }
69a49097
A
3604 break;
3605 case X86_64_RELOC_SIGNED:
86b84c30
A
3606 case X86_64_RELOC_SIGNED_1:
3607 case X86_64_RELOC_SIGNED_2:
3608 case X86_64_RELOC_SIGNED_4:
69a49097 3609 if ( ! reloc->r_pcrel() )
74cfe461 3610 throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
69a49097 3611 if ( reloc->r_length() != 2 )
74cfe461
A
3612 throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
3613 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3614 if ( reloc->r_extern() ) {
3615 switch ( reloc->r_type() ) {
3616 case X86_64_RELOC_SIGNED:
3617 kind = x86_64::kPCRel32;
3618 // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
3619 if ( addend == (uint64_t)(-1) ) {
3620 addend = 0;
86b84c30 3621 kind = x86_64::kPCRel32_1;
86b84c30 3622 }
74cfe461
A
3623 else if ( addend == (uint64_t)(-2) ) {
3624 addend = 0;
86b84c30 3625 kind = x86_64::kPCRel32_2;
86b84c30 3626 }
74cfe461
A
3627 else if ( addend == (uint64_t)(-4) ) {
3628 addend = 0;
86b84c30 3629 kind = x86_64::kPCRel32_4;
86b84c30 3630 }
74cfe461
A
3631 break;
3632 // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
3633 case X86_64_RELOC_SIGNED_1:
3634 kind = x86_64::kPCRel32_1;
3635 addend += 1;
3636 break;
3637 case X86_64_RELOC_SIGNED_2:
3638 kind = x86_64::kPCRel32_2;
3639 addend += 2;
3640 break;
3641 case X86_64_RELOC_SIGNED_4:
3642 kind = x86_64::kPCRel32_4;
3643 addend += 4;
3644 break;
3645 }
3646 makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
69a49097 3647 }
69a49097 3648 else {
74cfe461
A
3649 uint64_t ripRelativeOffset = addend;
3650 switch ( reloc->r_type() ) {
3651 case X86_64_RELOC_SIGNED:
3652 dstAddr = srcAddr + 4 + ripRelativeOffset;
3653 kind = x86_64::kPCRel32;
3654 break;
3655 case X86_64_RELOC_SIGNED_1:
3656 dstAddr = srcAddr + 5 + ripRelativeOffset;
3657 kind = x86_64::kPCRel32_1;
3658 break;
3659 case X86_64_RELOC_SIGNED_2:
3660 dstAddr = srcAddr + 6 + ripRelativeOffset;
3661 kind = x86_64::kPCRel32_2;
3662 break;
3663 case X86_64_RELOC_SIGNED_4:
3664 dstAddr = srcAddr + 8 + ripRelativeOffset;
3665 kind = x86_64::kPCRel32_4;
3666 break;
3667 }
3668 makeReference(kind, srcAddr, dstAddr);
a61fdf0a
A
3669 // verify that dstAddr is in the section being targeted
3670 int sectNum = reloc->r_symbolnum();
3671 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
3672 const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
3673 if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
3674 throwf("local relocation for address 0x%08llX in section %s does not target section %s",
3675 srcAddr, sect->sectname(), targetSection->sectname());
3676 }
74cfe461 3677 }
69a49097
A
3678 break;
3679 case X86_64_RELOC_BRANCH:
3680 if ( ! reloc->r_pcrel() )
3681 throw "not pcrel and X86_64_RELOC_BRANCH not supported";
2f2f92e4
A
3682 if ( reloc->r_length() == 2 ) {
3683 dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3684 if ( reloc->r_extern() ) {
3685 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3686 makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
3687 addDtraceExtraInfos(srcAddr, &targetName[16]);
3688 }
3689 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3690 makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3691 addDtraceExtraInfos(srcAddr, &targetName[16]);
3692 }
3693 else if ( isWeakImportSymbol(targetSymbol) )
3694 makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
3695 else
3696 makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
a61fdf0a 3697 }
2f2f92e4
A
3698 else {
3699 makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
3700 }
3701 }
3702 else if ( reloc->r_length() == 0 ) {
3703 dstAddr = *((int8_t*)fixUpPtr);
3704 if ( reloc->r_extern() ) {
3705 makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
3706 }
3707 else {
3708 makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
a61fdf0a 3709 }
69a49097
A
3710 }
3711 else {
2f2f92e4 3712 throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
69a49097
A
3713 }
3714 break;
3715 case X86_64_RELOC_GOT:
3716 if ( ! reloc->r_extern() )
3717 throw "not extern and X86_64_RELOC_GOT not supported";
3718 if ( ! reloc->r_pcrel() )
3719 throw "not pcrel and X86_64_RELOC_GOT not supported";
3720 if ( reloc->r_length() != 2 )
3721 throw "length != 2 and X86_64_RELOC_GOT not supported";
3722 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3723 if ( isWeakImportSymbol(targetSymbol) )
3724 makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
3725 else
3726 makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
3727 break;
3728 case X86_64_RELOC_GOT_LOAD:
3729 if ( ! reloc->r_extern() )
3730 throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
3731 if ( ! reloc->r_pcrel() )
3732 throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
3733 if ( reloc->r_length() != 2 )
3734 throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
3735 addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
3736 if ( isWeakImportSymbol(targetSymbol) )
3737 makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
3738 else
3739 makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
3740 break;
3741 case X86_64_RELOC_SUBTRACTOR:
a61fdf0a 3742 {
69a49097
A
3743 if ( reloc->r_pcrel() )
3744 throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
3745 if ( reloc->r_length() < 2 )
3746 throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
3747 if ( !reloc->r_extern() )
3748 throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
3749 const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
3750 if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
3751 throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
3752 result = true;
3753 if ( nextReloc->r_pcrel() )
3754 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
3755 if ( nextReloc->r_length() != reloc->r_length() )
3756 throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
3757 Reference<x86_64>* ref;
3758 bool negativeAddend;
3759 if ( reloc->r_length() == 2 ) {
3760 kind = x86_64::kPointerDiff32;
3761 dstAddr = E::get32(*fixUpPtr); // addend is in content
3762 negativeAddend = ((dstAddr & 0x80000000) != 0);
3763 }
3764 else {
3765 kind = x86_64::kPointerDiff;
3766 dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
3767 negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
3768 }
3769 ObjectFile::Atom* inAtom = this->findAtomAndOffset(srcAddr).atom;
3770 // create reference with "to" target
3771 if ( nextReloc->r_extern() ) {
3772 const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
3773 const char* targetName = &fStrings[targetSymbol->n_strx()];
3774 ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
3775 // if "to" is in this atom, change by-name to a direct reference
3776 if ( strcmp(targetName, inAtom->getName()) == 0 )
3777 ref->setTarget(*inAtom, 0);
3778 }
3779 else {
3780 ref = makeReference(kind, srcAddr, dstAddr);
3781 }
3782 // add in "from" target
3783 if ( reloc->r_extern() ) {
3784 const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
3785 const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
3786 if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
3787 // from target is translation unit scoped, so use a direct reference
3788 ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
3789 }
3790 else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
3791 // if "from" is in this atom, change by-name to a direct reference
3792 ref->setFromTarget(*inAtom);
3793 }
3794 else {
3795 // some non-static other atom
3796 ref->setFromTargetName(fromTargetName);
3797 }
3798 }
3799 // addend goes in from side iff negative
3800 if ( negativeAddend )
3801 ref->setFromTargetOffset(-dstAddr);
3802 else
3803 ref->setToTargetOffset(dstAddr);
3804 break;
a61fdf0a 3805 }
69a49097 3806 default:
2f2f92e4 3807 warning("unknown relocation type %d", reloc->r_type());
69a49097
A
3808 }
3809 return result;
3810}
d696c285
A
3811
3812
2f2f92e4
A
3813/// Reader<arm>::addRelocReference -
3814/// turns arm relocation entries into references. Returns true if the next
3815/// relocation should be skipped, false otherwise.
3816template <>
3817bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect,
3818 const macho_relocation_info<arm::P>* reloc)
3819{
3820 uint32_t * fixUpPtr;
3821 int32_t displacement;
3822 uint32_t instruction = 0;
3823 bool result = false;
3824 uint32_t srcAddr;
3825 uint32_t dstAddr;
3826 uint32_t pointerValue;
3827
3828 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
3829 // non-scattered relocation
3830 const char* targetName = NULL;
3831 bool weakImport = false;
3832
3833 srcAddr = sect->addr() + reloc->r_address();
3834 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
3835 if ( reloc->r_type() != ARM_RELOC_PAIR )
3836 instruction = LittleEndian::get32(*fixUpPtr);
3837
3838 if ( reloc->r_extern() ) {
3839 const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
3840 targetName = &fStrings[targetSymbol->n_strx()];
3841 weakImport = this->isWeakImportSymbol(targetSymbol);
3842 }
3843
3844 switch ( reloc->r_type() ) {
3845 case ARM_RELOC_BR24:
3846 // Sign-extend displacement
3847 displacement = (instruction & 0x00FFFFFF) << 2;
3848 if ( (displacement & 0x02000000) != 0 )
3849 displacement |= 0xFC000000;
3850 // The pc added will be +8 from the pc
3851 displacement += 8;
3852 // If this is BLX add H << 1
3853 if ((instruction & 0xFE000000) == 0xFA000000)
3854 displacement += ((instruction & 0x01000000) >> 23);
3855
3856 if ( reloc->r_extern() ) {
3857 uint32_t offsetInTarget = srcAddr + displacement;
3858 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3859 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3860 addDtraceExtraInfos(srcAddr, &targetName[16]);
3861 }
3862 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3863 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3864 addDtraceExtraInfos(srcAddr, &targetName[20]);
3865 }
3866 else if ( weakImport )
3867 makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
3868 else
3869 makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
3870 }
3871 else {
3872 dstAddr = srcAddr + displacement;
3873 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
3874 // check for dtrace probes and weak_import stubs
3875 const char* targetName = atom->getName();
3876 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3877 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3878 addDtraceExtraInfos(srcAddr, &targetName[16]);
3879 }
3880 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3881 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3882 addDtraceExtraInfos(srcAddr, &targetName[20]);
3883 }
3884 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3885 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3886 makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
3887 else if ( reloc->r_symbolnum() != R_ABS )
3888 makeReference(arm::kBranch24, srcAddr, dstAddr);
3889 else {
3890 // find absolute symbol that corresponds to pointerValue
3891 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3892 if ( pos != fAddrToAbsoluteAtom.end() )
3893 makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
3894 else
3895 throwf("R_ABS reloc but no absolute symbol at target address");
3896 }
3897 }
3898 break;
3899
3900 case ARM_THUMB_RELOC_BR22:
3901 // First instruction has upper 11 bits of the displacement.
3902 displacement = (instruction & 0x7FF) << 12;
3903 if ( (displacement & 0x400000) != 0 )
3904 displacement |= 0xFF800000;
3905 // Second instruction has lower eleven bits of the displacement.
3906 displacement += ((instruction >> 16) & 0x7FF) << 1;
3907 // The pc added will be +4 from the pc
3908 displacement += 4;
3909 // If the instruction was blx, force the low 2 bits to be clear
3910 dstAddr = srcAddr + displacement;
3911 if ((instruction & 0xF8000000) == 0xE8000000)
3912 dstAddr &= 0xFFFFFFFC;
3913
3914 if ( reloc->r_extern() ) {
3915 uint32_t offsetInTarget = dstAddr;
3916 if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
3917 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3918 addDtraceExtraInfos(srcAddr, &targetName[16]);
3919 }
3920 else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
3921 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3922 addDtraceExtraInfos(srcAddr, &targetName[20]);
3923 }
3924 else if ( weakImport )
3925 makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
3926 else
3927 makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
3928 }
3929 else {
3930 ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
3931 // check for dtrace probes and weak_import stubs
3932 const char* targetName = atom->getName();
3933 if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
3934 makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
3935 addDtraceExtraInfos(srcAddr, &targetName[16]);
3936 }
3937 else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
3938 makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
3939 addDtraceExtraInfos(srcAddr, &targetName[20]);
3940 }
3941 else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
3942 && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
3943 makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
3944 else if ( reloc->r_symbolnum() != R_ABS )
3945 makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
3946 else {
3947 // find absolute symbol that corresponds to pointerValue
3948 AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
3949 if ( pos != fAddrToAbsoluteAtom.end() )
3950 makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
3951 else
3952 throwf("R_ABS reloc but no absolute symbol at target address");
3953 }
3954 }
3955 break;
3956
3957 case ARM_RELOC_VANILLA:
3958 if ( reloc->r_length() != 2 )
3959 throw "bad length for ARM_RELOC_VANILLA";
3960
3961 pointerValue = instruction;
3962 if ( reloc->r_extern() ) {
3963 if ( weakImport )
3964 makeByNameReference(arm::kPointerWeakImport, srcAddr, targetName, pointerValue);
77cc3118
A
3965 else if ( strcmp(sect->segname(), "__TEXT") == 0 )
3966 makeByNameReference(arm::kReadOnlyPointer, srcAddr, targetName, pointerValue);
2f2f92e4
A
3967 else
3968 makeByNameReference(arm::kPointer, srcAddr, targetName, pointerValue);
3969 }
3970 else {
77cc3118
A
3971 if ( strcmp(sect->segname(), "__TEXT") == 0 )
3972 makeReference(arm::kReadOnlyPointer, srcAddr, pointerValue);
3973 else
3974 makeReference(arm::kPointer, srcAddr, pointerValue);
2f2f92e4
A
3975 }
3976 break;
3977
3978 default:
3979 warning("unexpected relocation type %u", reloc->r_type());
3980 break;
3981 }
3982 }
3983 else {
3984 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
3985 const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
3986 srcAddr = sect->addr() + sreloc->r_address();
3987 dstAddr = sreloc->r_value();
3988 uint32_t betterDstAddr;
3989 fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
3990 instruction = LittleEndian::get32(*fixUpPtr);
3991
3992 // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
3993 // relocation types, and it is an error to see one otherwise.
3994 bool nextRelocIsPair = false;
3995 uint32_t nextRelocAddress = 0;
3996 uint32_t nextRelocValue = 0;
3997 if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
3998 nextRelocIsPair = true;
3999 nextRelocAddress = nextSReloc->r_address();
4000 nextRelocValue = nextSReloc->r_value();
4001 result = true;
4002 }
4003
4004 switch (sreloc->r_type()) {
4005 case ARM_RELOC_VANILLA:
4006 if ( sreloc->r_length() != 2 )
4007 throw "bad length for ARM_RELOC_VANILLA";
4008
4009 betterDstAddr = LittleEndian::get32(*fixUpPtr);
4010 //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
4011 // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
77cc3118
A
4012 if ( strcmp(sect->segname(), "__TEXT") == 0 )
4013 makeReferenceWithToBase(arm::kReadOnlyPointer, srcAddr, betterDstAddr, dstAddr);
4014 else
4015 makeReferenceWithToBase(arm::kPointer, srcAddr, betterDstAddr, dstAddr);
2f2f92e4
A
4016 break;
4017
4018 case ARM_RELOC_BR24:
4019 // Sign-extend displacement
4020 displacement = (instruction & 0x00FFFFFF) << 2;
4021 if ( (displacement & 0x02000000) != 0 )
4022 displacement |= 0xFC000000;
4023 // The pc added will be +8 from the pc
4024 displacement += 8;
4025 // If this is BLX add H << 1
4026 if ((instruction & 0xFE000000) == 0xFA000000)
4027 displacement += ((instruction & 0x01000000) >> 23);
4028 betterDstAddr = srcAddr+displacement;
4029 makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
4030 break;
4031
4032 case ARM_THUMB_RELOC_BR22:
4033 // First instruction has upper 11 bits of the displacement.
4034 displacement = (instruction & 0x7FF) << 12;
4035 if ( (displacement & 0x400000) != 0 )
4036 displacement |= 0xFF800000;
4037 // Second instruction has lower eleven bits of the displacement.
4038 displacement += ((instruction >> 16) & 0x7FF) << 1;
4039 // The pc added will be +4 from the pc
4040 displacement += 4;
4041 betterDstAddr = srcAddr+displacement;
4042 // If the instruction was blx, force the low 2 bits to be clear
4043 if ((instruction & 0xF8000000) == 0xE8000000)
4044 betterDstAddr &= 0xFFFFFFFC;
4045 makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
4046 break;
4047
4048 case ARM_RELOC_SECTDIFF:
4049 case ARM_RELOC_LOCAL_SECTDIFF:
4050 if ( !nextRelocIsPair ) {
4051 warning("ARM_RELOC_SECTDIFF missing following pair");
4052 break;
4053 }
4054 if ( sreloc->r_length() != 2 )
4055 throw "bad length for ARM_RELOC_SECTDIFF";
4056 {
4057 AtomAndOffset srcao = findAtomAndOffset(srcAddr);
4058 AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
4059 AtomAndOffset toao = findAtomAndOffset(dstAddr);
4060 // check for addend encoded in the section content
4061 pointerValue = LittleEndian::get32(*fixUpPtr);
4062 if ( (dstAddr - nextRelocValue) != pointerValue ) {
4063 if ( toao.atom == srcao.atom )
4064 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
4065 else if ( fromao.atom == srcao.atom )
4066 toao.offset += (pointerValue + nextRelocValue) - dstAddr;
4067 else
4068 fromao.offset += (dstAddr - pointerValue) - nextRelocValue;
4069 }
4070 new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
4071 }
4072 break;
4073
4074 default:
4075 warning("unexpected srelocation type %u", sreloc->r_type());
4076 break;
4077 }
4078 }
4079 return result;
4080}
4081
a61fdf0a
A
4082template <typename A>
4083void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
4084{
4085 // ignore dwarf sections. If ld ever supports processing dwarf, this logic will need to change
4086 if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
4087 switch ( sect->flags() & SECTION_TYPE ) {
4088 case S_SYMBOL_STUBS:
4089 case S_LAZY_SYMBOL_POINTERS:
4090 // we ignore compiler generated stubs, so ignore those relocs too
4091 break;
4092 default:
4093 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
4094 const uint32_t relocCount = sect->nreloc();
4095 //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
4096 for (uint32_t r = 0; r < relocCount; ++r) {
4097 try {
4098 if ( addRelocReference(sect, &relocs[r]) )
4099 ++r; // skip next
4100 }
4101 catch (const char* msg) {
2f2f92e4 4102 throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
a61fdf0a
A
4103 }
4104 }
4105 }
4106 }
4107}
4108
4109
d696c285
A
4110template <>
4111const char* Reference<x86>::getDescription() const
4112{
69a49097 4113 static char temp[2048];
d696c285
A
4114 switch( fKind ) {
4115 case x86::kNoFixUp:
4116 sprintf(temp, "reference to ");
4117 break;
4118 case x86::kFollowOn:
4119 sprintf(temp, "followed by ");
4120 break;
2f2f92e4
A
4121 case x86::kGroupSubordinate:
4122 sprintf(temp, "group subordinate ");
4123 break;
d696c285
A
4124 case x86::kPointerWeakImport:
4125 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4126 break;
4127 case x86::kPointer:
4128 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4129 break;
4130 case x86::kPointerDiff:
4131 {
4132 // by-name references have quoted names
4133 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4134 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4135 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4136 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4137 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4138 return temp;
4139 }
4140 break;
a61fdf0a
A
4141 case x86::kPointerDiff16:
4142 {
4143 // by-name references have quoted names
4144 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4145 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4146 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4147 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4148 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4149 return temp;
4150 }
4151 break;
d696c285
A
4152 case x86::kPCRel32WeakImport:
4153 sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
4154 break;
4155 case x86::kPCRel32:
4156 sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
4157 break;
a61fdf0a
A
4158 case x86::kPCRel16:
4159 sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
4160 break;
2f2f92e4
A
4161 case x86::kPCRel8:
4162 sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
4163 break;
69a49097
A
4164 case x86::kAbsolute32:
4165 sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
4166 break;
a61fdf0a
A
4167 case x86::kDtraceProbe:
4168 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4169 break;
4170 case x86::kDtraceProbeSite:
4171 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4172 break;
4173 case x86::kDtraceIsEnabledSite:
4174 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4175 break;
4176 case x86::kDtraceTypeReference:
4177 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4178 break;
d696c285
A
4179 }
4180 // always quote by-name references
4181 if ( fToTargetName != NULL ) {
4182 strcat(temp, "\"");
4183 strcat(temp, fToTargetName);
4184 strcat(temp, "\"");
4185 }
4186 else if ( fToTarget.atom != NULL ) {
4187 strcat(temp, fToTarget.atom->getDisplayName());
4188 }
4189 else {
4190 strcat(temp, "NULL target");
4191 }
4192 if ( fToTarget.offset != 0 )
4193 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4194
4195 return temp;
4196}
4197
4198
4199template <>
4200const char* Reference<ppc>::getDescription() const
4201{
69a49097 4202 static char temp[2048];
d696c285
A
4203 switch( fKind ) {
4204 case ppc::kNoFixUp:
4205 sprintf(temp, "reference to ");
4206 break;
4207 case ppc::kFollowOn:
4208 sprintf(temp, "followed by ");
4209 break;
2f2f92e4
A
4210 case ppc::kGroupSubordinate:
4211 sprintf(temp, "group subordinate ");
4212 break;
d696c285
A
4213 case ppc::kPointerWeakImport:
4214 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4215 break;
4216 case ppc::kPointer:
4217 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4218 break;
a61fdf0a
A
4219 case ppc::kPointerDiff16:
4220 {
4221 // by-name references have quoted names
4222 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4223 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4224 sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4225 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4226 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4227 return temp;
4228 }
d696c285
A
4229 case ppc::kPointerDiff32:
4230 {
4231 // by-name references have quoted names
4232 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4233 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4234 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4235 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4236 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4237 return temp;
4238 }
4239 case ppc::kPointerDiff64:
4240 throw "unsupported refrence kind";
4241 break;
4242 case ppc::kBranch24WeakImport:
4243 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4244 break;
4245 case ppc::kBranch24:
4246 case ppc::kBranch14:
4247 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4248 break;
4249 case ppc::kPICBaseLow16:
a61fdf0a 4250 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
4251 break;
4252 case ppc::kPICBaseLow14:
a61fdf0a 4253 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
4254 break;
4255 case ppc::kPICBaseHigh16:
a61fdf0a 4256 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
4257 break;
4258 case ppc::kAbsLow16:
4259 sprintf(temp, "offset 0x%04X, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
4260 break;
4261 case ppc::kAbsLow14:
4262 sprintf(temp, "offset 0x%04X, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
4263 break;
4264 case ppc::kAbsHigh16:
a61fdf0a 4265 sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
d696c285
A
4266 break;
4267 case ppc::kAbsHigh16AddLow:
a61fdf0a
A
4268 sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
4269 break;
4270 case ppc::kDtraceProbe:
4271 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4272 break;
4273 case ppc::kDtraceProbeSite:
4274 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4275 break;
4276 case ppc::kDtraceIsEnabledSite:
4277 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4278 break;
4279 case ppc::kDtraceTypeReference:
4280 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
d696c285
A
4281 break;
4282 }
4283 // always quote by-name references
4284 if ( fToTargetName != NULL ) {
4285 strcat(temp, "\"");
4286 strcat(temp, fToTargetName);
4287 strcat(temp, "\"");
4288 }
4289 else if ( fToTarget.atom != NULL ) {
4290 strcat(temp, fToTarget.atom->getDisplayName());
4291 }
4292 else {
4293 strcat(temp, "NULL target");
4294 }
4295 if ( fToTarget.offset != 0 )
4296 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
4297
4298 return temp;
4299}
4300
4301template <>
4302const char* Reference<ppc64>::getDescription() const
4303{
69a49097 4304 static char temp[2048];
d696c285
A
4305 switch( fKind ) {
4306 case ppc64::kNoFixUp:
4307 sprintf(temp, "reference to ");
4308 break;
4309 case ppc64::kFollowOn:
4310 sprintf(temp, "followed by ");
4311 break;
2f2f92e4
A
4312 case ppc64::kGroupSubordinate:
4313 sprintf(temp, "group subordinate ");
4314 break;
d696c285
A
4315 case ppc64::kPointerWeakImport:
4316 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
4317 break;
4318 case ppc64::kPointer:
4319 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
4320 break;
4321 case ppc64::kPointerDiff64:
4322 {
4323 // by-name references have quoted names
4324 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4325 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4326 sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4327 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4328 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4329 return temp;
4330 }
4331 case ppc64::kPointerDiff32:
4332 {
4333 // by-name references have quoted names
4334 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4335 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4336 sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4337 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4338 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4339 return temp;
4340 }
a61fdf0a
A
4341 case ppc64::kPointerDiff16:
4342 {
4343 // by-name references have quoted names
4344 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4345 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4346 sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
4347 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4348 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4349 return temp;
4350 }
d696c285
A
4351 case ppc64::kBranch24WeakImport:
4352 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4353 break;
4354 case ppc64::kBranch24:
4355 case ppc64::kBranch14:
4356 sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4357 break;
4358 case ppc64::kPICBaseLow16:
4359 sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4360 break;
4361 case ppc64::kPICBaseLow14:
4362 sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4363 break;
4364 case ppc64::kPICBaseHigh16:
4365 sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
4366 break;
4367 case ppc64::kAbsLow16:
4368 sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", fFixUpOffsetInSrc);
4369 break;
4370 case ppc64::kAbsLow14:
4371 sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", fFixUpOffsetInSrc);
4372 break;
4373 case ppc64::kAbsHigh16:
a61fdf0a 4374 sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
d696c285
A
4375 break;
4376 case ppc64::kAbsHigh16AddLow:
a61fdf0a
A
4377 sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
4378 break;
4379 case ppc64::kDtraceProbe:
4380 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
4381 break;
4382 case ppc64::kDtraceProbeSite:
4383 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
4384 break;
4385 case ppc64::kDtraceIsEnabledSite:
4386 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4387 break;
4388 case ppc64::kDtraceTypeReference:
4389 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
d696c285
A
4390 break;
4391 }
4392 // always quote by-name references
4393 if ( fToTargetName != NULL ) {
4394 strcat(temp, "\"");
4395 strcat(temp, fToTargetName);
4396 strcat(temp, "\"");
4397 }
4398 else if ( fToTarget.atom != NULL ) {
4399 strcat(temp, fToTarget.atom->getDisplayName());
4400 }
4401 else {
4402 strcat(temp, "NULL target");
4403 }
4404 if ( fToTarget.offset != 0 )
69a49097 4405 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
d696c285
A
4406
4407 return temp;
4408}
4409
4410
69a49097
A
4411template <>
4412const char* Reference<x86_64>::getDescription() const
4413{
4414 static char temp[2048];
4415 switch( fKind ) {
4416 case x86_64::kNoFixUp:
4417 sprintf(temp, "reference to ");
4418 break;
4419 case x86_64::kFollowOn:
4420 sprintf(temp, "followed by ");
4421 break;
2f2f92e4
A
4422 case x86_64::kGroupSubordinate:
4423 sprintf(temp, "group subordinate ");
4424 break;
69a49097
A
4425 case x86_64::kPointerWeakImport:
4426 sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
4427 break;
4428 case x86_64::kPointer:
4429 sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
4430 break;
4431 case x86_64::kPointerDiff32:
4432 case x86_64::kPointerDiff:
4433 {
4434 // by-name references have quoted names
4435 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4436 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4437 const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
4438 sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
4439 fFixUpOffsetInSrc, size, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4440 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4441 return temp;
4442 }
4443 break;
4444 case x86_64::kPCRel32:
4445 sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
4446 break;
4447 case x86_64::kPCRel32_1:
4448 sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
4449 break;
4450 case x86_64::kPCRel32_2:
4451 sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
4452 break;
4453 case x86_64::kPCRel32_4:
4454 sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
4455 break;
4456 case x86_64::kBranchPCRel32:
4457 sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
4458 break;
4459 case x86_64::kBranchPCRel32WeakImport:
4460 sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
4461 break;
4462 case x86_64::kPCRel32GOT:
4463 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
4464 break;
4465 case x86_64::kPCRel32GOTWeakImport:
4466 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
4467 break;
4468 case x86_64::kPCRel32GOTLoad:
4469 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
4470 break;
4471 case x86_64::kPCRel32GOTLoadWeakImport:
4472 sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
4473 break;
2f2f92e4
A
4474 case x86_64::kBranchPCRel8:
4475 sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
4476 break;
a61fdf0a
A
4477 case x86_64::kDtraceProbe:
4478 sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
4479 break;
4480 case x86_64::kDtraceProbeSite:
4481 sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
4482 break;
4483 case x86_64::kDtraceIsEnabledSite:
4484 sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4485 break;
4486 case x86_64::kDtraceTypeReference:
4487 sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
4488 break;
69a49097
A
4489 }
4490 // always quote by-name references
4491 if ( fToTargetName != NULL ) {
4492 strcat(temp, "\"");
4493 strcat(temp, fToTargetName);
4494 strcat(temp, "\"");
4495 }
4496 else if ( fToTarget.atom != NULL ) {
4497 strcat(temp, fToTarget.atom->getDisplayName());
4498 }
4499 else {
4500 strcat(temp, "NULL target");
4501 }
4502 if ( fToTarget.offset != 0 )
4503 sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
4504
4505 return temp;
4506}
d696c285 4507
2f2f92e4
A
4508template <>
4509const char* Reference<arm>::getDescription() const
4510{
4511 static char temp[2048];
4512 switch( fKind ) {
4513 case arm::kNoFixUp:
4514 sprintf(temp, "reference to ");
4515 break;
4516 case arm::kFollowOn:
4517 sprintf(temp, "followed by ");
4518 break;
4519 case arm::kGroupSubordinate:
4520 sprintf(temp, "group subordinate ");
4521 break;
4522 case arm::kPointer:
4523 sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
4524 break;
4525 case arm::kPointerWeakImport:
4526 sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
4527 break;
4528 case arm::kPointerDiff:
4529 {
4530 // by-name references have quoted names
4531 const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
4532 const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
4533 sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
4534 fFixUpOffsetInSrc, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
4535 fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
4536 return temp;
4537 }
77cc3118
A
4538 case arm::kReadOnlyPointer:
4539 sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc);
4540 break;
2f2f92e4
A
4541 case arm::kBranch24:
4542 case arm::kThumbBranch22:
4543 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
4544 break;
4545 case arm::kBranch24WeakImport:
4546 case arm::kThumbBranch22WeakImport:
4547 sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
4548 break;
4549 case arm::kDtraceProbe:
4550 sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
4551 break;
4552 case arm::kDtraceProbeSite:
4553 sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
4554 break;
4555 case arm::kDtraceIsEnabledSite:
4556 sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
4557 break;
4558 case arm::kDtraceTypeReference:
4559 sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
4560 break;
4561 }
4562 // always quote by-name references
4563 if ( fToTargetName != NULL ) {
4564 strcat(temp, "\"");
4565 strcat(temp, fToTargetName);
4566 strcat(temp, "\"");
4567 }
4568 else if ( fToTarget.atom != NULL ) {
4569 strcat(temp, fToTarget.atom->getDisplayName());
4570 }
4571 else {
4572 strcat(temp, "NULL target");
4573 }
4574 if ( fToTarget.offset != 0 )
4575 sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
d696c285 4576
2f2f92e4
A
4577 return temp;
4578}
86b84c30 4579
d696c285
A
4580}; // namespace relocatable
4581}; // namespace mach_o
4582
4583#endif // __OBJECT_FILE_MACH_O__