]> git.saurik.com Git - apple/dyld.git/blob - dyld3/shared-cache/ObjC2Abstraction.hpp
dyld-733.6.tar.gz
[apple/dyld.git] / dyld3 / shared-cache / ObjC2Abstraction.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008-2010 Apple 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 #include <iterator>
26 #include <deque>
27 #include <set>
28
29
30 // iterate an entsize-based list
31 // typedef entsize_iterator<P, type_t<P>, type_list_t<P> > type_iterator;
32 template <typename P, typename T, typename Tlist>
33 struct entsize_iterator {
34 uint32_t entsize;
35 uint32_t index; // keeping track of this saves a divide in operator-
36 T* current;
37
38 typedef std::random_access_iterator_tag iterator_category;
39 typedef T value_type;
40 typedef ptrdiff_t difference_type;
41 typedef T* pointer;
42 typedef T& reference;
43
44 entsize_iterator() { }
45
46 entsize_iterator(const Tlist& list, uint32_t start = 0)
47 : entsize(list.getEntsize()), index(start), current(&list.get(start))
48 { }
49
50 const entsize_iterator<P,T,Tlist>& operator += (ptrdiff_t count) {
51 current = (T*)((uint8_t *)current + count*entsize);
52 index += count;
53 return *this;
54 }
55 const entsize_iterator<P,T,Tlist>& operator -= (ptrdiff_t count) {
56 current = (T*)((uint8_t *)current - count*entsize);
57 index -= count;
58 return *this;
59 }
60 const entsize_iterator<P,T,Tlist> operator + (ptrdiff_t count) const {
61 return entsize_iterator(*this) += count;
62 }
63 const entsize_iterator<P,T,Tlist> operator - (ptrdiff_t count) const {
64 return entsize_iterator(*this) -= count;
65 }
66
67 entsize_iterator<P,T,Tlist>& operator ++ () { *this += 1; return *this; }
68 entsize_iterator<P,T,Tlist>& operator -- () { *this -= 1; return *this; }
69 entsize_iterator<P,T,Tlist> operator ++ (int) {
70 entsize_iterator<P,T,Tlist> result(*this); *this += 1; return result;
71 }
72 entsize_iterator<P,T,Tlist> operator -- (int) {
73 entsize_iterator<P,T,Tlist> result(*this); *this -= 1; return result;
74 }
75
76 ptrdiff_t operator - (const entsize_iterator<P,T,Tlist>& rhs) const {
77 return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
78 }
79
80 T& operator * () { return *current; }
81 T& operator * () const { return *current; }
82 T& operator -> () { return *current; }
83 const T& operator -> () const { return *current; }
84
85 operator T& () const { return *current; }
86
87 bool operator == (const entsize_iterator<P,T,Tlist>& rhs) {
88 return this->current == rhs.current;
89 }
90 bool operator != (const entsize_iterator<P,T,Tlist>& rhs) {
91 return this->current != rhs.current;
92 }
93
94 bool operator < (const entsize_iterator<P,T,Tlist>& rhs) {
95 return this->current < rhs.current;
96 }
97 bool operator > (const entsize_iterator<P,T,Tlist>& rhs) {
98 return this->current > rhs.current;
99 }
100
101
102 static void overwrite(entsize_iterator<P,T,Tlist>& dst, const Tlist* srcList)
103 {
104 entsize_iterator<P,T,Tlist> src;
105 uint32_t ee = srcList->getEntsize();
106 for (src = srcList->begin(); src != srcList->end(); ++src) {
107 memcpy(&*dst, &*src, ee);
108 ++dst;
109 }
110 }
111 };
112
113 template <typename P>
114 class objc_header_info_rw_t {
115
116 typedef typename P::uint_t pint_t;
117
118 pint_t data; // loaded:1, allRealised:1, objc_header_info *:ptr
119
120 public:
121 objc_header_info_rw_t(ContentAccessor* cache, const macho_header<P>* mh)
122 : data(0) {
123 }
124 };
125
126 template <typename P>
127 class objc_header_info_ro_t {
128
129 typedef typename P::uint_t pint_t;
130
131 pint_t mhdr_offset; // offset to mach_header or mach_header_64
132 pint_t info_offset; // offset to objc_image_info *
133
134 public:
135 objc_header_info_ro_t(ContentAccessor* cache, const macho_header<P>* mh)
136 : mhdr_offset(0), info_offset(0) {
137 P::setP(mhdr_offset, (uint64_t)cache->vmAddrForContent((void*)mh) - (uint64_t)cache->vmAddrForContent(&mhdr_offset));
138 assert(header_vmaddr(cache) == (uint64_t)cache->vmAddrForContent((void*)mh));
139 const macho_section<P>* sect = mh->getSection("__DATA", "__objc_imageinfo");
140 if (sect) {
141 P::setP(info_offset, (uint64_t)sect->addr() - (uint64_t)cache->vmAddrForContent(&info_offset));
142 // set bit in mach_header.flags to tell dyld that this image has objc content
143 macho_header<P>* rwmh = const_cast<macho_header<P>*>(mh);
144 rwmh->set_flags(mh->flags() | MH_HAS_OBJC);
145 }
146 else
147 P::setP(info_offset, - (uint64_t)cache->vmAddrForContent(&info_offset));
148 }
149
150 pint_t header_vmaddr(ContentAccessor* cache) const {
151 return (pint_t)(((uint64_t)cache->vmAddrForContent(&mhdr_offset)) + mhdr_offset);
152 }
153 };
154
155
156 template <typename P>
157 class objc_method_list_t; // forward reference
158
159
160 template <typename P>
161 class objc_method_t {
162 typedef typename P::uint_t pint_t;
163 pint_t name; // SEL
164 pint_t types; // const char *
165 pint_t imp; // IMP
166 friend class objc_method_list_t<P>;
167 public:
168 pint_t getName() const { return (pint_t)P::getP(name); }
169 void setName(pint_t newName) { P::setP(name, newName); }
170
171 struct SortBySELAddress :
172 public std::binary_function<const objc_method_t<P>&,
173 const objc_method_t<P>&, bool>
174 {
175 bool operator() (const objc_method_t<P>& lhs,
176 const objc_method_t<P>& rhs)
177 {
178 return lhs.getName() < rhs.getName();
179 }
180 };
181 };
182
183 template <typename P>
184 class objc_method_list_t {
185 uint32_t entsize;
186 uint32_t count;
187 objc_method_t<P> first;
188
189 void* operator new (size_t, void* buf) { return buf; }
190
191 public:
192
193 typedef entsize_iterator<P, objc_method_t<P>, objc_method_list_t<P> > method_iterator;
194
195 uint32_t getCount() const { return P::E::get32(count); }
196
197 uint32_t getEntsize() const {return P::E::get32(entsize)&~(uint32_t)3;}
198
199 objc_method_t<P>& get(uint32_t i) const { return *(objc_method_t<P> *)((uint8_t *)&first + i * getEntsize()); }
200
201 uint32_t byteSize() const {
202 return byteSizeForCount(getCount(), getEntsize());
203 }
204
205 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_method_t<P>)) {
206 return sizeof(objc_method_list_t<P>) - sizeof(objc_method_t<P>) + c*e;
207 }
208
209 method_iterator begin() { return method_iterator(*this, 0); }
210 method_iterator end() { return method_iterator(*this, getCount()); }
211 const method_iterator begin() const { return method_iterator(*this, 0); }
212 const method_iterator end() const { return method_iterator(*this, getCount()); }
213
214 void setFixedUp() { P::E::set32(entsize, getEntsize() | 3); }
215
216 void getPointers(std::set<void*>& pointersToRemove) {
217 for(method_iterator it = begin(); it != end(); ++it) {
218 objc_method_t<P>& entry = *it;
219 pointersToRemove.insert(&(entry.name));
220 pointersToRemove.insert(&(entry.types));
221 pointersToRemove.insert(&(entry.imp));
222 }
223 }
224
225 static void addPointers(uint8_t* methodList, CacheBuilder::ASLR_Tracker& aslrTracker) {
226 objc_method_list_t<P>* mlist = (objc_method_list_t<P>*)methodList;
227 for(method_iterator it = mlist->begin(); it != mlist->end(); ++it) {
228 objc_method_t<P>& entry = *it;
229 aslrTracker.add(&(entry.name));
230 aslrTracker.add(&(entry.types));
231 aslrTracker.add(&(entry.imp));
232 }
233 }
234
235 static objc_method_list_t<P>* newMethodList(size_t newCount, uint32_t newEntsize) {
236 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
237 return new (buf) objc_method_list_t<P>(newCount, newEntsize);
238 }
239
240 void operator delete(void * p) {
241 ::free(p);
242 }
243
244 objc_method_list_t(uint32_t newCount,
245 uint32_t newEntsize = sizeof(objc_method_t<P>))
246 : entsize(newEntsize), count(newCount)
247 { }
248
249 private:
250 // use newMethodList instead
251 void* operator new (size_t);
252 };
253
254
255 template <typename P>
256 class objc_ivar_t {
257 typedef typename P::uint_t pint_t;
258
259 pint_t offset; // uint32_t* (uint64_t* on x86_64)
260 pint_t name; // const char*
261 pint_t type; // const char*
262 uint32_t alignment;
263 uint32_t size;
264
265 public:
266 const char* getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
267
268 bool hasOffset() const { return offset != 0; }
269 uint32_t getOffset(ContentAccessor* cache) const { return P::E::get32(*(uint32_t*)(cache->contentForVMAddr(P::getP(offset)))); }
270 void setOffset(ContentAccessor* cache, uint32_t newOffset) { P::E::set32(*(uint32_t*)(cache->contentForVMAddr(P::getP(offset))), newOffset); }
271
272
273 uint32_t getAlignment() {
274 uint32_t a = P::E::get32(alignment);
275 return (a == (uint32_t)-1) ? sizeof(pint_t) : 1<<a;
276 }
277 };
278
279 template <typename P>
280 class objc_ivar_list_t {
281 typedef typename P::uint_t pint_t;
282 uint32_t entsize;
283 uint32_t count;
284 objc_ivar_t<P> first;
285
286 void* operator new (size_t, void* buf) { return buf; }
287
288 public:
289
290 typedef entsize_iterator<P, objc_ivar_t<P>, objc_ivar_list_t<P> > ivar_iterator;
291
292 uint32_t getCount() const { return P::E::get32(count); }
293
294 uint32_t getEntsize() const { return P::E::get32(entsize); }
295
296 objc_ivar_t<P>& get(pint_t i) const { return *(objc_ivar_t<P> *)((uint8_t *)&first + i * P::E::get32(entsize)); }
297
298 uint32_t byteSize() const {
299 return byteSizeForCount(getCount(), getEntsize());
300 }
301
302 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_ivar_t<P>)) {
303 return sizeof(objc_ivar_list_t<P>) - sizeof(objc_ivar_t<P>) + c*e;
304 }
305
306 ivar_iterator begin() { return ivar_iterator(*this, 0); }
307 ivar_iterator end() { return ivar_iterator(*this, getCount()); }
308 const ivar_iterator begin() const { return ivar_iterator(*this, 0); }
309 const ivar_iterator end() const { return ivar_iterator(*this, getCount()); }
310
311 static objc_ivar_list_t<P>* newIvarList(size_t newCount, uint32_t newEntsize) {
312 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
313 return new (buf) objc_ivar_list_t<P>(newCount, newEntsize);
314 }
315
316 void operator delete(void * p) {
317 ::free(p);
318 }
319
320 objc_ivar_list_t(uint32_t newCount,
321 uint32_t newEntsize = sizeof(objc_ivar_t<P>))
322 : entsize(newEntsize), count(newCount)
323 { }
324 private:
325 // use newIvarList instead
326 void* operator new (size_t);
327 };
328
329
330 template <typename P> class objc_property_list_t; // forward
331
332 template <typename P>
333 class objc_property_t {
334 typedef typename P::uint_t pint_t;
335 pint_t name;
336 pint_t attributes;
337 friend class objc_property_list_t<P>;
338 public:
339
340 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
341
342 const char * getAttributes(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(attributes)); }
343 };
344
345 template <typename P>
346 class objc_property_list_t {
347 uint32_t entsize;
348 uint32_t count;
349 objc_property_t<P> first;
350
351 void* operator new (size_t, void* buf) { return buf; }
352
353 public:
354
355 typedef entsize_iterator<P, objc_property_t<P>, objc_property_list_t<P> > property_iterator;
356
357 uint32_t getCount() const { return P::E::get32(count); }
358
359 uint32_t getEntsize() const { return P::E::get32(entsize); }
360
361 objc_property_t<P>& get(uint32_t i) const { return *(objc_property_t<P> *)((uint8_t *)&first + i * getEntsize()); }
362
363 uint32_t byteSize() const {
364 return byteSizeForCount(getCount(), getEntsize());
365 }
366
367 static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_property_t<P>)) {
368 return sizeof(objc_property_list_t<P>) - sizeof(objc_property_t<P>) + c*e;
369 }
370
371 property_iterator begin() { return property_iterator(*this, 0); }
372 property_iterator end() { return property_iterator(*this, getCount()); }
373 const property_iterator begin() const { return property_iterator(*this, 0); }
374 const property_iterator end() const { return property_iterator(*this, getCount()); }
375
376 void getPointers(std::set<void*>& pointersToRemove) {
377 for(property_iterator it = begin(); it != end(); ++it) {
378 objc_property_t<P>& entry = *it;
379 pointersToRemove.insert(&(entry.name));
380 pointersToRemove.insert(&(entry.attributes));
381 }
382 }
383
384 static void addPointers(uint8_t* propertyList, CacheBuilder::ASLR_Tracker& aslrTracker) {
385 objc_property_list_t<P>* plist = (objc_property_list_t<P>*)propertyList;
386 for(property_iterator it = plist->begin(); it != plist->end(); ++it) {
387 objc_property_t<P>& entry = *it;
388 aslrTracker.add(&(entry.name));
389 aslrTracker.add(&(entry.attributes));
390 }
391 }
392
393 static objc_property_list_t<P>* newPropertyList(size_t newCount, uint32_t newEntsize) {
394 void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
395 return new (buf) objc_property_list_t<P>(newCount, newEntsize);
396 }
397
398 void operator delete(void * p) {
399 ::free(p);
400 }
401
402 objc_property_list_t(uint32_t newCount,
403 uint32_t newEntsize = sizeof(objc_property_t<P>))
404 : entsize(newEntsize), count(newCount)
405 { }
406 private:
407 // use newPropertyList instead
408 void* operator new (size_t);
409 };
410
411
412 template <typename A> class objc_protocol_list_t; // forward reference
413
414 template <typename P>
415 class objc_protocol_t {
416 typedef typename P::uint_t pint_t;
417
418 pint_t isa;
419 pint_t name;
420 pint_t protocols;
421 pint_t instanceMethods;
422 pint_t classMethods;
423 pint_t optionalInstanceMethods;
424 pint_t optionalClassMethods;
425 pint_t instanceProperties;
426 uint32_t size;
427 uint32_t flags;
428 pint_t extendedMethodTypes;
429 pint_t demangledName;
430 pint_t classProperties;
431
432 public:
433 pint_t getIsaVMAddr() const { return (pint_t)P::getP(isa); }
434 void setIsaVMAddr(pint_t newIsa) { P::setP(isa, newIsa); }
435
436 const char *getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
437
438 uint32_t getSize() const { return P::E::get32(size); }
439 void setSize(uint32_t newSize) { P::E::set32(size, newSize); }
440
441 uint32_t getFlags() const { return P::E::get32(flags); }
442
443 void setFixedUp() { P::E::set32(flags, getFlags() | (1<<30)); }
444 void setIsCanonical() {
445 assert((getFlags() & (1 << 29)) == 0);
446 P::E::set32(flags, getFlags() | (1<<29));
447 }
448
449 objc_protocol_list_t<P> *getProtocols(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(protocols)); }
450
451 objc_method_list_t<P> *getInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(instanceMethods)); }
452
453 objc_method_list_t<P> *getClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(classMethods)); }
454
455 objc_method_list_t<P> *getOptionalInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(optionalInstanceMethods)); }
456
457 objc_method_list_t<P> *getOptionalClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(optionalClassMethods)); }
458
459 objc_property_list_t<P> *getInstanceProperties(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(instanceProperties)); }
460
461 pint_t *getExtendedMethodTypes(ContentAccessor* cache) const {
462 if (getSize() < offsetof(objc_protocol_t<P>, extendedMethodTypes) + sizeof(extendedMethodTypes)) {
463 return NULL;
464 }
465 return (pint_t *)cache->contentForVMAddr(P::getP(extendedMethodTypes));
466 }
467
468 const char *getDemangledName(ContentAccessor* cache) const {
469 if (sizeof(*this) < offsetof(objc_protocol_t<P>, demangledName) + sizeof(demangledName)) {
470 return NULL;
471 }
472 return (const char *)cache->contentForVMAddr(P::getP(demangledName));
473 }
474
475 void setDemangledName(ContentAccessor* cache, const char *newName, Diagnostics& diag) {
476 if (sizeof(*this) < offsetof(objc_protocol_t<P>, demangledName) + sizeof(demangledName))
477 diag.error("objc protocol has the wrong size");
478 else
479 P::setP(demangledName, cache->vmAddrForContent((void*)newName));
480 }
481
482 void addPointers(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker)
483 {
484 aslrTracker.add(&isa);
485 aslrTracker.add(&name);
486 if (protocols) aslrTracker.add(&protocols);
487 if (instanceMethods) aslrTracker.add(&instanceMethods);
488 if (classMethods) aslrTracker.add(&classMethods);
489 if (optionalInstanceMethods) aslrTracker.add(&optionalInstanceMethods);
490 if (optionalClassMethods) aslrTracker.add(&optionalClassMethods);
491 if (instanceProperties) aslrTracker.add(&instanceProperties);
492 if (extendedMethodTypes) aslrTracker.add(&extendedMethodTypes);
493 if (demangledName) aslrTracker.add(&demangledName);
494 }
495 };
496
497
498 template <typename P>
499 class objc_protocol_list_t {
500 typedef typename P::uint_t pint_t;
501 pint_t count;
502 pint_t list[0];
503
504 void* operator new (size_t, void* buf) { return buf; }
505
506 public:
507
508 pint_t getCount() const { return (pint_t)P::getP(count); }
509
510 pint_t getVMAddress(pint_t i) {
511 return (pint_t)P::getP(list[i]);
512 }
513
514 objc_protocol_t<P>* get(ContentAccessor* cache, pint_t i) {
515 return (objc_protocol_t<P>*)cache->contentForVMAddr(getVMAddress(i));
516 }
517
518 void setVMAddress(pint_t i, pint_t protoVMAddr) {
519 P::setP(list[i], protoVMAddr);
520 }
521
522 void set(ContentAccessor* cache, pint_t i, objc_protocol_t<P>* proto) {
523 setVMAddress(i, cache->vmAddrForContent(proto));
524 }
525
526 uint32_t byteSize() const {
527 return byteSizeForCount(getCount());
528 }
529 static uint32_t byteSizeForCount(pint_t c) {
530 return sizeof(objc_protocol_list_t<P>) + c*sizeof(pint_t);
531 }
532
533 void getPointers(std::set<void*>& pointersToRemove) {
534 for(int i=0 ; i < count; ++i) {
535 pointersToRemove.insert(&list[i]);
536 }
537 }
538
539 static void addPointers(uint8_t* protocolList, CacheBuilder::ASLR_Tracker& aslrTracker) {
540 objc_protocol_list_t<P>* plist = (objc_protocol_list_t<P>*)protocolList;
541 for(int i=0 ; i < plist->count; ++i) {
542 aslrTracker.add(&plist->list[i]);
543 }
544 }
545
546 static objc_protocol_list_t<P>* newProtocolList(pint_t newCount) {
547 void *buf = ::calloc(byteSizeForCount(newCount), 1);
548 return new (buf) objc_protocol_list_t<P>(newCount);
549 }
550
551 void operator delete(void * p) {
552 ::free(p);
553 }
554
555 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
556 private:
557 // use newProtocolList instead
558 void* operator new (size_t);
559 };
560
561
562 template <typename P>
563 class objc_class_data_t {
564 typedef typename P::uint_t pint_t;
565 uint32_t flags;
566 uint32_t instanceStart;
567 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
568 // on 64-bit archs, but no padding on 32-bit archs.
569 // This union is a way to model that.
570 union {
571 uint32_t instanceSize;
572 pint_t pad;
573 } instanceSize;
574 pint_t ivarLayout;
575 pint_t name;
576 pint_t baseMethods;
577 pint_t baseProtocols;
578 pint_t ivars;
579 pint_t weakIvarLayout;
580 pint_t baseProperties;
581
582 public:
583 bool isMetaClass() { return P::E::get32(flags) & (1 << 0); }
584 bool isRootClass() { return P::E::get32(flags) & (1 << 1); }
585
586 uint32_t getInstanceStart() { return P::E::get32(instanceStart); }
587 void setInstanceStart(uint32_t newStart) { P::E::set32(instanceStart, newStart); }
588
589 uint32_t getInstanceSize() { return P::E::get32(instanceSize.instanceSize); }
590 void setInstanceSize(uint32_t newSiz) { P::E::set32(instanceSize.instanceSize, newSiz); }
591
592 objc_method_list_t<P> *getMethodList(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(baseMethods)); }
593
594 objc_protocol_list_t<P> *getProtocolList(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(baseProtocols)); }
595
596 objc_ivar_list_t<P> *getIvarList(ContentAccessor* cache) const { return (objc_ivar_list_t<P> *)cache->contentForVMAddr(P::getP(ivars)); }
597
598 objc_property_list_t<P> *getPropertyList(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(baseProperties)); }
599
600 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
601
602 void setMethodList(ContentAccessor* cache, objc_method_list_t<P>* mlist) {
603 P::setP(baseMethods, cache->vmAddrForContent(mlist));
604 }
605
606 void setProtocolList(ContentAccessor* cache, objc_protocol_list_t<P>* protolist) {
607 P::setP(baseProtocols, cache->vmAddrForContent(protolist));
608 }
609
610 void setPropertyList(ContentAccessor* cache, objc_property_list_t<P>* proplist) {
611 P::setP(baseProperties, cache->vmAddrForContent(proplist));
612 }
613
614 void addMethodListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
615 aslrTracker.add(&this->baseMethods);
616 }
617
618 void addPropertyListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
619 aslrTracker.add(&this->baseProperties);
620 }
621
622 void addProtocolListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
623 aslrTracker.add(&this->baseProtocols);
624 }
625 };
626
627 template <typename P>
628 class objc_class_t {
629 typedef typename P::uint_t pint_t;
630
631 pint_t isa;
632 pint_t superclass;
633 pint_t method_cache;
634 pint_t vtable;
635 pint_t data;
636
637 public:
638 bool isMetaClass(ContentAccessor* cache) const { return getData(cache)->isMetaClass(); }
639 bool isRootClass(ContentAccessor* cache) const { return getData(cache)->isRootClass(); }
640
641 objc_class_t<P> *getIsa(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(isa)); }
642
643 objc_class_t<P> *getSuperclass(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(superclass)); }
644
645 const pint_t* getSuperClassAddress() const { return &superclass; }
646
647 // Low bit marks Swift classes.
648 objc_class_data_t<P> *getData(ContentAccessor* cache) const { return (objc_class_data_t<P> *)cache->contentForVMAddr(P::getP(data & ~0x3LL)); }
649
650 objc_method_list_t<P> *getMethodList(ContentAccessor* cache) const {
651 objc_class_data_t<P>* d = getData(cache);
652 return d->getMethodList(cache);
653 }
654
655 objc_protocol_list_t<P> *getProtocolList(ContentAccessor* cache) const { return getData(cache)->getProtocolList(cache); }
656
657 objc_property_list_t<P> *getPropertyList(ContentAccessor* cache) const { return getData(cache)->getPropertyList(cache); }
658
659 const char* getName(ContentAccessor* cache) const {
660 return getData(cache)->getName(cache);
661 }
662
663 void setMethodList(ContentAccessor* cache, objc_method_list_t<P>* mlist) {
664 getData(cache)->setMethodList(cache, mlist);
665 }
666
667 void setProtocolList(ContentAccessor* cache, objc_protocol_list_t<P>* protolist) {
668 getData(cache)->setProtocolList(cache, protolist);
669 }
670
671 void setPropertyList(ContentAccessor* cache, objc_property_list_t<P>* proplist) {
672 getData(cache)->setPropertyList(cache, proplist);
673 }
674
675 void addMethodListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
676 getData(cache)->addMethodListPointer(aslrTracker);
677 }
678
679 void addPropertyListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
680 getData(cache)->addPropertyListPointer(aslrTracker);
681 }
682
683 void addProtocolListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
684 getData(cache)->addProtocolListPointer(aslrTracker);
685 }
686
687 };
688
689
690
691 template <typename P>
692 class objc_category_t {
693 typedef typename P::uint_t pint_t;
694
695 pint_t name;
696 pint_t cls;
697 pint_t instanceMethods;
698 pint_t classMethods;
699 pint_t protocols;
700 pint_t instanceProperties;
701
702 public:
703
704 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
705
706 objc_class_t<P> *getClass(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(cls)); }
707
708 objc_method_list_t<P> *getInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(instanceMethods)); }
709
710 objc_method_list_t<P> *getClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(classMethods)); }
711
712 objc_protocol_list_t<P> *getProtocols(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(protocols)); }
713
714 objc_property_list_t<P> *getInstanceProperties(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(instanceProperties)); }
715
716 void getPointers(std::set<void*>& pointersToRemove) {
717 pointersToRemove.insert(&name);
718 pointersToRemove.insert(&cls);
719 pointersToRemove.insert(&instanceMethods);
720 pointersToRemove.insert(&classMethods);
721 pointersToRemove.insert(&protocols);
722 pointersToRemove.insert(&instanceProperties);
723 }
724
725
726 };
727
728 template <typename P>
729 class objc_message_ref_t {
730 typedef typename P::uint_t pint_t;
731
732 pint_t imp;
733 pint_t sel;
734
735 public:
736 pint_t getName() const { return (pint_t)P::getP(sel); }
737
738 void setName(pint_t newName) { P::setP(sel, newName); }
739 };
740
741 // Call visitor.visitIvar() on every ivar in a given class.
742 template <typename P, typename V>
743 class IvarWalker {
744 typedef typename P::uint_t pint_t;
745 V& ivarVisitor;
746 public:
747
748 IvarWalker(V& visitor) : ivarVisitor(visitor) { }
749
750 void walk(ContentAccessor* cache, const macho_header<P>* header, objc_class_t<P> *cls)
751 {
752 objc_class_data_t<P> *data = cls->getData(cache);
753 objc_ivar_list_t<P> *ivars = data->getIvarList(cache);
754 if (ivars) {
755 for (pint_t i = 0; i < ivars->getCount(); i++) {
756 objc_ivar_t<P>& ivar = ivars->get(i);
757 //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
758 ivarVisitor.visitIvar(cache, header, cls, &ivar);
759 }
760 } else {
761 //fprintf(stderr, "no ivars\n");
762 }
763 }
764
765 void visitClass(ContentAccessor* cache, const macho_header<P>* header, objc_class_t<P> *cls)
766 {
767 walk(cache, header, cls);
768 }
769 };
770
771 // Call visitor.visitClass() on every class.
772 template <typename P, typename V>
773 class ClassWalker {
774 typedef typename P::uint_t pint_t;
775 V& _visitor;
776 public:
777
778 ClassWalker(V& visitor) : _visitor(visitor) { }
779
780 void walk(ContentAccessor* cache, const macho_header<P>* header)
781 {
782 PointerSection<P, objc_class_t<P>*> classList(cache, header, "__DATA", "__objc_classlist");
783
784 for (pint_t i = 0; i < classList.count(); i++) {
785 objc_class_t<P>* cls = classList.get(i);
786 //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
787 if (cls) _visitor.visitClass(cache, header, cls);
788 }
789 }
790 };
791
792 // Call visitor.visitProtocol() on every protocol.
793 template <typename P, typename V>
794 class ProtocolWalker {
795 typedef typename P::uint_t pint_t;
796 V& _protocolVisitor;
797 public:
798
799 ProtocolWalker(V& visitor) : _protocolVisitor(visitor) { }
800
801 void walk(ContentAccessor* cache, const macho_header<P>* header)
802 {
803 PointerSection<P, objc_protocol_t<P> *>
804 protocols(cache, header, "__DATA", "__objc_protolist");
805
806 for (pint_t i = 0; i < protocols.count(); i++) {
807 objc_protocol_t<P> *proto = protocols.get(i);
808 _protocolVisitor.visitProtocol(cache, header, proto);
809 }
810 }
811 };
812
813 // Call visitor.visitProtocolReference() on every protocol.
814 template <typename P, typename V>
815 class ProtocolReferenceWalker {
816 typedef typename P::uint_t pint_t;
817 V& _visitor;
818
819 void visitProtocolList(ContentAccessor* cache,
820 objc_protocol_list_t<P>* protolist)
821 {
822 if (!protolist) return;
823 for (pint_t i = 0; i < protolist->getCount(); i++) {
824 pint_t oldValue = protolist->getVMAddress(i);
825 pint_t newValue = _visitor.visitProtocolReference(cache, oldValue);
826 protolist->setVMAddress(i, newValue);
827 }
828 }
829
830 friend class ClassWalker<P, ProtocolReferenceWalker<P, V>>;
831
832 void visitClass(ContentAccessor* cache, const macho_header<P>*,
833 objc_class_t<P>* cls)
834 {
835 visitProtocolList(cache, cls->getProtocolList(cache));
836 visitProtocolList(cache, cls->getIsa(cache)->getProtocolList(cache));
837 }
838
839 public:
840
841 ProtocolReferenceWalker(V& visitor) : _visitor(visitor) { }
842 void walk(ContentAccessor* cache, const macho_header<P>* header)
843 {
844 // @protocol expressions
845 PointerSection<P, objc_protocol_t<P> *>
846 protorefs(cache, header, "__DATA", "__objc_protorefs");
847 for (pint_t i = 0; i < protorefs.count(); i++) {
848 pint_t oldValue = protorefs.getVMAddress(i);
849 pint_t newValue = _visitor.visitProtocolReference(cache, oldValue);
850 protorefs.setVMAddress(i, newValue);
851 }
852
853 // protocol lists in classes
854 ClassWalker<P, ProtocolReferenceWalker<P, V>> classes(*this);
855 classes.walk(cache, header);
856
857 // protocol lists from categories
858 PointerSection<P, objc_category_t<P> *>
859 cats(cache, header, "__DATA", "__objc_catlist");
860 for (pint_t i = 0; i < cats.count(); i++) {
861 objc_category_t<P> *cat = cats.get(i);
862 visitProtocolList(cache, cat->getProtocols(cache));
863 }
864
865 // protocol lists in protocols
866 // __objc_protolists itself is NOT updated
867 PointerSection<P, objc_protocol_t<P> *>
868 protocols(cache, header, "__DATA", "__objc_protolist");
869 for (pint_t i = 0; i < protocols.count(); i++) {
870 objc_protocol_t<P>* proto = protocols.get(i);
871 visitProtocolList(cache, proto->getProtocols(cache));
872 // not recursive: every old protocol object
873 // must be in some protolist section somewhere
874 }
875 }
876 };
877
878 // Call visitor.visitMethodList(mlist) on every
879 // class and category method list in a header.
880 // Call visitor.visitProtocolMethodList(mlist, typelist) on every
881 // protocol method list in a header.
882 template <typename P, typename V>
883 class MethodListWalker {
884
885 typedef typename P::uint_t pint_t;
886
887 V& mVisitor;
888
889 public:
890
891 MethodListWalker(V& visitor) : mVisitor(visitor) { }
892
893 void walk(ContentAccessor* cache, const macho_header<P>* header)
894 {
895 // Method lists in classes
896 PointerSection<P, objc_class_t<P> *>
897 classes(cache, header, "__DATA", "__objc_classlist");
898
899 for (pint_t i = 0; i < classes.count(); i++) {
900 objc_class_t<P> *cls = classes.get(i);
901 objc_method_list_t<P> *mlist;
902 if ((mlist = cls->getMethodList(cache))) {
903 mVisitor.visitMethodList(mlist);
904 }
905 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
906 mVisitor.visitMethodList(mlist);
907 }
908 }
909
910 // Method lists from categories
911 PointerSection<P, objc_category_t<P> *>
912 cats(cache, header, "__DATA", "__objc_catlist");
913 for (pint_t i = 0; i < cats.count(); i++) {
914 objc_category_t<P> *cat = cats.get(i);
915 objc_method_list_t<P> *mlist;
916 if ((mlist = cat->getInstanceMethods(cache))) {
917 mVisitor.visitMethodList(mlist);
918 }
919 if ((mlist = cat->getClassMethods(cache))) {
920 mVisitor.visitMethodList(mlist);
921 }
922 }
923
924 // Method description lists from protocols
925 PointerSection<P, objc_protocol_t<P> *>
926 protocols(cache, header, "__DATA", "__objc_protolist");
927 for (pint_t i = 0; i < protocols.count(); i++) {
928 objc_protocol_t<P> *proto = protocols.get(i);
929 objc_method_list_t<P> *mlist;
930 pint_t *typelist = proto->getExtendedMethodTypes(cache);
931
932 if ((mlist = proto->getInstanceMethods(cache))) {
933 mVisitor.visitProtocolMethodList(mlist, typelist);
934 if (typelist) typelist += mlist->getCount();
935 }
936 if ((mlist = proto->getClassMethods(cache))) {
937 mVisitor.visitProtocolMethodList(mlist, typelist);
938 if (typelist) typelist += mlist->getCount();
939 }
940 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
941 mVisitor.visitProtocolMethodList(mlist, typelist);
942 if (typelist) typelist += mlist->getCount();
943 }
944 if ((mlist = proto->getOptionalClassMethods(cache))) {
945 mVisitor.visitProtocolMethodList(mlist, typelist);
946 if (typelist) typelist += mlist->getCount();
947 }
948 }
949 }
950 };
951
952 // Update selector references. The visitor performs recording and uniquing.
953 template <typename P, typename V>
954 class SelectorOptimizer {
955
956 typedef typename P::uint_t pint_t;
957
958 V& mVisitor;
959
960 std::set<pint_t> selectorRefVMAddrs;
961
962 friend class MethodListWalker<P, SelectorOptimizer<P,V> >;
963 void visitMethodList(objc_method_list_t<P> *mlist)
964 {
965 // Gather selectors. Update method names.
966 for (uint32_t m = 0; m < mlist->getCount(); m++) {
967 pint_t oldValue = mlist->get(m).getName();
968 pint_t newValue = mVisitor.visit(oldValue);
969 mlist->get(m).setName(newValue);
970 }
971 // Do not setFixedUp: the methods are not yet sorted.
972 }
973
974 void visitProtocolMethodList(objc_method_list_t<P> *mlist, pint_t *types)
975 {
976 visitMethodList(mlist);
977 }
978
979 public:
980
981 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
982
983 void visitCoalescedStrings(const CacheBuilder::CacheCoalescedText& coalescedText) {
984 mVisitor.visitCoalescedStrings(coalescedText);
985 }
986
987 void optimize(ContentAccessor* cache, const macho_header<P>* header)
988 {
989 // method lists in classes, categories, and protocols
990 MethodListWalker<P, SelectorOptimizer<P,V> > mw(*this);
991 mw.walk(cache, header);
992
993 // @selector references
994 PointerSection<P, const char *>
995 selrefs(cache, header, "__DATA", "__objc_selrefs");
996 for (pint_t i = 0; i < selrefs.count(); i++) {
997 pint_t oldValue = selrefs.getVMAddress(i);
998 pint_t newValue = mVisitor.visit(oldValue);
999 selrefs.setVMAddress(i, newValue);
1000 selectorRefVMAddrs.insert(selrefs.getSectionVMAddress() + (i * sizeof(pint_t)));
1001 }
1002
1003 // message references
1004 ArraySection<P, objc_message_ref_t<P> >
1005 msgrefs(cache, header, "__DATA", "__objc_msgrefs");
1006 for (pint_t i = 0; i < msgrefs.count(); i++) {
1007 objc_message_ref_t<P>& msg = msgrefs.get(i);
1008 pint_t oldValue = msg.getName();
1009 pint_t newValue = mVisitor.visit(oldValue);
1010 msg.setName(newValue);
1011 }
1012 }
1013
1014 bool isSelectorRefAddress(pint_t vmAddr) const {
1015 return selectorRefVMAddrs.count(vmAddr);
1016 }
1017 };
1018
1019
1020 // Update selector references. The visitor performs recording and uniquing.
1021 template <typename P>
1022 class IvarOffsetOptimizer {
1023 uint32_t _slide;
1024 uint32_t _maxAlignment;
1025 uint32_t _optimized;
1026
1027 public:
1028
1029 IvarOffsetOptimizer() : _optimized(0) { }
1030
1031 size_t optimized() const { return _optimized; }
1032
1033 // dual purpose ivar visitor function
1034 // if slide!=0 then slides the ivar by that amount, otherwise computes _maxAlignment
1035 void visitIvar(ContentAccessor* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<P> *cls, objc_ivar_t<P> *ivar)
1036 {
1037 if (_slide == 0) {
1038 uint32_t alignment = ivar->getAlignment();
1039 if (alignment > _maxAlignment) _maxAlignment = alignment;
1040 } else {
1041 // skip anonymous bitfields
1042 if (ivar->hasOffset()) {
1043 uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
1044 ivar->setOffset(cache, oldOffset + _slide);
1045 _optimized++;
1046 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + _slide, cls->getName(cache), ivar->getName(cache));
1047 } else {
1048 //fprintf(stderr, "NULL offset\n");
1049 }
1050 }
1051 }
1052
1053 // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
1054 // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
1055 void visitClass(ContentAccessor* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<P> *cls)
1056 {
1057 objc_class_t<P> *super = cls->getSuperclass(cache);
1058 if (super) {
1059 // Recursively visit superclasses to ensure we have the correct superclass start
1060 // Note that we don't need the macho_header, so just pass NULL.
1061 visitClass(cache, nullptr, super);
1062
1063 objc_class_data_t<P> *data = cls->getData(cache);
1064 objc_class_data_t<P> *super_data = super->getData(cache);
1065 int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
1066 if (diff > 0) {
1067 IvarWalker<P, IvarOffsetOptimizer<P> > ivarVisitor(*this);
1068 _maxAlignment = 1;
1069 _slide = 0;
1070
1071 // This walk computes _maxAlignment
1072 ivarVisitor.walk(cache, nullptr, cls);
1073
1074 // Compute a slide value that preserves that alignment
1075 uint32_t alignMask = _maxAlignment - 1;
1076 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
1077
1078 // Slide all of this class's ivars en masse
1079 _slide = diff;
1080 if (_slide != 0) {
1081 //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), _slide, data->getInstanceStart(), super_data->getInstanceSize());
1082 ivarVisitor.walk(cache, nullptr, cls);
1083 data->setInstanceStart(data->getInstanceStart() + _slide);
1084 data->setInstanceSize(data->getInstanceSize() + _slide);
1085 }
1086 }
1087 }
1088 }
1089
1090 // Enumerates objc classes in the module and performs any ivar slides
1091 void optimize(ContentAccessor* cache, const macho_header<P>* header)
1092 {
1093 // The slide code cannot fix up GC layout strings so skip modules that support or require GC
1094 const macho_section<P> *imageInfoSection = header->getSection("__DATA", "__objc_imageinfo");
1095 if (imageInfoSection) {
1096 objc_image_info<P> *info = (objc_image_info<P> *)cache->contentForVMAddr(imageInfoSection->addr());
1097 if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) {
1098 ClassWalker<P, IvarOffsetOptimizer<P> > classVisitor(*this);
1099 classVisitor.walk(cache, header);
1100 } else {
1101 //fprintf(stderr, "GC support present - skipped module\n");
1102 }
1103 }
1104 }
1105 };
1106
1107
1108 // Detect classes that have missing weak-import superclasses.
1109 template <typename P>
1110 class WeakClassDetector {
1111 bool noMissing;
1112 const std::map<void*, std::string>* missingWeakImports = nullptr;
1113
1114 friend class ClassWalker<P, WeakClassDetector<P>>;
1115 void visitClass(ContentAccessor* cache, const macho_header<P>*,
1116 objc_class_t<P>* cls)
1117 {
1118 auto supercls = cls->getSuperclass(cache);
1119 if (supercls) {
1120 // okay: class with superclass
1121 // Note that the superclass itself might have a missing superclass.
1122 // That is fine for mere detection because we will visit the
1123 // superclass separately.
1124 } else if (cls->isRootClass(cache)) {
1125 // okay: root class is expected to have no superclass
1126 } else {
1127 // bad: cls's superclass is missing.
1128 // See if we can find the name from the missing weak import map
1129 auto it = missingWeakImports->find((void*)cls->getSuperClassAddress());
1130 const char* dylibName = "unknown dylib";
1131 if (it != missingWeakImports->end()) {
1132 dylibName = it->second.c_str();
1133 }
1134 cache->diagnostics().warning("Superclass of class '%s' is weak-import and missing. Expected in %s",
1135 cls->getName(cache), dylibName);
1136 noMissing = false;
1137 }
1138 }
1139
1140 public:
1141 bool noMissingWeakSuperclasses(ContentAccessor* cache,
1142 const std::map<void*, std::string>& missingWeakImportsMap,
1143 std::vector<const macho_header<P>*> dylibs)
1144 {
1145 noMissing = true;
1146 missingWeakImports = &missingWeakImportsMap;
1147 ClassWalker<P, WeakClassDetector<P>> classes(*this);
1148 for (auto mh : dylibs) {
1149 classes.walk(cache, mh);
1150 }
1151 return noMissing;
1152 }
1153 };
1154
1155
1156 // Sort methods in place by selector.
1157 template <typename P>
1158 class MethodListSorter {
1159
1160 typedef typename P::uint_t pint_t;
1161
1162 uint32_t _optimized;
1163
1164 friend class MethodListWalker<P, MethodListSorter<P> >;
1165 void visitMethodList(objc_method_list_t<P> *mlist)
1166 {
1167 typename objc_method_t<P>::SortBySELAddress sorter;
1168 std::stable_sort(mlist->begin(), mlist->end(), sorter);
1169 mlist->setFixedUp();
1170 _optimized++;
1171 }
1172
1173 void visitProtocolMethodList(objc_method_list_t<P> *mlist, pint_t *typelist)
1174 {
1175 typename objc_method_t<P>::SortBySELAddress sorter;
1176 // can't easily use std::stable_sort here
1177 for (uint32_t i = 0; i < mlist->getCount(); i++) {
1178 for (uint32_t j = i+1; j < mlist->getCount(); j++) {
1179 objc_method_t<P>& mi = mlist->get(i);
1180 objc_method_t<P>& mj = mlist->get(j);
1181 if (! sorter(mi, mj)) {
1182 std::swap(mi, mj);
1183 if (typelist) std::swap(typelist[i], typelist[j]);
1184 }
1185 }
1186 }
1187
1188 mlist->setFixedUp();
1189 _optimized++;
1190 }
1191
1192 public:
1193 MethodListSorter() : _optimized(0) { }
1194
1195 size_t optimized() const { return _optimized; }
1196
1197 void optimize(ContentAccessor* cache, const macho_header<P>* header)
1198 {
1199 MethodListWalker<P, MethodListSorter<P> > mw(*this);
1200 mw.walk(cache, header);
1201 }
1202 };
1203
1204
1205 template <typename P, typename InfoT>
1206 class HeaderInfoOptimizer {
1207 public:
1208
1209 typedef typename P::uint_t pint_t;
1210
1211 HeaderInfoOptimizer() : _hInfos(0), _count(0) { }
1212
1213 const char* init(uint32_t count, uint8_t*& buf, size_t& bufSize) {
1214 if (count == 0)
1215 return nullptr;
1216
1217 size_t requiredSize =
1218 2*sizeof(uint32_t) + count*sizeof(InfoT);
1219 if (bufSize < requiredSize) {
1220 return "libobjc's read/write section is too small (metadata not optimized)";
1221 }
1222
1223 uint32_t *buf32 = (uint32_t *)buf;
1224 P::E::set32(buf32[0], count);
1225 P::E::set32(buf32[1], sizeof(InfoT));
1226 _hInfos = (InfoT*)(buf32+2);
1227
1228 buf += requiredSize;
1229 bufSize -= requiredSize;
1230
1231 return nullptr;
1232 }
1233
1234 void update(ContentAccessor* cache, const macho_header<P>* mh, CacheBuilder::ASLR_Tracker& aslrTracker) {
1235 InfoT* hi = new(&_hInfos[_count++]) InfoT(cache, mh);
1236 (void)hi;
1237 }
1238
1239 InfoT* hinfoForHeader(ContentAccessor* cache, const macho_header<P>* mh) {
1240 // FIXME: could be binary search
1241 uint64_t mh_vmaddr = cache->vmAddrForContent((void*)mh);
1242 for (size_t i = 0; i < _count; i++) {
1243 InfoT* hi = &_hInfos[i];
1244 if (hi->header_vmaddr(cache) == mh_vmaddr) return hi;
1245 }
1246 return nullptr;
1247 }
1248 private:
1249 InfoT* _hInfos;
1250 size_t _count;
1251 };