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