2 * Copyright (c) 2019 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #ifndef MachOAnalyzerSet_h
25 #define MachOAnalyzerSet_h
28 #include "MachOAnalyzer.h"
35 // MachOAnalyzerSet is an abstraction to deal with sets of mach-o files. For instance,
36 // if a mach-o file A binds to a symbol in mach-o file B, the MachOAnalyzerSet lets you
37 // evaulate the bind such that you know where in B, the bind pointer in A needs to point.
39 // The goal of MachOAnalyzerSet is to be the one place for code that handles mach-o
40 // file interactions, such as two-level namespace binding, weak-def coalescing, and
41 // dyld cache patching.
43 // Conceptually, MachOAnalyzerSet is an ordered list of mach-o files. Each file is modeled
44 // as an WrappedMachO object. This is a lightweight POD struct of three pointers that
45 // can be copied around. A WrappedMachO consists of the MachOAnalyzer* that is represents,
46 // a pointer to the MachOAnalyzerSet it is in, and an abstract "other" pointer that the
47 // concrete implementation of MachOAnalyzerSet defines. All uses of mach-o files in
48 // the MachOAnalyzerSet method uses WrappedMachO types.
50 // // This is the key method on WrappedMachO. It is called during closure building to
51 // // compile down the fixups, as well as at runtime in dyld3 minimal closure mode
52 // // to parse LINKEDIT and rebase/bind pointers.
53 // void forEachFixup(Diagnostics& diag, FixUpHandler, CachePatchHandler) const;
56 // It would have been nice to have virtual methods on WrappedMachO, but C++ won't allow
57 // objects with vtables to be copied. So instead the methods on WrappedMachO simply
58 // forward to virtual methods in the owning MachOAnalyzerSet object. Therefore, there
59 // are two kinds of methods on MachOAnalyzerSet: methods for a WrappedMachO start with wmo_,
60 // whereas methods for the whole set start with mas_.
62 // // Walk all images in the set in order. "hidden" means the image was loaded with RTLD_LOCAL
63 // void mas_forEachImage(void (^handler)(const WrappedMachO& wmo, bool hidden, bool& stop)) const = 0;
65 // // fills in mainWmo with the WrappedMachO for the main executable in the set
66 // void mas_mainExecutable(WrappedMachO& mainWmo) const = 0;
68 // // returns a pointer to the start of the dyld cache used the mach-o files in the set
69 // void* mas_dyldCache() const = 0;
71 // // For weak-def coalescing. The file fromWmo needs to bind to symbolName. All files with weak-defs should be searched.
72 // // As a side effect of doing this binding, it may find that the symbol is bound overrides something in the dyld cache.
73 // // In that case, the CachePatchHandler function is called with info about how to patch the dyld cache.
74 // // This function has a default implementation. Only the dyld cache builder overrides this, because the set is all the
75 // // dylibs in the dyld cache, and coalescing should only look at files actually linked.
76 // bool mas_fromImageWeakDefLookup(const WrappedMachO& fromWmo, const char* symbolName, uint64_t addend,
77 // CachePatchHandler patcher, FixupTarget& target) const;
80 // // For a given WrappedMachO (fromWmo), find the nth dependent dylib. If depIndex is out of range, return false.
81 // // If child is weak-linked dylib that could not be loaded, set missingWeakDylib to true and return true.
82 // // Otherwise fill in childWmo and return true
83 // bool wmo_dependent(const WrappedMachO* fromWmo, uint32_t depIndex, WrappedMachO& childWmo, bool& missingWeakDylib) const = 0;
85 // // Returns the path to the specified WrappedMachO
86 // const char* wmo_path(const WrappedMachO* wmo) const = 0;
88 // // Called if a symbol cannot be found. If false is returned, then the symbol binding code will return an error.
89 // // If true is returned, then "target" must be set. It may be set to "NULL" as absolute/0.
90 // bool wmo_missingSymbolResolver(const WrappedMachO* fromWmo, bool weakImport, bool lazyBind, const char* symbolName,
91 // const char* expectedInDylibPath, const char* clientPath, FixupTarget& target) const = 0;
93 // // Returns the exports trie for the given binary. There is a default implementation which walks the load commands.
94 // // This should only be overriden if the MachOAnalyzerSet caches the export trie location.
95 // ExportsTrie wmo_getExportsTrie(const WrappedMachO* wmo) const;
97 // // This handles special symbols like C++ operator new which can exist in the main executable as non-weak but
98 // // coalesce with other weak implementations. It does not need to be overridden.
99 // void wmo_findExtraSymbolFrom(const WrappedMachO* fromWmo, CachePatchHandler ph) const;
101 // // This is core logic for two-level namespace symbol look ups. It does not need to be overridden.
102 // bool wmo_findSymbolFrom(const WrappedMachO* fromWmo, Diagnostics& diag, int libOrdinal, const char* symbolName,
103 // bool weakImport, bool lazyBind, uint64_t addend, CachePatchHandler ph, FixupTarget& target) const;
107 struct VIS_HIDDEN MachOAnalyzerSet
112 struct ExportsTrie
{ const uint8_t* start
; const uint8_t* end
; } ;
114 // Extra info needed when setting an actual pointer value at runtime
115 struct PointerMetaData
118 PointerMetaData(const MachOLoaded
::ChainedFixupPointerOnDisk
* fixupLoc
, uint16_t pointer_format
);
120 uint32_t diversity
: 16,
124 usesAddrDiversity
: 1;
127 typedef void (^FixUpHandler
)(uint64_t fixupLocRuntimeOffset
, PointerMetaData pmd
, const FixupTarget
& target
, bool& stop
);
128 typedef void (^CachePatchHandler
)(uint32_t cachedDylibIndex
, uint32_t exportCacheOffset
, const FixupTarget
& target
);
132 const MachOAnalyzer
* _mh
;
133 const MachOAnalyzerSet
* _set
;
136 WrappedMachO() : _mh(nullptr), _set((nullptr)), _other((nullptr)) { }
137 WrappedMachO(const MachOAnalyzer
* ma
, const MachOAnalyzerSet
* mas
, void* o
) : _mh(ma
), _set(mas
), _other(o
) { }
140 // Used by: dyld cache building, dyld3s fixup applying, app closure building traditional format, dyldinfo tool
141 void forEachFixup(Diagnostics
& diag
, FixUpHandler
, CachePatchHandler
) const;
143 // convenience functions
144 bool dependent(uint32_t depIndex
, WrappedMachO
& childObj
, bool& missingWeakDylib
) const { return _set
->wmo_dependent(this, depIndex
, childObj
, missingWeakDylib
); }
145 const char* path() const { return (_set ? _set
->wmo_path(this) : nullptr); }
146 ExportsTrie
getExportsTrie() const { return _set
->wmo_getExportsTrie(this); }
147 bool findSymbolFrom(Diagnostics
& diag
, int libOrdinal
, const char* symbolName
, bool weakImport
, bool lazyBind
, uint64_t addend
, CachePatchHandler ph
, FixupTarget
& target
) const
148 { return _set
->wmo_findSymbolFrom(this, diag
, libOrdinal
, symbolName
, weakImport
, lazyBind
, addend
, ph
, target
); }
149 bool missingSymbolResolver(bool weakImport
, bool lazyBind
, const char* symbolName
, const char* expectedInDylibPath
, const char* clientPath
, FixupTarget
& target
) const
150 { return _set
->wmo_missingSymbolResolver(this, weakImport
, lazyBind
, symbolName
, expectedInDylibPath
, clientPath
, target
); }
152 bool findSymbolIn(Diagnostics
& diag
, const char* symbolName
, uint64_t addend
, FixupTarget
& target
) const;
155 void forEachBind(Diagnostics
& diag
, FixUpHandler
, CachePatchHandler
) const;
161 enum class Kind
{ rebase
, bindToImage
, bindAbsolute
, bindMissingSymbol
};
162 WrappedMachO foundInImage
;
163 uint64_t offsetInImage
= 0; // includes addend
164 const char* requestedSymbolName
= nullptr;
165 const char* foundSymbolName
= nullptr;
166 uint64_t addend
= 0; // already added into offsetInImage
168 Kind kind
= Kind
::rebase
;
169 bool isLazyBindRebase
= false; // target is stub helper in same image
170 bool isWeakDef
= false; // target symbol is a weak-def
171 bool weakCoalesced
= false; // target found searching all images
172 bool weakBoundSameImage
= false; // first weak-def was in same image as use
173 bool skippableWeakDef
= false; // old binary that stripped symbol, so def will never be found
176 virtual void mas_forEachImage(void (^handler
)(const WrappedMachO
& wmo
, bool hidden
, bool& stop
)) const = 0;
177 virtual bool mas_fromImageWeakDefLookup(const WrappedMachO
& fromWmo
, const char* symbolName
, uint64_t addend
, CachePatchHandler patcher
, FixupTarget
& target
) const;
178 virtual void mas_mainExecutable(WrappedMachO
& mainWmo
) const = 0;
179 virtual void* mas_dyldCache() const = 0;
185 virtual bool wmo_dependent(const WrappedMachO
* fromWmo
, uint32_t depIndex
, WrappedMachO
& childWmo
, bool& missingWeakDylib
) const = 0;
186 virtual const char* wmo_path(const WrappedMachO
* wmo
) const = 0;
187 virtual ExportsTrie
wmo_getExportsTrie(const WrappedMachO
* wmo
) const;
188 virtual bool wmo_findSymbolFrom(const WrappedMachO
* fromWmo
, Diagnostics
& diag
, int libOrdinal
, const char* symbolName
, bool weakImport
,
189 bool lazyBind
, uint64_t addend
, CachePatchHandler ph
, FixupTarget
& target
) const;
190 virtual bool wmo_missingSymbolResolver(const WrappedMachO
* fromWmo
, bool weakImport
, bool lazyBind
, const char* symbolName
,
191 const char* expectedInDylibPath
, const char* clientPath
, FixupTarget
& target
) const = 0;
192 virtual void wmo_findExtraSymbolFrom(const WrappedMachO
* fromWmo
, CachePatchHandler ph
) const;
199 #endif /* MachOAnalyzerSet_h */