1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
27 namespace ObjectFileDylibMachO
{
29 class Reader
: public ObjectFile::Reader
32 Reader(const macho_header
* header
, const char* path
, const ObjectFile::ReaderOptions
& options
);
35 virtual const char* getPath();
36 virtual std::vector
<class ObjectFile::Atom
*>& getAtoms();
37 virtual std::vector
<class ObjectFile::Atom
*>* getJustInTimeAtomsFor(const char* name
);
38 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo();
39 virtual const char* getInstallPath();
40 virtual uint32_t getTimestamp();
41 virtual uint32_t getCurrentVersion();
42 virtual uint32_t getCompatibilityVersion();
43 virtual std::vector
<const char*>* getDependentLibraryPaths();
44 virtual bool reExports(ObjectFile::Reader
*);
45 virtual bool isDefinitionWeak(const ObjectFile::Atom
&);
48 struct CStringComparor
50 bool operator()(const char* left
, const char* right
) { return (strcmp(left
, right
) > 0); }
52 typedef std::map
<const char*, ObjectFile::Atom
*, CStringComparor
> Mapper
;
55 void init(const macho_header
* header
,const char* path
);
56 const macho_nlist
* binarySearchWithToc(const char* key
, const char stringPool
[], const macho_nlist symbols
[], const struct dylib_table_of_contents toc
[], uint32_t symbolCount
);
57 const macho_nlist
* binarySearch(const char* key
, const char stringPool
[], const macho_nlist symbols
[], uint32_t symbolCount
);
58 bool hasExport(const char* name
);
59 const macho_nlist
* findExport(const char* name
);
62 const macho_header
* fHeader
;
64 const macho_dysymtab_command
* fDynamicInfo
;
65 const macho_dylib_command
* fDylibID
;
66 const macho_nlist
* fSymbols
;
67 uint32_t fSymbolCount
;
69 std::vector
<Reader
*> fReExportedDylibs
;
71 static std::vector
<class ObjectFile::Atom
*> fEmptyAtomList
;
74 std::vector
<class ObjectFile::Atom
*> Reader::fEmptyAtomList
;
77 class Segment
: public ObjectFile::Segment
80 Segment(const char* name
) { fName
= name
; }
81 virtual const char* getName() const { return fName
; }
82 virtual bool isContentReadable() const { return true; }
83 virtual bool isContentWritable() const { return false; }
84 virtual bool isContentExecutable() const { return false; }
90 class ExportAtom
: public ObjectFile::Atom
93 virtual ObjectFile::Reader
* getFile() const { return &fOwner
; }
94 virtual const char* getName() const { return fName
; }
95 virtual const char* getDisplayName() const;
96 virtual Scope
getScope() const { return ObjectFile::Atom::scopeGlobal
; }
97 virtual bool isTentativeDefinition() const { return false; }
98 virtual bool isWeakDefinition() const { return false; }
99 virtual bool isCoalesableByName() const { return false; }
100 virtual bool isCoalesableByValue() const { return false; }
101 virtual bool isZeroFill() const { return false; }
102 virtual bool dontDeadStrip() const { return false; }
103 virtual bool dontStripName() const { return false; }
104 virtual bool isImportProxy() const { return true; }
105 virtual uint64_t getSize() const { return 0; }
106 virtual std::vector
<ObjectFile::Reference
*>& getReferences() const { return fgEmptyReferenceList
; }
107 virtual bool mustRemainInSection() const { return false; }
108 virtual const char* getSectionName() const { return "._imports"; }
109 virtual Segment
& getSegment() const { return fgImportSegment
; }
110 virtual bool requiresFollowOnAtom() const{ return false; }
111 virtual ObjectFile::Atom
& getFollowOnAtom() const { return *((ObjectFile::Atom
*)NULL
); }
112 virtual std::vector
<ObjectFile::StabsInfo
>* getStabsDebugInfo() const { return NULL
; }
113 virtual uint8_t getAlignment() const { return 0; }
114 virtual WeakImportSetting
getImportWeakness() const { return fWeakImportSetting
; }
115 virtual void copyRawContent(uint8_t buffer
[]) const {}
116 virtual void writeContent(bool finalLinkedImage
, ObjectFile::ContentWriter
&) const {}
118 virtual void setScope(Scope
) { }
119 virtual void setImportWeakness(bool weakImport
) { fWeakImportSetting
= weakImport
? kWeakImport
: kNonWeakImport
; }
124 ExportAtom(Reader
& owner
, const char* name
) : fOwner(owner
), fName(name
), fWeakImportSetting(kWeakUnset
) {}
125 virtual ~ExportAtom() {}
129 WeakImportSetting fWeakImportSetting
;
131 static std::vector
<ObjectFile::Reference
*> fgEmptyReferenceList
;
132 static Segment fgImportSegment
;
135 Segment
ExportAtom::fgImportSegment("__LINKEDIT");
136 std::vector
<ObjectFile::Reference
*> ExportAtom::fgEmptyReferenceList
;
138 const char* ExportAtom::getDisplayName() const
140 static char temp
[300];
142 strcat(temp
, "$import");
148 Reader::Reader(const macho_header
* header
, const char* path
, const ObjectFile::ReaderOptions
& options
)
149 : fHeader(header
), fStrings(NULL
), fDylibID(NULL
), fSymbols(NULL
), fSymbolCount(0)
151 typedef std::pair
<const macho_dylib_command
*, bool> DylibAndReExportFlag
;
152 std::vector
<DylibAndReExportFlag
> dependentDylibs
;
154 fPath
= strdup(path
);
155 const uint32_t cmd_count
= header
->ncmds();
156 const macho_load_command
* const cmds
= (macho_load_command
*)((char*)header
+ macho_header::size
);
157 // get all dylib load commands
158 const macho_load_command
* cmd
= cmds
;
159 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
160 switch (cmd
->cmd()) {
162 case LC_LOAD_WEAK_DYLIB
:
164 DylibAndReExportFlag info
;
165 info
.first
= (struct macho_dylib_command
*)cmd
;
166 info
.second
= options
.fFlatNamespace
;
167 dependentDylibs
.push_back(info
);
171 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
174 // cache interesting pointers
176 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
177 switch (cmd
->cmd()) {
180 const macho_symtab_command
* symtab
= (macho_symtab_command
*)cmd
;
181 fSymbolCount
= symtab
->nsyms();
182 fSymbols
= (const macho_nlist
*)((char*)header
+ symtab
->symoff());
183 fStrings
= (char*)header
+ symtab
->stroff();
187 fDynamicInfo
= (macho_dysymtab_command
*)cmd
;
190 fDylibID
= (macho_dylib_command
*)cmd
;
192 case LC_SUB_UMBRELLA
:
193 if ( !options
.fFlatNamespace
) {
194 const char* frameworkLeafName
= ((macho_sub_umbrella_command
*)cmd
)->name();
195 for (std::vector
<DylibAndReExportFlag
>::iterator it
= dependentDylibs
.begin(); it
!= dependentDylibs
.end(); it
++) {
196 const char* dylibName
= it
->first
->name();
197 const char* lastSlash
= strrchr(dylibName
, '/');
198 if ( (lastSlash
!= NULL
) && (strcmp(&lastSlash
[1], frameworkLeafName
) == 0) )
204 if ( !options
.fFlatNamespace
) {
205 const char* dylibBaseName
= ((macho_sub_library_command
*)cmd
)->name();
206 for (std::vector
<DylibAndReExportFlag
>::iterator it
= dependentDylibs
.begin(); it
!= dependentDylibs
.end(); it
++) {
207 const char* dylibName
= it
->first
->name();
208 const char* lastSlash
= strrchr(dylibName
, '/');
209 const char* leafStart
= &lastSlash
[1];
210 if ( lastSlash
== NULL
)
211 leafStart
= dylibName
;
212 const char* firstDot
= strchr(leafStart
, '.');
213 int len
= strlen(leafStart
);
214 if ( firstDot
!= NULL
)
215 len
= firstDot
- leafStart
;
216 if ( strncmp(leafStart
, dylibBaseName
, len
) == 0 )
222 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
225 // load dylibs we need to re-export
226 for (std::vector
<DylibAndReExportFlag
>::iterator it
= dependentDylibs
.begin(); it
!= dependentDylibs
.end(); it
++) {
228 // printf("%s need to re-export %s\n", path, it->first->name());
229 //fReExportedDylibs.push_back(
239 const char* Reader::getPath()
245 std::vector
<class ObjectFile::Atom
*>& Reader::getAtoms()
247 return fEmptyAtomList
;
252 const macho_nlist
* Reader::binarySearchWithToc(const char* key
, const char stringPool
[], const macho_nlist symbols
[],
253 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
)
255 int32_t high
= symbolCount
-1;
256 int32_t mid
= symbolCount
/2;
258 for (int32_t low
= 0; low
<= high
; mid
= (low
+high
)/2) {
259 const uint32_t index
= ENDIAN_READ32(toc
[mid
].symbol_index
);
260 const macho_nlist
* pivot
= &symbols
[index
];
261 const char* pivotStr
= &stringPool
[pivot
->n_strx()];
262 int cmp
= strcmp(key
, pivotStr
);
278 const macho_nlist
* Reader::binarySearch(const char* key
, const char stringPool
[], const macho_nlist symbols
[], uint32_t symbolCount
)
280 const macho_nlist
* base
= symbols
;
281 for (uint32_t n
= symbolCount
; n
> 0; n
/= 2) {
282 const macho_nlist
* pivot
= &base
[n
/2];
283 const char* pivotStr
= &stringPool
[pivot
->n_strx()];
284 int cmp
= strcmp(key
, pivotStr
);
289 // move base to symbol after pivot
301 const macho_nlist
* Reader::findExport(const char* name
)
303 if ( fDynamicInfo
->tocoff() == 0 )
304 return binarySearch(name
, fStrings
, &fSymbols
[fDynamicInfo
->iextdefsym()], fDynamicInfo
->nextdefsym());
306 return binarySearchWithToc(name
, fStrings
, fSymbols
, (dylib_table_of_contents
*)((char*)fHeader
+ fDynamicInfo
->tocoff()),
307 fDynamicInfo
->nextdefsym());
311 bool Reader::hasExport(const char* name
)
313 return ( findExport(name
) != NULL
);
316 std::vector
<class ObjectFile::Atom
*>* Reader::getJustInTimeAtomsFor(const char* name
)
318 std::vector
<class ObjectFile::Atom
*>* atoms
= NULL
;
320 if ( this->hasExport(name
) ) {
321 // see if this atom already synthesized
322 ObjectFile::Atom
* atom
= NULL
;
323 Mapper::iterator pos
= fAtoms
.find(name
);
324 if ( pos
!= fAtoms
.end() ) {
328 atom
= new ExportAtom(*this, name
);
331 // return a vector of one atom
332 atoms
= new std::vector
<class ObjectFile::Atom
*>;
333 atoms
->push_back(atom
);
338 for (std::vector
<Reader
*>::iterator it
= fReExportedDylibs
.begin(); it
!= fReExportedDylibs
.end(); it
++) {
339 Reader
* reExportedReader
= *it
;
340 atoms
= reExportedReader
->getJustInTimeAtomsFor(name
);
349 std::vector
<ObjectFile::StabsInfo
>* Reader::getStabsDebugInfo()
354 const char* Reader::getInstallPath()
356 return fDylibID
->name();
359 uint32_t Reader::getTimestamp()
361 return fDylibID
->timestamp();
364 uint32_t Reader::getCurrentVersion()
366 return fDylibID
->current_version();
369 uint32_t Reader::getCompatibilityVersion()
371 return fDylibID
->compatibility_version();
374 std::vector
<const char*>* Reader::getDependentLibraryPaths()
376 std::vector
<const char*>* result
= new std::vector
<const char*>;
377 const uint32_t cmd_count
= fHeader
->ncmds();
378 const macho_load_command
* const cmds
= (macho_load_command
*)((char*)fHeader
+ macho_header::size
);
379 const macho_load_command
* cmd
= cmds
;
380 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
381 switch (cmd
->cmd()) {
383 case LC_LOAD_WEAK_DYLIB
:
385 result
->push_back(((struct macho_dylib_command
*)cmd
)->name());
389 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
394 bool Reader::reExports(ObjectFile::Reader
* child
)
396 // A dependent dylib is re-exported under two conditions:
397 // 1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
399 const uint32_t cmd_count
= fHeader
->ncmds();
400 const macho_load_command
* const cmds
= (macho_load_command
*)((char*)fHeader
+ macho_header::size
);
401 const macho_load_command
* cmd
= cmds
;
402 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
403 switch (cmd
->cmd()) {
404 case LC_SUB_UMBRELLA
:
406 const char* frameworkLeafName
= ((macho_sub_umbrella_command
*)cmd
)->name();
407 const char* dylibName
= child
->getPath();
408 const char* lastSlash
= strrchr(dylibName
, '/');
409 if ( (lastSlash
!= NULL
) && (strcmp(&lastSlash
[1], frameworkLeafName
) == 0) )
415 const char* dylibBaseName
= ((macho_sub_library_command
*)cmd
)->name();
416 const char* dylibName
= child
->getPath();
417 const char* lastSlash
= strrchr(dylibName
, '/');
418 const char* leafStart
= &lastSlash
[1];
419 if ( lastSlash
== NULL
)
420 leafStart
= dylibName
;
421 const char* firstDot
= strchr(leafStart
, '.');
422 int len
= strlen(leafStart
);
423 if ( firstDot
!= NULL
)
424 len
= firstDot
- leafStart
;
425 if ( strncmp(leafStart
, dylibBaseName
, len
) == 0 )
430 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
434 // 2) child contains LC_SUB_FRAMEWORK with parent name
436 const uint32_t cmd_count
= ((Reader
*)child
)->fHeader
->ncmds();
437 const macho_load_command
* const cmds
= (macho_load_command
*)((char*)(((Reader
*)child
)->fHeader
) + macho_header::size
);
438 const macho_load_command
* cmd
= cmds
;
439 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
440 switch (cmd
->cmd()) {
441 case LC_SUB_FRAMEWORK
:
443 const char* frameworkLeafName
= ((macho_sub_framework_command
*)cmd
)->name();
444 const char* parentName
= this->getPath();
445 const char* lastSlash
= strrchr(parentName
, '/');
446 if ( (lastSlash
!= NULL
) && (strcmp(&lastSlash
[1], frameworkLeafName
) == 0) )
451 cmd
= (const macho_load_command
*)(((char*)cmd
)+cmd
->cmdsize());
459 bool Reader::isDefinitionWeak(const ObjectFile::Atom
& atom
)
461 const macho_nlist
* sym
= findExport(atom
.getName());
463 if ( (sym
->n_desc() & N_WEAK_DEF
) != 0 )
471 Reader
* MakeReader(const macho_header
* mh
, const char* path
, const ObjectFile::ReaderOptions
& options
)
473 return new Reader(mh
, path
, options
);