]> git.saurik.com Git - apple/ld64.git/blob - src/Readers/ObjectFileArchiveMachO.cpp
a6851a1d3e537a5ee83647d926c7fd3b6084670c
[apple/ld64.git] / src / Readers / ObjectFileArchiveMachO.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25
26 namespace ObjectFileArchiveMachO {
27
28 class Reader : public ObjectFile::Reader
29 {
30 public:
31 Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
32 virtual ~Reader();
33
34 virtual const char* getPath();
35 virtual std::vector<class ObjectFile::Atom*>& getAtoms();
36 virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
37 virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
38
39 private:
40 class Entry : ar_hdr
41 {
42 public:
43 const char* getName() const;
44 const uint8_t* getContent() const;
45 uint32_t getContentSize() const;
46 const Entry* getNext() const;
47 private:
48 bool hasLongName() const;
49 unsigned int getLongNameSpace() const;
50
51 };
52
53 const struct ranlib* ranlibBinarySearch(const char* name);
54 const struct ranlib* ranlibLinearSearch(const char* name);
55 ObjectFile::Reader* makeObjectReaderForMember(const Entry* member);
56 void dumpTableOfContents();
57
58 const char* fPath;
59 const ObjectFile::ReaderOptions& fOptions;
60 const uint8_t* fFileContent;
61 uint64_t fFileLength;
62 const struct ranlib* fTableOfContents;
63 uint32_t fTableOfContentCount;
64 bool fSorted;
65 const char* fStringPool;
66 std::vector<class ObjectFile::Atom*> fAllAtoms;
67 std::set<const class Entry*> fInstantiatedEntries;
68
69 static std::vector<class ObjectFile::Atom*> fgEmptyList;
70 };
71
72 std::vector<class ObjectFile::Atom*> Reader::fgEmptyList;
73
74
75 bool Reader::Entry::hasLongName() const
76 {
77 return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
78 }
79
80 unsigned int Reader::Entry::getLongNameSpace() const
81 {
82 char* endptr;
83 long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
84 return result;
85 }
86
87 const char* Reader::Entry::getName() const
88 {
89 if ( this->hasLongName() ) {
90 int len = this->getLongNameSpace();
91 static char longName[256];
92 strncpy(longName, ((char*)this)+sizeof(ar_hdr), len);
93 longName[len] = '\0';
94 return longName;
95 }
96 else {
97 static char shortName[20];
98 strncpy(shortName, this->ar_name, 16);
99 shortName[16] = '\0';
100 char* space = strchr(shortName, ' ');
101 if ( space != NULL )
102 *space = '\0';
103 return shortName;
104 }
105 }
106
107
108 const uint8_t* Reader::Entry::getContent() const
109 {
110 if ( this->hasLongName() )
111 return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
112 else
113 return ((uint8_t*)this) + sizeof(ar_hdr);
114 }
115
116
117 uint32_t Reader::Entry::getContentSize() const
118 {
119 char temp[12];
120 strncpy(temp, this->ar_size, 10);
121 temp[10] = '\0';
122 char* endptr;
123 long size = strtol(temp, &endptr, 10);
124 // long name is included in ar_size
125 if ( this->hasLongName() )
126 size -= this->getLongNameSpace();
127 return size;
128 }
129
130 const Reader::Entry* Reader::Entry::getNext() const
131 {
132 const uint8_t* p = this->getContent() + getContentSize();
133 p = (const uint8_t*)(((uint32_t)p+3) & (-4)); // 4-byte align
134 return (Reader::Entry*)p;
135 }
136
137
138
139 Reader::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
140 : fPath(NULL), fOptions(options), fFileContent(NULL), fTableOfContents(NULL), fTableOfContentCount(0),
141 fSorted(false), fStringPool(NULL)
142 {
143 fPath = strdup(path);
144 fFileContent = fileContent;
145 fFileLength = fileLength;
146
147 if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
148 throw "not an archive";
149
150 if ( !options.fFullyLoadArchives ) {
151 const Entry* const firstMember = (Entry*)&fFileContent[8];
152 if ( strcmp(firstMember->getName(), SYMDEF_SORTED) == 0 )
153 fSorted = true;
154 else if ( strcmp(firstMember->getName(), SYMDEF) == 0 )
155 fSorted = false;
156 else
157 throw "archive has no table of contents";
158 const uint8_t* contents = firstMember->getContent();
159 uint32_t ranlibArrayLen = OSReadBigInt32((void *) contents, 0);
160 fTableOfContents = (const struct ranlib*)&contents[4];
161 fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
162 fStringPool = (const char*)&contents[ranlibArrayLen+8];
163 }
164
165 if ( options.fTraceArchives )
166 printf("[Logging for Build & Integration] Used static archive: %s\n", fPath);
167 }
168
169 Reader::~Reader()
170 {
171 }
172
173
174
175 ObjectFile::Reader* Reader::makeObjectReaderForMember(const Entry* member)
176 {
177 const char* memberName = member->getName();
178 char memberPath[strlen(fPath) + strlen(memberName)+4];
179 strcpy(memberPath, fPath);
180 strcat(memberPath, "(");
181 strcat(memberPath, memberName);
182 strcat(memberPath, ")");
183 //fprintf(stderr, "using %s from %s\n", memberName, fPath);
184 try {
185 return ObjectFileMachO::MakeReader((class macho_header*)member->getContent(), memberPath, fOptions);
186 }
187 catch (const char* msg) {
188 throwf("in %s, %s", memberPath, msg);
189 }
190 }
191
192 const char* Reader::getPath()
193 {
194 return fPath;
195 }
196
197 std::vector<class ObjectFile::Atom*>& Reader::getAtoms()
198 {
199 if ( fOptions.fFullyLoadArchives ) {
200 // build vector of all atoms from all .o files in this archive
201 const Entry* const start = (Entry*)&fFileContent[8];
202 const Entry* const end = (Entry*)&fFileContent[fFileLength];
203 for (const Entry* p=start; p < end; p = p->getNext()) {
204 const char* memberName = p->getName();
205 if ( (p==start) && (strcmp(memberName, SYMDEF_SORTED) == 0) )
206 continue;
207 ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
208 std::vector<class ObjectFile::Atom*>& atoms = r->getAtoms();
209 fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
210 }
211 return fAllAtoms;
212 }
213 else {
214 // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
215 return fgEmptyList;
216 }
217 }
218
219
220 const struct ranlib* Reader::ranlibBinarySearch(const char* key)
221 {
222 const struct ranlib* base = fTableOfContents;
223 for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
224 const struct ranlib* pivot = &base[n/2];
225 const char* pivotStr = &fStringPool[OSSwapBigToHostInt32(pivot->ran_un.ran_strx)];
226 int cmp = strcmp(key, pivotStr);
227 if ( cmp == 0 )
228 return pivot;
229 if ( cmp > 0 ) {
230 // key > pivot
231 // move base to symbol after pivot
232 base = &pivot[1];
233 --n;
234 }
235 else {
236 // key < pivot
237 // keep same base
238 }
239 }
240 return NULL;
241 }
242
243 const struct ranlib* Reader::ranlibLinearSearch(const char* key)
244 {
245 for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
246 const struct ranlib* entry = &fTableOfContents[i];
247 const char* entryName = &fStringPool[OSSwapBigToHostInt32(entry->ran_un.ran_strx)];
248 if ( strcmp(key, entryName) == 0 )
249 return entry;
250 }
251 return NULL;
252 }
253
254
255 void Reader::dumpTableOfContents()
256 {
257 for (unsigned int i=0; i < fTableOfContentCount; ++i) {
258 const struct ranlib* e = &fTableOfContents[i];
259 printf("%s in %s\n", &fStringPool[OSSwapBigToHostInt32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[OSSwapBigToHostInt32(e->ran_off)])->getName());
260 }
261 }
262
263 std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
264 {
265 if ( fOptions.fFullyLoadArchives ) {
266 return NULL;
267 }
268 else {
269 const struct ranlib* result = NULL;
270 if ( fSorted ) {
271 // do a binary search of table of contents lookig for requested symbol
272 result = ranlibBinarySearch(name);
273 }
274 else {
275 // do a linear search of table of contents lookig for requested symbol
276 result = ranlibLinearSearch(name);
277 }
278 if ( result != NULL ) {
279 const Entry* member = (Entry*)&fFileContent[OSSwapBigToHostInt32(result->ran_off)];
280 //fprintf(stderr, "%s found in %s\n", name, member->getName());
281 if ( fInstantiatedEntries.count(member) == 0 ) {
282 // only return these atoms once
283 fInstantiatedEntries.insert(member);
284 ObjectFile::Reader* r = makeObjectReaderForMember(member);
285 return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
286 }
287 }
288 //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
289 return NULL;
290 }
291 }
292
293
294 std::vector<ObjectFile::StabsInfo>* Reader::getStabsDebugInfo()
295 {
296 return NULL;
297 }
298
299
300
301 Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
302 {
303 return new Reader(fileContent, fileLength, path, options);
304 }
305
306
307
308 };
309
310
311
312
313
314
315