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