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 };