]> git.saurik.com Git - apple/ld64.git/blob - src/Readers/ObjectFileArchiveMachO.cpp
b01d8a0a170a07947bdd22311b5166e0190be567
[apple/ld64.git] / src / Readers / ObjectFileArchiveMachO.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
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
26
27 namespace ObjectFileArchiveMachO {
28
29 class Reader : public ObjectFile::Reader
30 {
31 public:
32 Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
33 virtual ~Reader();
34
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
40 private:
41 class Entry : ar_hdr
42 {
43 public:
44 const char* getName() const;
45 const uint8_t* getContent() const;
46 uint32_t getContentSize() const;
47 const Entry* getNext() const;
48 private:
49 bool hasLongName() const;
50 unsigned int getLongNameSpace() const;
51
52 };
53
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();
58
59 const char* fPath;
60 const ObjectFile::ReaderOptions& fOptions;
61 const uint8_t* fFileContent;
62 uint64_t fFileLength;
63 const struct ranlib* fTableOfContents;
64 uint32_t fTableOfContentCount;
65 bool fSorted;
66 const char* fStringPool;
67 std::vector<class ObjectFile::Atom*> fAllAtoms;
68 std::set<const class Entry*> fInstantiatedEntries;
69
70 static std::vector<class ObjectFile::Atom*> fgEmptyList;
71 };
72
73 std::vector<class ObjectFile::Atom*> Reader::fgEmptyList;
74
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)
80 #endif
81
82
83
84 bool Reader::Entry::hasLongName() const
85 {
86 return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
87 }
88
89 unsigned int Reader::Entry::getLongNameSpace() const
90 {
91 char* endptr;
92 long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
93 return result;
94 }
95
96 const char* Reader::Entry::getName() const
97 {
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';
103 return longName;
104 }
105 else {
106 static char shortName[20];
107 strncpy(shortName, this->ar_name, 16);
108 shortName[16] = '\0';
109 char* space = strchr(shortName, ' ');
110 if ( space != NULL )
111 *space = '\0';
112 return shortName;
113 }
114 }
115
116
117 const uint8_t* Reader::Entry::getContent() const
118 {
119 if ( this->hasLongName() )
120 return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
121 else
122 return ((uint8_t*)this) + sizeof(ar_hdr);
123 }
124
125
126 uint32_t Reader::Entry::getContentSize() const
127 {
128 char temp[12];
129 strncpy(temp, this->ar_size, 10);
130 temp[10] = '\0';
131 char* endptr;
132 long size = strtol(temp, &endptr, 10);
133 // long name is included in ar_size
134 if ( this->hasLongName() )
135 size -= this->getLongNameSpace();
136 return size;
137 }
138
139 const Reader::Entry* Reader::Entry::getNext() const
140 {
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;
144 }
145
146
147
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)
151 {
152 fPath = strdup(path);
153 fFileContent = fileContent;
154 fFileLength = fileLength;
155
156 if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
157 throw "not an archive";
158
159 if ( !options.fFullyLoadArchives ) {
160 const Entry* const firstMember = (Entry*)&fFileContent[8];
161 if ( strcmp(firstMember->getName(), SYMDEF_SORTED) == 0 )
162 fSorted = true;
163 else if ( strcmp(firstMember->getName(), SYMDEF) == 0 )
164 fSorted = false;
165 else
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];
172 }
173
174 if ( options.fTraceArchives )
175 printf("[Logging for Build & Integration] Used static archive: %s\n", fPath);
176 }
177
178 Reader::~Reader()
179 {
180 }
181
182
183
184 ObjectFile::Reader* Reader::makeObjectReaderForMember(const Entry* member)
185 {
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);
193 try {
194 return ObjectFileMachO::MakeReader((class macho_header*)member->getContent(), memberPath, fOptions);
195 }
196 catch (const char* msg) {
197 throwf("in %s, %s", memberPath, msg);
198 }
199 }
200
201 const char* Reader::getPath()
202 {
203 return fPath;
204 }
205
206 std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
207 {
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) )
215 continue;
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());
219 }
220 return fAllAtoms;
221 }
222 else {
223 // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
224 return fgEmptyList;
225 }
226 }
227
228
229 const struct ranlib* Reader::ranlibBinarySearch(const char* key)
230 {
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);
236 if ( cmp == 0 )
237 return pivot;
238 if ( cmp > 0 ) {
239 // key > pivot
240 // move base to symbol after pivot
241 base = &pivot[1];
242 --n;
243 }
244 else {
245 // key < pivot
246 // keep same base
247 }
248 }
249 return NULL;
250 }
251
252 const struct ranlib* Reader::ranlibLinearSearch(const char* key)
253 {
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 )
258 return entry;
259 }
260 return NULL;
261 }
262
263
264 void Reader::dumpTableOfContents()
265 {
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());
269 }
270 }
271
272 std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
273 {
274 if ( fOptions.fFullyLoadArchives ) {
275 return NULL;
276 }
277 else {
278 const struct ranlib* result = NULL;
279 if ( fSorted ) {
280 // do a binary search of table of contents looking for requested symbol
281 result = ranlibBinarySearch(name);
282 }
283 else {
284 // do a linear search of table of contents looking for requested symbol
285 result = ranlibLinearSearch(name);
286 }
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());
295 }
296 }
297 //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
298 return NULL;
299 }
300 }
301
302
303 std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
304 {
305 return NULL;
306 }
307
308
309
310 Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
311 {
312 return new Reader(fileContent, fileLength, path, options);
313 }
314
315
316
317 };
318
319
320
321
322
323
324