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