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