]>
git.saurik.com Git - apple/ld64.git/blob - src/Readers/ObjectFileArchiveMachO.cpp
b01d8a0a170a07947bdd22311b5166e0190be567
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 ObjectFileArchiveMachO
{
29 class Reader
: public ObjectFile::Reader
32 Reader(const uint8_t fileContent
[], uint64_t fileLength
, 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();
44 const char* getName() const;
45 const uint8_t* getContent() const;
46 uint32_t getContentSize() const;
47 const Entry
* getNext() const;
49 bool hasLongName() const;
50 unsigned int getLongNameSpace() const;
54 const struct ranlib
* ranlibBinarySearch(const char* name
);
55 const struct ranlib
* ranlibLinearSearch(const char* name
);
56 ObjectFile::Reader
* makeObjectReaderForMember(const Entry
* member
);
57 void dumpTableOfContents();
60 const ObjectFile::ReaderOptions
& fOptions
;
61 const uint8_t* fFileContent
;
63 const struct ranlib
* fTableOfContents
;
64 uint32_t fTableOfContentCount
;
66 const char* fStringPool
;
67 std::vector
<class ObjectFile::Atom
*> fAllAtoms
;
68 std::set
<const class Entry
*> fInstantiatedEntries
;
70 static std::vector
<class ObjectFile::Atom
*> fgEmptyList
;
73 std::vector
<class ObjectFile::Atom
*> Reader::fgEmptyList
;
75 #undef SwapArchToHostInt32
76 #if defined(ARCH_PPC) || defined(ARCH_PPC64)
77 #define SwapArchToHostInt32(value) OSSwapBigToHostInt32(value)
78 #elif defined(ARCH_I386)
79 #define SwapArchToHostInt32(value) OSSwapLittleToHostInt32(value)
84 bool Reader::Entry::hasLongName() const
86 return ( strncmp(this->ar_name
, AR_EFMT1
, strlen(AR_EFMT1
)) == 0 );
89 unsigned int Reader::Entry::getLongNameSpace() const
92 long result
= strtol(&this->ar_name
[strlen(AR_EFMT1
)], &endptr
, 10);
96 const char* Reader::Entry::getName() const
98 if ( this->hasLongName() ) {
99 int len
= this->getLongNameSpace();
100 static char longName
[256];
101 strncpy(longName
, ((char*)this)+sizeof(ar_hdr
), len
);
102 longName
[len
] = '\0';
106 static char shortName
[20];
107 strncpy(shortName
, this->ar_name
, 16);
108 shortName
[16] = '\0';
109 char* space
= strchr(shortName
, ' ');
117 const uint8_t* Reader::Entry::getContent() const
119 if ( this->hasLongName() )
120 return ((uint8_t*)this) + sizeof(ar_hdr
) + this->getLongNameSpace();
122 return ((uint8_t*)this) + sizeof(ar_hdr
);
126 uint32_t Reader::Entry::getContentSize() const
129 strncpy(temp
, this->ar_size
, 10);
132 long size
= strtol(temp
, &endptr
, 10);
133 // long name is included in ar_size
134 if ( this->hasLongName() )
135 size
-= this->getLongNameSpace();
139 const Reader::Entry
* Reader::Entry::getNext() const
141 const uint8_t* p
= this->getContent() + getContentSize();
142 p
= (const uint8_t*)(((uintptr_t)p
+3) & (-4)); // 4-byte align
143 return (Reader::Entry
*)p
;
148 Reader::Reader(const uint8_t fileContent
[], uint64_t fileLength
, const char* path
, const ObjectFile::ReaderOptions
& options
)
149 : fPath(NULL
), fOptions(options
), fFileContent(NULL
), fTableOfContents(NULL
), fTableOfContentCount(0),
150 fSorted(false), fStringPool(NULL
)
152 fPath
= strdup(path
);
153 fFileContent
= fileContent
;
154 fFileLength
= fileLength
;
156 if ( strncmp((const char*)fileContent
, "!<arch>\n", 8) != 0 )
157 throw "not an archive";
159 if ( !options
.fFullyLoadArchives
) {
160 const Entry
* const firstMember
= (Entry
*)&fFileContent
[8];
161 if ( strcmp(firstMember
->getName(), SYMDEF_SORTED
) == 0 )
163 else if ( strcmp(firstMember
->getName(), SYMDEF
) == 0 )
166 throw "archive has no table of contents";
167 const uint8_t* contents
= firstMember
->getContent();
168 uint32_t ranlibArrayLen
= SwapArchToHostInt32(*((uint32_t*)contents
));
169 fTableOfContents
= (const struct ranlib
*)&contents
[4];
170 fTableOfContentCount
= ranlibArrayLen
/ sizeof(struct ranlib
);
171 fStringPool
= (const char*)&contents
[ranlibArrayLen
+8];
174 if ( options
.fTraceArchives
)
175 printf("[Logging for Build & Integration] Used static archive: %s\n", fPath
);
184 ObjectFile::Reader
* Reader::makeObjectReaderForMember(const Entry
* member
)
186 const char* memberName
= member
->getName();
187 char memberPath
[strlen(fPath
) + strlen(memberName
)+4];
188 strcpy(memberPath
, fPath
);
189 strcat(memberPath
, "(");
190 strcat(memberPath
, memberName
);
191 strcat(memberPath
, ")");
192 //fprintf(stderr, "using %s from %s\n", memberName, fPath);
194 return ObjectFileMachO::MakeReader((class macho_header
*)member
->getContent(), memberPath
, fOptions
);
196 catch (const char* msg
) {
197 throwf("in %s, %s", memberPath
, msg
);
201 const char* Reader::getPath()
206 std::vector
<class ObjectFile::Atom
*>& Reader::getAtoms()
208 if ( fOptions
.fFullyLoadArchives
) {
209 // build vector of all atoms from all .o files in this archive
210 const Entry
* const start
= (Entry
*)&fFileContent
[8];
211 const Entry
* const end
= (Entry
*)&fFileContent
[fFileLength
];
212 for (const Entry
* p
=start
; p
< end
; p
= p
->getNext()) {
213 const char* memberName
= p
->getName();
214 if ( (p
==start
) && (strcmp(memberName
, SYMDEF_SORTED
) == 0) )
216 ObjectFile::Reader
* r
= this->makeObjectReaderForMember(p
);
217 std::vector
<class ObjectFile::Atom
*>& atoms
= r
->getAtoms();
218 fAllAtoms
.insert(fAllAtoms
.end(), atoms
.begin(), atoms
.end());
223 // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
229 const struct ranlib
* Reader::ranlibBinarySearch(const char* key
)
231 const struct ranlib
* base
= fTableOfContents
;
232 for (uint32_t n
= fTableOfContentCount
; n
> 0; n
/= 2) {
233 const struct ranlib
* pivot
= &base
[n
/2];
234 const char* pivotStr
= &fStringPool
[SwapArchToHostInt32(pivot
->ran_un
.ran_strx
)];
235 int cmp
= strcmp(key
, pivotStr
);
240 // move base to symbol after pivot
252 const struct ranlib
* Reader::ranlibLinearSearch(const char* key
)
254 for (uint32_t i
= 0; i
< fTableOfContentCount
; ++i
) {
255 const struct ranlib
* entry
= &fTableOfContents
[i
];
256 const char* entryName
= &fStringPool
[SwapArchToHostInt32(entry
->ran_un
.ran_strx
)];
257 if ( strcmp(key
, entryName
) == 0 )
264 void Reader::dumpTableOfContents()
266 for (unsigned int i
=0; i
< fTableOfContentCount
; ++i
) {
267 const struct ranlib
* e
= &fTableOfContents
[i
];
268 printf("%s in %s\n", &fStringPool
[SwapArchToHostInt32(e
->ran_un
.ran_strx
)], ((Entry
*)&fFileContent
[SwapArchToHostInt32(e
->ran_off
)])->getName());
272 std::vector
<class ObjectFile::Atom
*>* Reader::getJustInTimeAtomsFor(const char* name
)
274 if ( fOptions
.fFullyLoadArchives
) {
278 const struct ranlib
* result
= NULL
;
280 // do a binary search of table of contents looking for requested symbol
281 result
= ranlibBinarySearch(name
);
284 // do a linear search of table of contents looking for requested symbol
285 result
= ranlibLinearSearch(name
);
287 if ( result
!= NULL
) {
288 const Entry
* member
= (Entry
*)&fFileContent
[SwapArchToHostInt32(result
->ran_off
)];
289 if ( fInstantiatedEntries
.count(member
) == 0 ) {
290 // only return these atoms once
291 fInstantiatedEntries
.insert(member
);
292 ObjectFile::Reader
* r
= makeObjectReaderForMember(member
);
293 //fprintf(stderr, "%s found in %s\n", name, member->getName());
294 return new std::vector
<class ObjectFile::Atom
*>(r
->getAtoms());
297 //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
303 std::vector
<ObjectFile::StabsInfo
>* Reader::getStabsDebugInfo()
310 Reader
* MakeReader(const uint8_t fileContent
[], uint64_t fileLength
, const char* path
, const ObjectFile::ReaderOptions
& options
)
312 return new Reader(fileContent
, fileLength
, path
, options
);