1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
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 {
35 uint32_t index; // keeping track of this saves a divide in operator-
38 typedef std::random_access_iterator_tag iterator_category;
40 typedef ptrdiff_t difference_type;
44 entsize_iterator() { }
46 entsize_iterator(const Tlist& list, uint32_t start = 0)
47 : entsize(list.getEntsize()), index(start), current(&list.get(start))
50 const entsize_iterator<P,T,Tlist>& operator += (ptrdiff_t count) {
51 current = (T*)((uint8_t *)current + count*entsize);
55 const entsize_iterator<P,T,Tlist>& operator -= (ptrdiff_t count) {
56 current = (T*)((uint8_t *)current - count*entsize);
60 const entsize_iterator<P,T,Tlist> operator + (ptrdiff_t count) const {
61 return entsize_iterator(*this) += count;
63 const entsize_iterator<P,T,Tlist> operator - (ptrdiff_t count) const {
64 return entsize_iterator(*this) -= count;
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;
72 entsize_iterator<P,T,Tlist> operator -- (int) {
73 entsize_iterator<P,T,Tlist> result(*this); *this -= 1; return result;
76 ptrdiff_t operator - (const entsize_iterator<P,T,Tlist>& rhs) const {
77 return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
80 T& operator * () { return *current; }
81 T& operator * () const { return *current; }
82 T& operator -> () { return *current; }
83 const T& operator -> () const { return *current; }
85 operator T& () const { return *current; }
87 bool operator == (const entsize_iterator<P,T,Tlist>& rhs) {
88 return this->current == rhs.current;
90 bool operator != (const entsize_iterator<P,T,Tlist>& rhs) {
91 return this->current != rhs.current;
94 bool operator < (const entsize_iterator<P,T,Tlist>& rhs) {
95 return this->current < rhs.current;
97 bool operator > (const entsize_iterator<P,T,Tlist>& rhs) {
98 return this->current > rhs.current;
102 static void overwrite(entsize_iterator<P,T,Tlist>& dst, const Tlist* srcList)
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);
113 template <typename P>
114 class objc_header_info_rw_t {
116 typedef typename P::uint_t pint_t;
118 pint_t data; // loaded:1, allRealised:1, objc_header_info *:ptr
121 objc_header_info_rw_t(ContentAccessor* cache, const macho_header<P>* mh)
126 template <typename P>
127 class objc_header_info_ro_t {
129 typedef typename P::uint_t pint_t;
131 pint_t mhdr_offset; // offset to mach_header or mach_header_64
132 pint_t info_offset; // offset to objc_image_info *
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");
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);
147 P::setP(info_offset, - (uint64_t)cache->vmAddrForContent(&info_offset));
150 pint_t header_vmaddr(ContentAccessor* cache) const {
151 return (pint_t)(((uint64_t)cache->vmAddrForContent(&mhdr_offset)) + mhdr_offset);
156 template <typename P>
157 class objc_method_list_t; // forward reference
160 template <typename P>
161 class objc_method_t {
162 typedef typename P::uint_t pint_t;
164 pint_t types; // const char *
166 friend class objc_method_list_t<P>;
168 pint_t getName() const { return (pint_t)P::getP(name); }
169 void setName(pint_t newName) { P::setP(name, newName); }
171 struct SortBySELAddress :
172 public std::binary_function<const objc_method_t<P>&,
173 const objc_method_t<P>&, bool>
175 bool operator() (const objc_method_t<P>& lhs,
176 const objc_method_t<P>& rhs)
178 return lhs.getName() < rhs.getName();
183 template <typename P>
184 class objc_method_list_t {
187 objc_method_t<P> first;
189 void* operator new (size_t, void* buf) { return buf; }
193 typedef entsize_iterator<P, objc_method_t<P>, objc_method_list_t<P> > method_iterator;
195 uint32_t getCount() const { return P::E::get32(count); }
197 uint32_t getEntsize() const {return P::E::get32(entsize)&~(uint32_t)3;}
199 objc_method_t<P>& get(uint32_t i) const { return *(objc_method_t<P> *)((uint8_t *)&first + i * getEntsize()); }
201 uint32_t byteSize() const {
202 return byteSizeForCount(getCount(), getEntsize());
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;
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()); }
214 void setFixedUp() { P::E::set32(entsize, getEntsize() | 3); }
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));
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));
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);
240 void operator delete(void * p) {
244 objc_method_list_t(uint32_t newCount,
245 uint32_t newEntsize = sizeof(objc_method_t<P>))
246 : entsize(newEntsize), count(newCount)
250 // use newMethodList instead
251 void* operator new (size_t);
255 template <typename P>
257 typedef typename P::uint_t pint_t;
259 pint_t offset; // uint32_t* (uint64_t* on x86_64)
260 pint_t name; // const char*
261 pint_t type; // const char*
266 const char* getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
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); }
273 uint32_t getAlignment() {
274 uint32_t a = P::E::get32(alignment);
275 return (a == (uint32_t)-1) ? sizeof(pint_t) : 1<<a;
279 template <typename P>
280 class objc_ivar_list_t {
281 typedef typename P::uint_t pint_t;
284 objc_ivar_t<P> first;
286 void* operator new (size_t, void* buf) { return buf; }
290 typedef entsize_iterator<P, objc_ivar_t<P>, objc_ivar_list_t<P> > ivar_iterator;
292 uint32_t getCount() const { return P::E::get32(count); }
294 uint32_t getEntsize() const { return P::E::get32(entsize); }
296 objc_ivar_t<P>& get(pint_t i) const { return *(objc_ivar_t<P> *)((uint8_t *)&first + i * P::E::get32(entsize)); }
298 uint32_t byteSize() const {
299 return byteSizeForCount(getCount(), getEntsize());
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;
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()); }
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);
316 void operator delete(void * p) {
320 objc_ivar_list_t(uint32_t newCount,
321 uint32_t newEntsize = sizeof(objc_ivar_t<P>))
322 : entsize(newEntsize), count(newCount)
325 // use newIvarList instead
326 void* operator new (size_t);
330 template <typename P> class objc_property_list_t; // forward
332 template <typename P>
333 class objc_property_t {
334 typedef typename P::uint_t pint_t;
337 friend class objc_property_list_t<P>;
340 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
342 const char * getAttributes(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(attributes)); }
345 template <typename P>
346 class objc_property_list_t {
349 objc_property_t<P> first;
351 void* operator new (size_t, void* buf) { return buf; }
355 typedef entsize_iterator<P, objc_property_t<P>, objc_property_list_t<P> > property_iterator;
357 uint32_t getCount() const { return P::E::get32(count); }
359 uint32_t getEntsize() const { return P::E::get32(entsize); }
361 objc_property_t<P>& get(uint32_t i) const { return *(objc_property_t<P> *)((uint8_t *)&first + i * getEntsize()); }
363 uint32_t byteSize() const {
364 return byteSizeForCount(getCount(), getEntsize());
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;
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()); }
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));
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));
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);
398 void operator delete(void * p) {
402 objc_property_list_t(uint32_t newCount,
403 uint32_t newEntsize = sizeof(objc_property_t<P>))
404 : entsize(newEntsize), count(newCount)
407 // use newPropertyList instead
408 void* operator new (size_t);
412 template <typename A> class objc_protocol_list_t; // forward reference
414 template <typename P>
415 class objc_protocol_t {
416 typedef typename P::uint_t pint_t;
421 pint_t instanceMethods;
423 pint_t optionalInstanceMethods;
424 pint_t optionalClassMethods;
425 pint_t instanceProperties;
428 pint_t extendedMethodTypes;
429 pint_t demangledName;
430 pint_t classProperties;
433 pint_t getIsaVMAddr() const { return (pint_t)P::getP(isa); }
434 void setIsaVMAddr(pint_t newIsa) { P::setP(isa, newIsa); }
436 const char *getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
438 uint32_t getSize() const { return P::E::get32(size); }
439 void setSize(uint32_t newSize) { P::E::set32(size, newSize); }
441 uint32_t getFlags() const { return P::E::get32(flags); }
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));
449 objc_protocol_list_t<P> *getProtocols(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(protocols)); }
451 objc_method_list_t<P> *getInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(instanceMethods)); }
453 objc_method_list_t<P> *getClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(classMethods)); }
455 objc_method_list_t<P> *getOptionalInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(optionalInstanceMethods)); }
457 objc_method_list_t<P> *getOptionalClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(optionalClassMethods)); }
459 objc_property_list_t<P> *getInstanceProperties(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(instanceProperties)); }
461 pint_t *getExtendedMethodTypes(ContentAccessor* cache) const {
462 if (getSize() < offsetof(objc_protocol_t<P>, extendedMethodTypes) + sizeof(extendedMethodTypes)) {
465 return (pint_t *)cache->contentForVMAddr(P::getP(extendedMethodTypes));
468 const char *getDemangledName(ContentAccessor* cache) const {
469 if (sizeof(*this) < offsetof(objc_protocol_t<P>, demangledName) + sizeof(demangledName)) {
472 return (const char *)cache->contentForVMAddr(P::getP(demangledName));
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");
479 P::setP(demangledName, cache->vmAddrForContent((void*)newName));
482 void addPointers(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker)
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);
499 template <typename P>
500 class objc_protocol_list_t {
501 typedef typename P::uint_t pint_t;
505 void* operator new (size_t, void* buf) { return buf; }
509 pint_t getCount() const { return (pint_t)P::getP(count); }
511 pint_t getVMAddress(pint_t i) {
512 return (pint_t)P::getP(list[i]);
515 objc_protocol_t<P>* get(ContentAccessor* cache, pint_t i) {
516 return (objc_protocol_t<P>*)cache->contentForVMAddr(getVMAddress(i));
519 void setVMAddress(pint_t i, pint_t protoVMAddr) {
520 P::setP(list[i], protoVMAddr);
523 void set(ContentAccessor* cache, pint_t i, objc_protocol_t<P>* proto) {
524 setVMAddress(i, cache->vmAddrForContent(proto));
527 uint32_t byteSize() const {
528 return byteSizeForCount(getCount());
530 static uint32_t byteSizeForCount(pint_t c) {
531 return sizeof(objc_protocol_list_t<P>) + c*sizeof(pint_t);
534 void getPointers(std::set<void*>& pointersToRemove) {
535 for(int i=0 ; i < count; ++i) {
536 pointersToRemove.insert(&list[i]);
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]);
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);
552 void operator delete(void * p) {
556 objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
558 // use newProtocolList instead
559 void* operator new (size_t);
563 template <typename P>
564 class objc_class_data_t {
565 typedef typename P::uint_t pint_t;
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.
572 uint32_t instanceSize;
578 pint_t baseProtocols;
580 pint_t weakIvarLayout;
581 pint_t baseProperties;
584 bool isMetaClass() { return P::E::get32(flags) & (1 << 0); }
585 bool isRootClass() { return P::E::get32(flags) & (1 << 1); }
587 uint32_t getInstanceStart() { return P::E::get32(instanceStart); }
588 void setInstanceStart(uint32_t newStart) { P::E::set32(instanceStart, newStart); }
590 uint32_t getInstanceSize() { return P::E::get32(instanceSize.instanceSize); }
591 void setInstanceSize(uint32_t newSiz) { P::E::set32(instanceSize.instanceSize, newSiz); }
593 objc_method_list_t<P> *getMethodList(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(baseMethods)); }
595 objc_protocol_list_t<P> *getProtocolList(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(baseProtocols)); }
597 objc_ivar_list_t<P> *getIvarList(ContentAccessor* cache) const { return (objc_ivar_list_t<P> *)cache->contentForVMAddr(P::getP(ivars)); }
599 objc_property_list_t<P> *getPropertyList(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(baseProperties)); }
601 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
603 void setMethodList(ContentAccessor* cache, objc_method_list_t<P>* mlist) {
604 P::setP(baseMethods, cache->vmAddrForContent(mlist));
607 void setProtocolList(ContentAccessor* cache, objc_protocol_list_t<P>* protolist) {
608 P::setP(baseProtocols, cache->vmAddrForContent(protolist));
611 void setPropertyList(ContentAccessor* cache, objc_property_list_t<P>* proplist) {
612 P::setP(baseProperties, cache->vmAddrForContent(proplist));
615 void addMethodListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
616 aslrTracker.add(&this->baseMethods);
619 void addPropertyListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
620 aslrTracker.add(&this->baseProperties);
623 void addProtocolListPointer(CacheBuilder::ASLR_Tracker& aslrTracker) {
624 aslrTracker.add(&this->baseProtocols);
628 template <typename P>
630 typedef typename P::uint_t pint_t;
639 bool isMetaClass(ContentAccessor* cache) const { return getData(cache)->isMetaClass(); }
640 bool isRootClass(ContentAccessor* cache) const { return getData(cache)->isRootClass(); }
642 objc_class_t<P> *getIsa(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(isa)); }
644 objc_class_t<P> *getSuperclass(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(superclass)); }
646 const pint_t* getSuperClassAddress() const { return &superclass; }
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)); }
651 objc_method_list_t<P> *getMethodList(ContentAccessor* cache) const {
652 objc_class_data_t<P>* d = getData(cache);
653 return d->getMethodList(cache);
656 objc_protocol_list_t<P> *getProtocolList(ContentAccessor* cache) const { return getData(cache)->getProtocolList(cache); }
658 objc_property_list_t<P> *getPropertyList(ContentAccessor* cache) const { return getData(cache)->getPropertyList(cache); }
660 const char* getName(ContentAccessor* cache) const {
661 return getData(cache)->getName(cache);
664 void setMethodList(ContentAccessor* cache, objc_method_list_t<P>* mlist) {
665 getData(cache)->setMethodList(cache, mlist);
668 void setProtocolList(ContentAccessor* cache, objc_protocol_list_t<P>* protolist) {
669 getData(cache)->setProtocolList(cache, protolist);
672 void setPropertyList(ContentAccessor* cache, objc_property_list_t<P>* proplist) {
673 getData(cache)->setPropertyList(cache, proplist);
676 void addMethodListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
677 getData(cache)->addMethodListPointer(aslrTracker);
680 void addPropertyListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
681 getData(cache)->addPropertyListPointer(aslrTracker);
684 void addProtocolListPointer(ContentAccessor* cache, CacheBuilder::ASLR_Tracker& aslrTracker) {
685 getData(cache)->addProtocolListPointer(aslrTracker);
692 template <typename P>
693 class objc_category_t {
694 typedef typename P::uint_t pint_t;
698 pint_t instanceMethods;
701 pint_t instanceProperties;
705 const char * getName(ContentAccessor* cache) const { return (const char *)cache->contentForVMAddr(P::getP(name)); }
707 objc_class_t<P> *getClass(ContentAccessor* cache) const { return (objc_class_t<P> *)cache->contentForVMAddr(P::getP(cls)); }
709 objc_method_list_t<P> *getInstanceMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(instanceMethods)); }
711 objc_method_list_t<P> *getClassMethods(ContentAccessor* cache) const { return (objc_method_list_t<P> *)cache->contentForVMAddr(P::getP(classMethods)); }
713 objc_protocol_list_t<P> *getProtocols(ContentAccessor* cache) const { return (objc_protocol_list_t<P> *)cache->contentForVMAddr(P::getP(protocols)); }
715 objc_property_list_t<P> *getInstanceProperties(ContentAccessor* cache) const { return (objc_property_list_t<P> *)cache->contentForVMAddr(P::getP(instanceProperties)); }
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);
729 template <typename P>
730 class objc_message_ref_t {
731 typedef typename P::uint_t pint_t;
737 pint_t getName() const { return (pint_t)P::getP(sel); }
739 void setName(pint_t newName) { P::setP(sel, newName); }
742 // Call visitor.visitIvar() on every ivar in a given class.
743 template <typename P, typename V>
745 typedef typename P::uint_t pint_t;
749 IvarWalker(V& visitor) : ivarVisitor(visitor) { }
751 void walk(ContentAccessor* cache, const macho_header<P>* header, objc_class_t<P> *cls)
753 objc_class_data_t<P> *data = cls->getData(cache);
754 objc_ivar_list_t<P> *ivars = data->getIvarList(cache);
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);
762 //fprintf(stderr, "no ivars\n");
766 void visitClass(ContentAccessor* cache, const macho_header<P>* header, objc_class_t<P> *cls)
768 walk(cache, header, cls);
772 // Call visitor.visitClass() on every class.
773 template <typename P, typename V>
775 typedef typename P::uint_t pint_t;
779 ClassWalker(V& visitor) : _visitor(visitor) { }
781 void walk(ContentAccessor* cache, const macho_header<P>* header)
783 PointerSection<P, objc_class_t<P>*> classList(cache, header, "__DATA", "__objc_classlist");
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);
793 // Call visitor.visitProtocol() on every protocol.
794 template <typename P, typename V>
795 class ProtocolWalker {
796 typedef typename P::uint_t pint_t;
800 ProtocolWalker(V& visitor) : _protocolVisitor(visitor) { }
802 void walk(ContentAccessor* cache, const macho_header<P>* header)
804 PointerSection<P, objc_protocol_t<P> *>
805 protocols(cache, header, "__DATA", "__objc_protolist");
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);
814 // Call visitor.visitProtocolReference() on every protocol.
815 template <typename P, typename V>
816 class ProtocolReferenceWalker {
817 typedef typename P::uint_t pint_t;
820 void visitProtocolList(ContentAccessor* cache,
821 objc_protocol_list_t<P>* protolist)
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);
831 friend class ClassWalker<P, ProtocolReferenceWalker<P, V>>;
833 void visitClass(ContentAccessor* cache, const macho_header<P>*,
834 objc_class_t<P>* cls)
836 visitProtocolList(cache, cls->getProtocolList(cache));
837 visitProtocolList(cache, cls->getIsa(cache)->getProtocolList(cache));
842 ProtocolReferenceWalker(V& visitor) : _visitor(visitor) { }
843 void walk(ContentAccessor* cache, const macho_header<P>* header)
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);
854 // protocol lists in classes
855 ClassWalker<P, ProtocolReferenceWalker<P, V>> classes(*this);
856 classes.walk(cache, header);
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));
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
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 {
886 typedef typename P::uint_t pint_t;
892 MethodListWalker(V& visitor) : mVisitor(visitor) { }
894 void walk(ContentAccessor* cache, const macho_header<P>* header)
896 // Method lists in classes
897 PointerSection<P, objc_class_t<P> *>
898 classes(cache, header, "__DATA", "__objc_classlist");
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);
906 if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
907 mVisitor.visitMethodList(mlist);
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);
920 if ((mlist = cat->getClassMethods(cache))) {
921 mVisitor.visitMethodList(mlist);
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);
933 if ((mlist = proto->getInstanceMethods(cache))) {
934 mVisitor.visitProtocolMethodList(mlist, typelist);
935 if (typelist) typelist += mlist->getCount();
937 if ((mlist = proto->getClassMethods(cache))) {
938 mVisitor.visitProtocolMethodList(mlist, typelist);
939 if (typelist) typelist += mlist->getCount();
941 if ((mlist = proto->getOptionalInstanceMethods(cache))) {
942 mVisitor.visitProtocolMethodList(mlist, typelist);
943 if (typelist) typelist += mlist->getCount();
945 if ((mlist = proto->getOptionalClassMethods(cache))) {
946 mVisitor.visitProtocolMethodList(mlist, typelist);
947 if (typelist) typelist += mlist->getCount();
953 // Update selector references. The visitor performs recording and uniquing.
954 template <typename P, typename V>
955 class SelectorOptimizer {
957 typedef typename P::uint_t pint_t;
961 std::set<pint_t> selectorRefVMAddrs;
963 friend class MethodListWalker<P, SelectorOptimizer<P,V> >;
964 void visitMethodList(objc_method_list_t<P> *mlist)
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);
972 // Do not setFixedUp: the methods are not yet sorted.
975 void visitProtocolMethodList(objc_method_list_t<P> *mlist, pint_t *types)
977 visitMethodList(mlist);
982 SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
984 void visitCoalescedStrings(const CacheBuilder::CacheCoalescedText& coalescedText) {
985 mVisitor.visitCoalescedStrings(coalescedText);
988 void optimize(ContentAccessor* cache, const macho_header<P>* header)
990 // method lists in classes, categories, and protocols
991 MethodListWalker<P, SelectorOptimizer<P,V> > mw(*this);
992 mw.walk(cache, header);
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)));
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);
1015 bool isSelectorRefAddress(pint_t vmAddr) const {
1016 return selectorRefVMAddrs.count(vmAddr);
1021 // Update selector references. The visitor performs recording and uniquing.
1022 template <typename P>
1023 class IvarOffsetOptimizer {
1025 uint32_t _maxAlignment;
1026 uint32_t _optimized;
1030 IvarOffsetOptimizer() : _optimized(0) { }
1032 size_t optimized() const { return _optimized; }
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)
1039 uint32_t alignment = ivar->getAlignment();
1040 if (alignment > _maxAlignment) _maxAlignment = alignment;
1042 // skip anonymous bitfields
1043 if (ivar->hasOffset()) {
1044 uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
1045 ivar->setOffset(cache, oldOffset + _slide);
1047 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + _slide, cls->getName(cache), ivar->getName(cache));
1049 //fprintf(stderr, "NULL offset\n");
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)
1058 objc_class_t<P> *super = cls->getSuperclass(cache);
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);
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();
1068 IvarWalker<P, IvarOffsetOptimizer<P> > ivarVisitor(*this);
1072 // This walk computes _maxAlignment
1073 ivarVisitor.walk(cache, nullptr, cls);
1075 // Compute a slide value that preserves that alignment
1076 uint32_t alignMask = _maxAlignment - 1;
1077 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
1079 // Slide all of this class's ivars en masse
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);
1091 // Enumerates objc classes in the module and performs any ivar slides
1092 void optimize(ContentAccessor* cache, const macho_header<P>* header)
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);
1102 //fprintf(stderr, "GC support present - skipped module\n");
1109 // Detect classes that have missing weak-import superclasses.
1110 template <typename P>
1111 class WeakClassDetector {
1113 const std::map<void*, std::string>* missingWeakImports = nullptr;
1115 friend class ClassWalker<P, WeakClassDetector<P>>;
1116 void visitClass(ContentAccessor* cache, const macho_header<P>*,
1117 objc_class_t<P>* cls)
1119 auto supercls = cls->getSuperclass(cache);
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
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();
1135 cache->diagnostics().warning("Superclass of class '%s' is weak-import and missing. Expected in %s",
1136 cls->getName(cache), dylibName);
1142 bool noMissingWeakSuperclasses(ContentAccessor* cache,
1143 const std::map<void*, std::string>& missingWeakImportsMap,
1144 std::vector<const macho_header<P>*> dylibs)
1147 missingWeakImports = &missingWeakImportsMap;
1148 ClassWalker<P, WeakClassDetector<P>> classes(*this);
1149 for (auto mh : dylibs) {
1150 classes.walk(cache, mh);
1157 // Sort methods in place by selector.
1158 template <typename P>
1159 class MethodListSorter {
1161 typedef typename P::uint_t pint_t;
1163 uint32_t _optimized;
1165 friend class MethodListWalker<P, MethodListSorter<P> >;
1166 void visitMethodList(objc_method_list_t<P> *mlist)
1168 typename objc_method_t<P>::SortBySELAddress sorter;
1169 std::stable_sort(mlist->begin(), mlist->end(), sorter);
1170 mlist->setFixedUp();
1174 void visitProtocolMethodList(objc_method_list_t<P> *mlist, pint_t *typelist)
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)) {
1184 if (typelist) std::swap(typelist[i], typelist[j]);
1189 mlist->setFixedUp();
1194 MethodListSorter() : _optimized(0) { }
1196 size_t optimized() const { return _optimized; }
1198 void optimize(ContentAccessor* cache, const macho_header<P>* header)
1200 MethodListWalker<P, MethodListSorter<P> > mw(*this);
1201 mw.walk(cache, header);
1206 template <typename P, typename InfoT>
1207 class HeaderInfoOptimizer {
1210 typedef typename P::uint_t pint_t;
1212 HeaderInfoOptimizer() : _hInfos(0), _count(0) { }
1214 const char* init(uint32_t count, uint8_t*& buf, size_t& bufSize) {
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)";
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);
1229 buf += requiredSize;
1230 bufSize -= requiredSize;
1235 void update(ContentAccessor* cache, const macho_header<P>* mh, CacheBuilder::ASLR_Tracker& aslrTracker) {
1236 InfoT* hi = new(&_hInfos[_count++]) InfoT(cache, mh);
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;