]> git.saurik.com Git - apple/dyld.git/blob - dyld3/shared-cache/ObjC2Abstraction.hpp
dyld-750.5.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 if (classProperties) aslrTracker.add(&classProperties);
495 }
496 };
497
498
499 template <typename P>
500 class objc_protocol_list_t {
501 typedef typename P::uint_t pint_t;
502 pint_t count;
503 pint_t list[0];
504
505 void* operator new (size_t, void* buf) { return buf; }
506
507 public:
508
509 pint_t getCount() const { return (pint_t)P::getP(count); }
510
511 pint_t getVMAddress(pint_t i) {
512 return (pint_t)P::getP(list[i]);
513 }
514
515 objc_protocol_t<P>* get(ContentAccessor* cache, pint_t i) {
516 return (objc_protocol_t<P>*)cache->contentForVMAddr(getVMAddress(i));
517 }
518
519 void setVMAddress(pint_t i, pint_t protoVMAddr) {
520 P::setP(list[i], protoVMAddr);
521 }
522
523 void set(ContentAccessor* cache, pint_t i, objc_protocol_t<P>* proto) {
524 setVMAddress(i, cache->vmAddrForContent(proto));
525 }
526
527 uint32_t byteSize() const {
528 return byteSizeForCount(getCount());
529 }
530 static uint32_t byteSizeForCount(pint_t c) {
531 return sizeof(objc_protocol_list_t<P>) + c*sizeof(pint_t);
532 }
533
534 void getPointers(std::set<void*>& pointersToRemove) {
535 for(int i=0 ; i < count; ++i) {
536 pointersToRemove.insert(&list[i]);
537 }
538 }
539
540 static void addPointers(uint8_t* protocolList, CacheBuilder::ASLR_Tracker& aslrTracker) {
541 objc_protocol_list_t<P>* plist = (objc_protocol_list_t<P>*)protocolList;
542 for(int i=0 ; i < plist->count; ++i) {
543 aslrTracker.add(&plist->list[i]);
544 }
545 }
546
547 static objc_protocol_list_t<P>* newProtocolList(pint_t newCount) {
548 void *buf = ::calloc(byteSizeForCount(newCount), 1);
549 return new (buf) objc_protocol_list_t<P>(newCount);
550 }
551
552 void operator delete(void * p) {
553 ::free(p);
554 }
555
556 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
557 private:
558 // use newProtocolList instead
559 void* operator new (size_t);
560 };
561
562
563 template <typename P>
564 class objc_class_data_t {
565 typedef typename P::uint_t pint_t;
566 uint32_t flags;
567 uint32_t instanceStart;
568 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
569 // on 64-bit archs, but no padding on 32-bit archs.
570 // This union is a way to model that.
571 union {
572 uint32_t instanceSize;
573 pint_t pad;
574 } instanceSize;
575 pint_t ivarLayout;
576 pint_t name;
577 pint_t baseMethods;
578 pint_t baseProtocols;
579 pint_t ivars;
580 pint_t weakIvarLayout;
581 pint_t baseProperties;
582
583 public:
584 bool isMetaClass() { return P::E::get32(flags) & (1 << 0); }
585 bool isRootClass() { return P::E::get32(flags) & (1 << 1); }
586
587 uint32_t getInstanceStart() { return P::E::get32(instanceStart); }
588 void setInstanceStart(uint32_t newStart) { P::E::set32(instanceStart, newStart); }
589
590 uint32_t getInstanceSize() { return P::E::get32(instanceSize.instanceSize); }
591 void setInstanceSize(uint32_t newSiz) { P::E::set32(instanceSize.instanceSize, newSiz); }
592
593 objc_method_list_t<P> *getMethodList(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(baseMethods)); }
594
595 objc_protocol_list_t<P> *getProtocolList(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(baseProtocols)); }
596
597 objc_ivar_list_t<P> *getIvarList(ContentAccessor* cache) const { return (objc_ivar_list_t<P> *)cache->contentForVMAddr(P::getP(ivars)); }
598
599 objc_property_list_t<P> *getPropertyList(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(baseProperties)); }
600
601 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
602
603 void setMethodList(ContentAccessor* cache, objc_method_list_t<P>* mlist) {
604 P::setP(baseMethods, cache->vmAddrForContent(mlist));
605 }
606
607 void setProtocolList(ContentAccessor* cache, objc_protocol_list_t<P>* protolist) {
608 P::setP(baseProtocols, cache->vmAddrForContent(protolist));
609 }
610
611 void setPropertyList(ContentAccessor* cache, objc_property_list_t<P>* proplist) {
612 P::setP(baseProperties, cache->vmAddrForContent(proplist));
613 }
614
615 void addMethodListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
616 aslrTracker.add(&this->baseMethods);
617 }
618
619 void addPropertyListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
620 aslrTracker.add(&this->baseProperties);
621 }
622
623 void addProtocolListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
624 aslrTracker.add(&this->baseProtocols);
625 }
626 };
627
628 template <typename P>
629 class objc_class_t {
630 typedef typename P::uint_t pint_t;
631
632 pint_t isa;
633 pint_t superclass;
634 pint_t method_cache;
635 pint_t vtable;
636 pint_t data;
637
638 public:
639 bool isMetaClass(ContentAccessor* cache) const { return getData(cache)->isMetaClass(); }
640 bool isRootClass(ContentAccessor* cache) const { return getData(cache)->isRootClass(); }
641
642 objc_class_t<P> *getIsa(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(isa)); }
643
644 objc_class_t<P> *getSuperclass(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(superclass)); }
645
646 const pint_t* getSuperClassAddress() const { return &superclass; }
647
648 // Low bit marks Swift classes.
649 objc_class_data_t<P> *getData(ContentAccessor* cache) const { return (objc_class_data_t<P> *)cache->contentForVMAddr(P::getP(data & ~0x3LL)); }
650
651 objc_method_list_t<P> *getMethodList(ContentAccessor* cache) const {
652 objc_class_data_t<P>* d = getData(cache);
653 return d->getMethodList(cache);
654 }
655
656 objc_protocol_list_t<P> *getProtocolList(ContentAccessor* cache) const { return getData(cache)->getProtocolList(cache); }
657
658 objc_property_list_t<P> *getPropertyList(ContentAccessor* cache) const { return getData(cache)->getPropertyList(cache); }
659
660 const char* getName(ContentAccessor* cache) const {
661 return getData(cache)->getName(cache);
662 }
663
664 void setMethodList(ContentAccessor* cache, objc_method_list_t<P>* mlist) {
665 getData(cache)->setMethodList(cache, mlist);
666 }
667
668 void setProtocolList(ContentAccessor* cache, objc_protocol_list_t<P>* protolist) {
669 getData(cache)->setProtocolList(cache, protolist);
670 }
671
672 void setPropertyList(ContentAccessor* cache, objc_property_list_t<P>* proplist) {
673 getData(cache)->setPropertyList(cache, proplist);
674 }
675
676 void addMethodListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
677 getData(cache)->addMethodListPointer(aslrTracker);
678 }
679
680 void addPropertyListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
681 getData(cache)->addPropertyListPointer(aslrTracker);
682 }
683
684 void addProtocolListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
685 getData(cache)->addProtocolListPointer(aslrTracker);
686 }
687
688 };
689
690
691
692 template <typename P>
693 class objc_category_t {
694 typedef typename P::uint_t pint_t;
695
696 pint_t name;
697 pint_t cls;
698 pint_t instanceMethods;
699 pint_t classMethods;
700 pint_t protocols;
701 pint_t instanceProperties;
702
703 public:
704
705 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
706
707 objc_class_t<P> *getClass(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(cls)); }
708
709 objc_method_list_t<P> *getInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(instanceMethods)); }
710
711 objc_method_list_t<P> *getClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(classMethods)); }
712
713 objc_protocol_list_t<P> *getProtocols(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(protocols)); }
714
715 objc_property_list_t<P> *getInstanceProperties(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(instanceProperties)); }
716
717 void getPointers(std::set<void*>& pointersToRemove) {
718 pointersToRemove.insert(&name);
719 pointersToRemove.insert(&cls);
720 pointersToRemove.insert(&instanceMethods);
721 pointersToRemove.insert(&classMethods);
722 pointersToRemove.insert(&protocols);
723 pointersToRemove.insert(&instanceProperties);
724 }
725
726
727 };
728
729 template <typename P>
730 class objc_message_ref_t {
731 typedef typename P::uint_t pint_t;
732
733 pint_t imp;
734 pint_t sel;
735
736 public:
737 pint_t getName() const { return (pint_t)P::getP(sel); }
738
739 void setName(pint_t newName) { P::setP(sel, newName); }
740 };
741
742 // Call visitor.visitIvar() on every ivar in a given class.
743 template <typename P, typename V>
744 class IvarWalker {
745 typedef typename P::uint_t pint_t;
746 V& ivarVisitor;
747 public:
748
749 IvarWalker(V& visitor) : ivarVisitor(visitor) { }
750
751 void walk(ContentAccessor* cache, const macho_header<P>* header, objc_class_t<P> *cls)
752 {
753 objc_class_data_t<P> *data = cls->getData(cache);
754 objc_ivar_list_t<P> *ivars = data->getIvarList(cache);
755 if (ivars) {
756 for (pint_t i = 0; i < ivars->getCount(); i++) {
757 objc_ivar_t<P>& ivar = ivars->get(i);
758 //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
759 ivarVisitor.visitIvar(cache, header, cls, &ivar);
760 }
761 } else {
762 //fprintf(stderr, "no ivars\n");
763 }
764 }
765
766 void visitClass(ContentAccessor* cache, const macho_header<P>* header, objc_class_t<P> *cls)
767 {
768 walk(cache, header, cls);
769 }
770 };
771
772 // Call visitor.visitClass() on every class.
773 template <typename P, typename V>
774 class ClassWalker {
775 typedef typename P::uint_t pint_t;
776 V& _visitor;
777 public:
778
779 ClassWalker(V& visitor) : _visitor(visitor) { }
780
781 void walk(ContentAccessor* cache, const macho_header<P>* header)
782 {
783 PointerSection<P, objc_class_t<P>*> classList(cache, header, "__DATA", "__objc_classlist");
784
785 for (pint_t i = 0; i < classList.count(); i++) {
786 objc_class_t<P>* cls = classList.get(i);
787 //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
788 if (cls) _visitor.visitClass(cache, header, cls);
789 }
790 }
791 };
792
793 // Call visitor.visitProtocol() on every protocol.
794 template <typename P, typename V>
795 class ProtocolWalker {
796 typedef typename P::uint_t pint_t;
797 V& _protocolVisitor;
798 public:
799
800 ProtocolWalker(V& visitor) : _protocolVisitor(visitor) { }
801
802 void walk(ContentAccessor* cache, const macho_header<P>* header)
803 {
804 PointerSection<P, objc_protocol_t<P> *>
805 protocols(cache, header, "__DATA", "__objc_protolist");
806
807 for (pint_t i = 0; i < protocols.count(); i++) {
808 objc_protocol_t<P> *proto = protocols.get(i);
809 _protocolVisitor.visitProtocol(cache, header, proto);
810 }
811 }
812 };
813
814 // Call visitor.visitProtocolReference() on every protocol.
815 template <typename P, typename V>
816 class ProtocolReferenceWalker {
817 typedef typename P::uint_t pint_t;
818 V& _visitor;
819
820 void visitProtocolList(ContentAccessor* cache,
821 objc_protocol_list_t<P>* protolist)
822 {
823 if (!protolist) return;
824 for (pint_t i = 0; i < protolist->getCount(); i++) {
825 pint_t oldValue = protolist->getVMAddress(i);
826 pint_t newValue = _visitor.visitProtocolReference(cache, oldValue);
827 protolist->setVMAddress(i, newValue);
828 }
829 }
830
831 friend class ClassWalker<P, ProtocolReferenceWalker<P, V>>;
832
833 void visitClass(ContentAccessor* cache, const macho_header<P>*,
834 objc_class_t<P>* cls)
835 {
836 visitProtocolList(cache, cls->getProtocolList(cache));
837 visitProtocolList(cache, cls->getIsa(cache)->getProtocolList(cache));
838 }
839
840 public:
841
842 ProtocolReferenceWalker(V& visitor) : _visitor(visitor) { }
843 void walk(ContentAccessor* cache, const macho_header<P>* header)
844 {
845 // @protocol expressions
846 PointerSection<P, objc_protocol_t<P> *>
847 protorefs(cache, header, "__DATA", "__objc_protorefs");
848 for (pint_t i = 0; i < protorefs.count(); i++) {
849 pint_t oldValue = protorefs.getVMAddress(i);
850 pint_t newValue = _visitor.visitProtocolReference(cache, oldValue);
851 protorefs.setVMAddress(i, newValue);
852 }
853
854 // protocol lists in classes
855 ClassWalker<P, ProtocolReferenceWalker<P, V>> classes(*this);
856 classes.walk(cache, header);
857
858 // protocol lists from categories
859 PointerSection<P, objc_category_t<P> *>
860 cats(cache, header, "__DATA", "__objc_catlist");
861 for (pint_t i = 0; i < cats.count(); i++) {
862 objc_category_t<P> *cat = cats.get(i);
863 visitProtocolList(cache, cat->getProtocols(cache));
864 }
865
866 // protocol lists in protocols
867 // __objc_protolists itself is NOT updated
868 PointerSection<P, objc_protocol_t<P> *>
869 protocols(cache, header, "__DATA", "__objc_protolist");
870 for (pint_t i = 0; i < protocols.count(); i++) {
871 objc_protocol_t<P>* proto = protocols.get(i);
872 visitProtocolList(cache, proto->getProtocols(cache));
873 // not recursive: every old protocol object
874 // must be in some protolist section somewhere
875 }
876 }
877 };
878
879 // Call visitor.visitMethodList(mlist) on every
880 // class and category method list in a header.
881 // Call visitor.visitProtocolMethodList(mlist, typelist) on every
882 // protocol method list in a header.
883 template <typename P, typename V>
884 class MethodListWalker {
885
886 typedef typename P::uint_t pint_t;
887
888 V& mVisitor;
889
890 public:
891
892 MethodListWalker(V& visitor) : mVisitor(visitor) { }
893
894 void walk(ContentAccessor* cache, const macho_header<P>* header)
895 {
896 // Method lists in classes
897 PointerSection<P, objc_class_t<P> *>
898 classes(cache, header, "__DATA", "__objc_classlist");
899
900 for (pint_t i = 0; i < classes.count(); i++) {
901 objc_class_t<P> *cls = classes.get(i);
902 objc_method_list_t<P> *mlist;
903 if ((mlist = cls->getMethodList(cache))) {
904 mVisitor.visitMethodList(mlist);
905 }
906 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
907 mVisitor.visitMethodList(mlist);
908 }
909 }
910
911 // Method lists from categories
912 PointerSection<P, objc_category_t<P> *>
913 cats(cache, header, "__DATA", "__objc_catlist");
914 for (pint_t i = 0; i < cats.count(); i++) {
915 objc_category_t<P> *cat = cats.get(i);
916 objc_method_list_t<P> *mlist;
917 if ((mlist = cat->getInstanceMethods(cache))) {
918 mVisitor.visitMethodList(mlist);
919 }
920 if ((mlist = cat->getClassMethods(cache))) {
921 mVisitor.visitMethodList(mlist);
922 }
923 }
924
925 // Method description lists from protocols
926 PointerSection<P, objc_protocol_t<P> *>
927 protocols(cache, header, "__DATA", "__objc_protolist");
928 for (pint_t i = 0; i < protocols.count(); i++) {
929 objc_protocol_t<P> *proto = protocols.get(i);
930 objc_method_list_t<P> *mlist;
931 pint_t *typelist = proto->getExtendedMethodTypes(cache);
932
933 if ((mlist = proto->getInstanceMethods(cache))) {
934 mVisitor.visitProtocolMethodList(mlist, typelist);
935 if (typelist) typelist += mlist->getCount();
936 }
937 if ((mlist = proto->getClassMethods(cache))) {
938 mVisitor.visitProtocolMethodList(mlist, typelist);
939 if (typelist) typelist += mlist->getCount();
940 }
941 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
942 mVisitor.visitProtocolMethodList(mlist, typelist);
943 if (typelist) typelist += mlist->getCount();
944 }
945 if ((mlist = proto->getOptionalClassMethods(cache))) {
946 mVisitor.visitProtocolMethodList(mlist, typelist);
947 if (typelist) typelist += mlist->getCount();
948 }
949 }
950 }
951 };
952
953 // Update selector references. The visitor performs recording and uniquing.
954 template <typename P, typename V>
955 class SelectorOptimizer {
956
957 typedef typename P::uint_t pint_t;
958
959 V& mVisitor;
960
961 std::set<pint_t> selectorRefVMAddrs;
962
963 friend class MethodListWalker<P, SelectorOptimizer<P,V> >;
964 void visitMethodList(objc_method_list_t<P> *mlist)
965 {
966 // Gather selectors. Update method names.
967 for (uint32_t m = 0; m < mlist->getCount(); m++) {
968 pint_t oldValue = mlist->get(m).getName();
969 pint_t newValue = mVisitor.visit(oldValue);
970 mlist->get(m).setName(newValue);
971 }
972 // Do not setFixedUp: the methods are not yet sorted.
973 }
974
975 void visitProtocolMethodList(objc_method_list_t<P> *mlist, pint_t *types)
976 {
977 visitMethodList(mlist);
978 }
979
980 public:
981
982 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
983
984 void visitCoalescedStrings(const CacheBuilder::CacheCoalescedText& coalescedText) {
985 mVisitor.visitCoalescedStrings(coalescedText);
986 }
987
988 void optimize(ContentAccessor* cache, const macho_header<P>* header)
989 {
990 // method lists in classes, categories, and protocols
991 MethodListWalker<P, SelectorOptimizer<P,V> > mw(*this);
992 mw.walk(cache, header);
993
994 // @selector references
995 PointerSection<P, const char *>
996 selrefs(cache, header, "__DATA", "__objc_selrefs");
997 for (pint_t i = 0; i < selrefs.count(); i++) {
998 pint_t oldValue = selrefs.getVMAddress(i);
999 pint_t newValue = mVisitor.visit(oldValue);
1000 selrefs.setVMAddress(i, newValue);
1001 selectorRefVMAddrs.insert(selrefs.getSectionVMAddress() + (i * sizeof(pint_t)));
1002 }
1003
1004 // message references
1005 ArraySection<P, objc_message_ref_t<P> >
1006 msgrefs(cache, header, "__DATA", "__objc_msgrefs");
1007 for (pint_t i = 0; i < msgrefs.count(); i++) {
1008 objc_message_ref_t<P>& msg = msgrefs.get(i);
1009 pint_t oldValue = msg.getName();
1010 pint_t newValue = mVisitor.visit(oldValue);
1011 msg.setName(newValue);
1012 }
1013 }
1014
1015 bool isSelectorRefAddress(pint_t vmAddr) const {
1016 return selectorRefVMAddrs.count(vmAddr);
1017 }
1018 };
1019
1020
1021 // Update selector references. The visitor performs recording and uniquing.
1022 template <typename P>
1023 class IvarOffsetOptimizer {
1024 uint32_t _slide;
1025 uint32_t _maxAlignment;
1026 uint32_t _optimized;
1027
1028 public:
1029
1030 IvarOffsetOptimizer() : _optimized(0) { }
1031
1032 size_t optimized() const { return _optimized; }
1033
1034 // dual purpose ivar visitor function
1035 // if slide!=0 then slides the ivar by that amount, otherwise computes _maxAlignment
1036 void visitIvar(ContentAccessor* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<P> *cls, objc_ivar_t<P> *ivar)
1037 {
1038 if (_slide == 0) {
1039 uint32_t alignment = ivar->getAlignment();
1040 if (alignment > _maxAlignment) _maxAlignment = alignment;
1041 } else {
1042 // skip anonymous bitfields
1043 if (ivar->hasOffset()) {
1044 uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
1045 ivar->setOffset(cache, oldOffset + _slide);
1046 _optimized++;
1047 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + _slide, cls->getName(cache), ivar->getName(cache));
1048 } else {
1049 //fprintf(stderr, "NULL offset\n");
1050 }
1051 }
1052 }
1053
1054 // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
1055 // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
1056 void visitClass(ContentAccessor* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<P> *cls)
1057 {
1058 objc_class_t<P> *super = cls->getSuperclass(cache);
1059 if (super) {
1060 // Recursively visit superclasses to ensure we have the correct superclass start
1061 // Note that we don't need the macho_header, so just pass NULL.
1062 visitClass(cache, nullptr, super);
1063
1064 objc_class_data_t<P> *data = cls->getData(cache);
1065 objc_class_data_t<P> *super_data = super->getData(cache);
1066 int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
1067 if (diff > 0) {
1068 IvarWalker<P, IvarOffsetOptimizer<P> > ivarVisitor(*this);
1069 _maxAlignment = 1;
1070 _slide = 0;
1071
1072 // This walk computes _maxAlignment
1073 ivarVisitor.walk(cache, nullptr, cls);
1074
1075 // Compute a slide value that preserves that alignment
1076 uint32_t alignMask = _maxAlignment - 1;
1077 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
1078
1079 // Slide all of this class's ivars en masse
1080 _slide = diff;
1081 if (_slide != 0) {
1082 //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), _slide, data->getInstanceStart(), super_data->getInstanceSize());
1083 ivarVisitor.walk(cache, nullptr, cls);
1084 data->setInstanceStart(data->getInstanceStart() + _slide);
1085 data->setInstanceSize(data->getInstanceSize() + _slide);
1086 }
1087 }
1088 }
1089 }
1090
1091 // Enumerates objc classes in the module and performs any ivar slides
1092 void optimize(ContentAccessor* cache, const macho_header<P>* header)
1093 {
1094 // The slide code cannot fix up GC layout strings so skip modules that support or require GC
1095 const macho_section<P> *imageInfoSection = header->getSection("__DATA", "__objc_imageinfo");
1096 if (imageInfoSection) {
1097 objc_image_info<P> *info = (objc_image_info<P> *)cache->contentForVMAddr(imageInfoSection->addr());
1098 if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) {
1099 ClassWalker<P, IvarOffsetOptimizer<P> > classVisitor(*this);
1100 classVisitor.walk(cache, header);
1101 } else {
1102 //fprintf(stderr, "GC support present - skipped module\n");
1103 }
1104 }
1105 }
1106 };
1107
1108
1109 // Detect classes that have missing weak-import superclasses.
1110 template <typename P>
1111 class WeakClassDetector {
1112 bool noMissing;
1113 const std::map<void*, std::string>* missingWeakImports = nullptr;
1114
1115 friend class ClassWalker<P, WeakClassDetector<P>>;
1116 void visitClass(ContentAccessor* cache, const macho_header<P>*,
1117 objc_class_t<P>* cls)
1118 {
1119 auto supercls = cls->getSuperclass(cache);
1120 if (supercls) {
1121 // okay: class with superclass
1122 // Note that the superclass itself might have a missing superclass.
1123 // That is fine for mere detection because we will visit the
1124 // superclass separately.
1125 } else if (cls->isRootClass(cache)) {
1126 // okay: root class is expected to have no superclass
1127 } else {
1128 // bad: cls's superclass is missing.
1129 // See if we can find the name from the missing weak import map
1130 auto it = missingWeakImports->find((void*)cls->getSuperClassAddress());
1131 const char* dylibName = "unknown dylib";
1132 if (it != missingWeakImports->end()) {
1133 dylibName = it->second.c_str();
1134 }
1135 cache->diagnostics().warning("Superclass of class '%s' is weak-import and missing. Expected in %s",
1136 cls->getName(cache), dylibName);
1137 noMissing = false;
1138 }
1139 }
1140
1141 public:
1142 bool noMissingWeakSuperclasses(ContentAccessor* cache,
1143 const std::map<void*, std::string>& missingWeakImportsMap,
1144 std::vector<const macho_header<P>*> dylibs)
1145 {
1146 noMissing = true;
1147 missingWeakImports = &missingWeakImportsMap;
1148 ClassWalker<P, WeakClassDetector<P>> classes(*this);
1149 for (auto mh : dylibs) {
1150 classes.walk(cache, mh);
1151 }
1152 return noMissing;
1153 }
1154 };
1155
1156
1157 // Sort methods in place by selector.
1158 template <typename P>
1159 class MethodListSorter {
1160
1161 typedef typename P::uint_t pint_t;
1162
1163 uint32_t _optimized;
1164
1165 friend class MethodListWalker<P, MethodListSorter<P> >;
1166 void visitMethodList(objc_method_list_t<P> *mlist)
1167 {
1168 typename objc_method_t<P>::SortBySELAddress sorter;
1169 std::stable_sort(mlist->begin(), mlist->end(), sorter);
1170 mlist->setFixedUp();
1171 _optimized++;
1172 }
1173
1174 void visitProtocolMethodList(objc_method_list_t<P> *mlist, pint_t *typelist)
1175 {
1176 typename objc_method_t<P>::SortBySELAddress sorter;
1177 // can't easily use std::stable_sort here
1178 for (uint32_t i = 0; i < mlist->getCount(); i++) {
1179 for (uint32_t j = i+1; j < mlist->getCount(); j++) {
1180 objc_method_t<P>& mi = mlist->get(i);
1181 objc_method_t<P>& mj = mlist->get(j);
1182 if (! sorter(mi, mj)) {
1183 std::swap(mi, mj);
1184 if (typelist) std::swap(typelist[i], typelist[j]);
1185 }
1186 }
1187 }
1188
1189 mlist->setFixedUp();
1190 _optimized++;
1191 }
1192
1193 public:
1194 MethodListSorter() : _optimized(0) { }
1195
1196 size_t optimized() const { return _optimized; }
1197
1198 void optimize(ContentAccessor* cache, const macho_header<P>* header)
1199 {
1200 MethodListWalker<P, MethodListSorter<P> > mw(*this);
1201 mw.walk(cache, header);
1202 }
1203 };
1204
1205
1206 template <typename P, typename InfoT>
1207 class HeaderInfoOptimizer {
1208 public:
1209
1210 typedef typename P::uint_t pint_t;
1211
1212 HeaderInfoOptimizer() : _hInfos(0), _count(0) { }
1213
1214 const char* init(uint32_t count, uint8_t*& buf, size_t& bufSize) {
1215 if (count == 0)
1216 return nullptr;
1217
1218 size_t requiredSize =
1219 2*sizeof(uint32_t) + count*sizeof(InfoT);
1220 if (bufSize < requiredSize) {
1221 return "libobjc's read/write section is too small (metadata not optimized)";
1222 }
1223
1224 uint32_t *buf32 = (uint32_t *)buf;
1225 P::E::set32(buf32[0], count);
1226 P::E::set32(buf32[1], sizeof(InfoT));
1227 _hInfos = (InfoT*)(buf32+2);
1228
1229 buf += requiredSize;
1230 bufSize -= requiredSize;
1231
1232 return nullptr;
1233 }
1234
1235 void update(ContentAccessor* cache, const macho_header<P>* mh, CacheBuilder::ASLR_Tracker& aslrTracker) {
1236 InfoT* hi = new(&_hInfos[_count++]) InfoT(cache, mh);
1237 (void)hi;
1238 }
1239
1240 InfoT* hinfoForHeader(ContentAccessor* cache, const macho_header<P>* mh) {
1241 // FIXME: could be binary search
1242 uint64_t mh_vmaddr = cache->vmAddrForContent((void*)mh);
1243 for (size_t i = 0; i < _count; i++) {
1244 InfoT* hi = &_hInfos[i];
1245 if (hi->header_vmaddr(cache) == mh_vmaddr) return hi;
1246 }
1247 return nullptr;
1248 }
1249 private:
1250 InfoT* _hInfos;
1251 size_t _count;
1252 };