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