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@
25 #include "MachOLayout.hpp"
29 // iterate an entsize-based list
30 // typedef entsize_iterator< A, type_t<A>, type_list_t<A> > type_iterator;
31 template <typename A
, typename T
, typename Tlist
>
32 struct entsize_iterator
{
34 uint32_t index
; // keeping track of this saves a divide in operator-
37 typedef std::random_access_iterator_tag iterator_category
;
39 typedef ptrdiff_t difference_type
;
43 entsize_iterator() { }
45 entsize_iterator(const Tlist
& list
, uint32_t start
= 0)
46 : entsize(list
.getEntsize()), index(start
), current(&list
.get(start
))
49 const entsize_iterator
<A
,T
,Tlist
>& operator += (ptrdiff_t count
) {
50 current
= (T
*)((uint8_t *)current
+ count
*entsize
);
54 const entsize_iterator
<A
,T
,Tlist
>& operator -= (ptrdiff_t count
) {
55 current
= (T
*)((uint8_t *)current
- count
*entsize
);
59 const entsize_iterator
<A
,T
,Tlist
> operator + (ptrdiff_t count
) const {
60 return entsize_iterator(*this) += count
;
62 const entsize_iterator
<A
,T
,Tlist
> operator - (ptrdiff_t count
) const {
63 return entsize_iterator(*this) -= count
;
66 entsize_iterator
<A
,T
,Tlist
>& operator ++ () { *this += 1; return *this; }
67 entsize_iterator
<A
,T
,Tlist
>& operator -- () { *this -= 1; return *this; }
68 entsize_iterator
<A
,T
,Tlist
> operator ++ (int) {
69 entsize_iterator
<A
,T
,Tlist
> result(*this); *this += 1; return result
;
71 entsize_iterator
<A
,T
,Tlist
> operator -- (int) {
72 entsize_iterator
<A
,T
,Tlist
> result(*this); *this -= 1; return result
;
75 ptrdiff_t operator - (const entsize_iterator
<A
,T
,Tlist
>& rhs
) const {
76 return (ptrdiff_t)this->index
- (ptrdiff_t)rhs
.index
;
79 T
& operator * () { return *current
; }
80 T
& operator * () const { return *current
; }
81 T
& operator -> () { return *current
; }
82 const T
& operator -> () const { return *current
; }
84 operator T
& () const { return *current
; }
86 bool operator == (const entsize_iterator
<A
,T
,Tlist
>& rhs
) {
87 return this->current
== rhs
.current
;
89 bool operator != (const entsize_iterator
<A
,T
,Tlist
>& rhs
) {
90 return this->current
!= rhs
.current
;
93 bool operator < (const entsize_iterator
<A
,T
,Tlist
>& rhs
) {
94 return this->current
< rhs
.current
;
96 bool operator > (const entsize_iterator
<A
,T
,Tlist
>& rhs
) {
97 return this->current
> rhs
.current
;
101 static void overwrite(entsize_iterator
<A
,T
,Tlist
>& dst
, const Tlist
* srcList
)
103 entsize_iterator
<A
,T
,Tlist
> src
;
104 uint32_t ee
= srcList
->getEntsize();
105 for (src
= srcList
->begin(); src
!= srcList
->end(); ++src
) {
106 memcpy(&*dst
, &*src
, ee
);
112 template <typename A
>
113 class objc_header_info_t
{
115 typedef typename
A::P P
;
116 typedef typename
A::P::uint_t pint_t
;
118 pint_t next
; // objc_header_info *
119 pint_t mhdr
; // mach_header or mach_header_64
120 pint_t info
; // objc_image_info *
121 pint_t fname
; // const char *
124 bool allClassesRealized
;
127 objc_header_info_t(SharedCache
<A
>* cache
, const macho_header
<P
>* mh
)
133 allClassesRealized(0)
135 A::P::setP(mhdr
, cache
->VMAddressForMappedAddress(mh
));
136 const macho_section
<P
>* sect
= mh
->getSection("__DATA", "__objc_imageinfo");
137 if (sect
) A::P::setP(info
, sect
->addr());
139 // can't set fname because dyld sometimes edits it
142 void addPointers(std::vector
<void*>& pointersToAdd
) {
143 pointersToAdd
.push_back(&mhdr
);
144 if (info
) pointersToAdd
.push_back(&info
);
147 uint64_t header_vmaddr() const { return mhdr
; }
150 template <typename A
> class objc_method_list_t
; // forward reference
152 template <typename A
>
153 class objc_method_t
{
154 typename
A::P::uint_t name
; // SEL
155 typename
A::P::uint_t types
; // const char *
156 typename
A::P::uint_t imp
; // IMP
157 friend class objc_method_list_t
<A
>;
159 typename
A::P::uint_t
getName() const { return A::P::getP(name
); }
160 void setName(typename
A::P::uint_t newName
) { A::P::setP(name
, newName
); }
162 struct SortBySELAddress
:
163 public std::binary_function
<const objc_method_t
<A
>&,
164 const objc_method_t
<A
>&, bool>
166 bool operator() (const objc_method_t
<A
>& lhs
,
167 const objc_method_t
<A
>& rhs
)
169 return lhs
.getName() < rhs
.getName();
174 template <typename A
>
175 class objc_method_list_t
{
178 objc_method_t
<A
> first
;
180 void* operator new (size_t, void* buf
) { return buf
; }
184 typedef entsize_iterator
< A
, objc_method_t
<A
>, objc_method_list_t
<A
> > method_iterator
;
186 uint32_t getCount() const { return A::P::E::get32(count
); }
188 uint32_t getEntsize() const {return A::P::E::get32(entsize
)&~(uint32_t)3;}
190 objc_method_t
<A
>& get(uint32_t i
) const { return *(objc_method_t
<A
> *)((uint8_t *)&first
+ i
* getEntsize()); }
192 uint32_t byteSize() const {
193 return byteSizeForCount(getCount(), getEntsize());
196 static uint32_t byteSizeForCount(uint32_t c
, uint32_t e
= sizeof(objc_method_t
<A
>)) {
197 return sizeof(objc_method_list_t
<A
>) - sizeof(objc_method_t
<A
>) + c
*e
;
200 method_iterator
begin() { return method_iterator(*this, 0); }
201 method_iterator
end() { return method_iterator(*this, getCount()); }
202 const method_iterator
begin() const { return method_iterator(*this, 0); }
203 const method_iterator
end() const { return method_iterator(*this, getCount()); }
205 void setFixedUp() { A::P::E::set32(entsize
, getEntsize() | 3); }
207 void getPointers(std::set
<void*>& pointersToRemove
) {
208 for(method_iterator it
= begin(); it
!= end(); ++it
) {
209 objc_method_t
<A
>& entry
= *it
;
210 pointersToRemove
.insert(&(entry
.name
));
211 pointersToRemove
.insert(&(entry
.types
));
212 pointersToRemove
.insert(&(entry
.imp
));
216 static void addPointers(uint8_t* methodList
, std::vector
<void*>& pointersToAdd
) {
217 objc_method_list_t
<A
>* mlist
= (objc_method_list_t
<A
>*)methodList
;
218 for(method_iterator it
= mlist
->begin(); it
!= mlist
->end(); ++it
) {
219 objc_method_t
<A
>& entry
= *it
;
220 pointersToAdd
.push_back(&(entry
.name
));
221 pointersToAdd
.push_back(&(entry
.types
));
222 pointersToAdd
.push_back(&(entry
.imp
));
226 static objc_method_list_t
<A
>* newMethodList(size_t newCount
, uint32_t newEntsize
) {
227 void *buf
= ::calloc(byteSizeForCount(newCount
, newEntsize
), 1);
228 return new (buf
) objc_method_list_t
<A
>(newCount
, newEntsize
);
231 void operator delete(void * p
) {
235 objc_method_list_t(uint32_t newCount
,
236 uint32_t newEntsize
= sizeof(objc_method_t
<A
>))
237 : entsize(newEntsize
), count(newCount
)
241 // use newMethodList instead
242 void* operator new (size_t);
246 // Ivar offset variables are 64-bit on x86_64 and 32-bit everywhere else.
248 template <typename A
>
249 class objc_ivar_offset_t
{
250 typedef typename
A::P::uint_t pint_t
;
251 typename
A::P::uint_t ptr
; // uint32_t *
253 uint32_t& offset(SharedCache
<A
> *cache
) const { return *(uint32_t *)cache
->mappedAddressForVMAddress(A::P::getP(ptr
)); }
256 bool hasOffset() const { return A::P::getP(ptr
) != 0; }
257 pint_t
getOffset(SharedCache
<A
> *cache
) const { return A::P::E::get32(offset(cache
)); }
258 void setOffset(SharedCache
<A
> *cache
, pint_t newOffset
) { A::P::E::set32(offset(cache
), newOffset
); }
262 class objc_ivar_offset_t
<x86_64
> {
264 typedef typename
A::P::uint_t pint_t
;
265 typename
A::P::uint_t ptr
; // uint64_t *
267 uint64_t& offset(SharedCache
<A
> *cache
) const { return *(uint64_t *)cache
->mappedAddressForVMAddress(A::P::getP(ptr
)); }
270 bool hasOffset() const { return A::P::getP(ptr
) != 0; }
271 pint_t
getOffset(SharedCache
<A
> *cache
) const { return A::P::E::get64(offset(cache
)); }
272 void setOffset(SharedCache
<A
> *cache
, pint_t newOffset
) { A::P::E::set64(offset(cache
), newOffset
); }
275 template <typename A
>
277 typedef typename
A::P::uint_t pint_t
;
278 objc_ivar_offset_t
<A
> offset
; // uint32_t * (uint64_t * on x86_64)
279 typename
A::P::uint_t name
; // const char *
280 typename
A::P::uint_t type
; // const char *
285 const char * getName(SharedCache
<A
> *cache
) const { return (const char *)cache
->mappedAddressForVMAddress(A::P::getP(name
)); }
287 bool hasOffset() const { return offset
.hasOffset(); }
288 pint_t
getOffset(SharedCache
<A
> *cache
) const { return offset
.getOffset(cache
); }
289 void setOffset(SharedCache
<A
> *cache
, pint_t newOffset
) { offset
.setOffset(cache
, newOffset
); }
291 uint32_t getAlignment()
293 uint32_t a
= A::P::E::get32(alignment
);
294 return a
== (uint32_t)-1 ? sizeof(typename
A::P::uint_t
) : 1<<a
;
298 template <typename A
>
299 class objc_ivar_list_t
{
300 typedef typename
A::P::uint_t pint_t
;
303 objc_ivar_t
<A
> first
;
305 void* operator new (size_t, void* buf
) { return buf
; }
309 typedef entsize_iterator
< A
, objc_ivar_t
<A
>, objc_ivar_list_t
<A
> > ivar_iterator
;
311 uint32_t getCount() const { return A::P::E::get32(count
); }
313 uint32_t getEntsize() const { return A::P::E::get32(entsize
); }
315 objc_ivar_t
<A
>& get(pint_t i
) const { return *(objc_ivar_t
<A
> *)((uint8_t *)&first
+ i
* A::P::E::get32(entsize
)); }
317 uint32_t byteSize() const {
318 return byteSizeForCount(getCount(), getEntsize());
321 static uint32_t byteSizeForCount(uint32_t c
, uint32_t e
= sizeof(objc_ivar_t
<A
>)) {
322 return sizeof(objc_ivar_list_t
<A
>) - sizeof(objc_ivar_t
<A
>) + c
*e
;
325 ivar_iterator
begin() { return ivar_iterator(*this, 0); }
326 ivar_iterator
end() { return ivar_iterator(*this, getCount()); }
327 const ivar_iterator
begin() const { return ivar_iterator(*this, 0); }
328 const ivar_iterator
end() const { return ivar_iterator(*this, getCount()); }
330 static objc_ivar_list_t
<A
>* newIvarList(size_t newCount
, uint32_t newEntsize
) {
331 void *buf
= ::calloc(byteSizeForCount(newCount
, newEntsize
), 1);
332 return new (buf
) objc_ivar_list_t
<A
>(newCount
, newEntsize
);
335 void operator delete(void * p
) {
339 objc_ivar_list_t(uint32_t newCount
,
340 uint32_t newEntsize
= sizeof(objc_ivar_t
<A
>))
341 : entsize(newEntsize
), count(newCount
)
344 // use newIvarList instead
345 void* operator new (size_t);
349 template <typename A
> class objc_property_list_t
; // forward
351 template <typename A
>
352 class objc_property_t
{
353 typename
A::P::uint_t name
;
354 typename
A::P::uint_t attributes
;
355 friend class objc_property_list_t
<A
>;
358 const char * getName(SharedCache
<A
>* cache
) const { return (const char *)cache
->mappedAddressForVMAddress(A::P::getP(name
)); }
360 const char * getAttributes(SharedCache
<A
>* cache
) const { return (const char *)cache
->mappedAddressForVMAddress(A::P::getP(attributes
)); }
363 template <typename A
>
364 class objc_property_list_t
{
367 objc_property_t
<A
> first
;
369 void* operator new (size_t, void* buf
) { return buf
; }
373 typedef entsize_iterator
< A
, objc_property_t
<A
>, objc_property_list_t
<A
> > property_iterator
;
375 uint32_t getCount() const { return A::P::E::get32(count
); }
377 uint32_t getEntsize() const { return A::P::E::get32(entsize
); }
379 objc_property_t
<A
>& get(uint32_t i
) const { return *(objc_property_t
<A
> *)((uint8_t *)&first
+ i
* getEntsize()); }
381 uint32_t byteSize() const {
382 return byteSizeForCount(getCount(), getEntsize());
385 static uint32_t byteSizeForCount(uint32_t c
, uint32_t e
= sizeof(objc_property_t
<A
>)) {
386 return sizeof(objc_property_list_t
<A
>) - sizeof(objc_property_t
<A
>) + c
*e
;
389 property_iterator
begin() { return property_iterator(*this, 0); }
390 property_iterator
end() { return property_iterator(*this, getCount()); }
391 const property_iterator
begin() const { return property_iterator(*this, 0); }
392 const property_iterator
end() const { return property_iterator(*this, getCount()); }
394 void getPointers(std::set
<void*>& pointersToRemove
) {
395 for(property_iterator it
= begin(); it
!= end(); ++it
) {
396 objc_property_t
<A
>& entry
= *it
;
397 pointersToRemove
.insert(&(entry
.name
));
398 pointersToRemove
.insert(&(entry
.attributes
));
402 static void addPointers(uint8_t* propertyList
, std::vector
<void*>& pointersToAdd
) {
403 objc_property_list_t
<A
>* plist
= (objc_property_list_t
<A
>*)propertyList
;
404 for(property_iterator it
= plist
->begin(); it
!= plist
->end(); ++it
) {
405 objc_property_t
<A
>& entry
= *it
;
406 pointersToAdd
.push_back(&(entry
.name
));
407 pointersToAdd
.push_back(&(entry
.attributes
));
411 static objc_property_list_t
<A
>* newPropertyList(size_t newCount
, uint32_t newEntsize
) {
412 void *buf
= ::calloc(byteSizeForCount(newCount
, newEntsize
), 1);
413 return new (buf
) objc_property_list_t
<A
>(newCount
, newEntsize
);
416 void operator delete(void * p
) {
420 objc_property_list_t(uint32_t newCount
,
421 uint32_t newEntsize
= sizeof(objc_property_t
<A
>))
422 : entsize(newEntsize
), count(newCount
)
425 // use newPropertyList instead
426 void* operator new (size_t);
429 template <typename A
>
430 class objc_protocol_t
{
431 typename
A::P::uint_t isa
;
432 typename
A::P::uint_t name
;
433 typename
A::P::uint_t protocols
;
434 typename
A::P::uint_t instanceMethods
;
435 typename
A::P::uint_t classMethods
;
436 typename
A::P::uint_t optionalInstanceMethods
;
437 typename
A::P::uint_t optionalClassMethods
;
438 typename
A::P::uint_t instanceProperties
;
441 objc_method_list_t
<A
> *getInstanceMethods(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(instanceMethods
)); }
443 objc_method_list_t
<A
> *getClassMethods(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(classMethods
)); }
445 objc_method_list_t
<A
> *getOptionalInstanceMethods(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(optionalInstanceMethods
)); }
447 objc_method_list_t
<A
> *getOptionalClassMethods(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(optionalClassMethods
)); }
451 template <typename A
>
452 class objc_protocol_list_t
{
453 typedef typename
A::P::uint_t pint_t
;
457 void* operator new (size_t, void* buf
) { return buf
; }
461 pint_t
getCount() const { return A::P::getP(count
); }
463 objc_protocol_t
<A
>* get(SharedCache
<A
>* cache
, pint_t i
) {
464 return (objc_protocol_t
<A
>*)cache
->mappedAddressForVMAddress(A::P::getP(list
[i
]));
467 void overwrite(pint_t
& index
, const objc_protocol_list_t
<A
>* src
) {
468 pint_t srcCount
= src
->getCount();
469 memcpy(list
+index
, src
->list
, srcCount
* sizeof(pint_t
));
473 uint32_t byteSize() const {
474 return byteSizeForCount(getCount());
476 static uint32_t byteSizeForCount(pint_t c
) {
477 return sizeof(objc_protocol_list_t
<A
>) + c
*sizeof(pint_t
);
480 void getPointers(std::set
<void*>& pointersToRemove
) {
481 for(int i
=0 ; i
< count
; ++i
) {
482 pointersToRemove
.insert(&list
[i
]);
486 static void addPointers(uint8_t* protocolList
, std::vector
<void*>& pointersToAdd
) {
487 objc_protocol_list_t
<A
>* plist
= (objc_protocol_list_t
<A
>*)protocolList
;
488 for(int i
=0 ; i
< plist
->count
; ++i
) {
489 pointersToAdd
.push_back(&plist
->list
[i
]);
493 static objc_protocol_list_t
<A
>* newProtocolList(pint_t newCount
) {
494 void *buf
= ::calloc(byteSizeForCount(newCount
), 1);
495 return new (buf
) objc_protocol_list_t
<A
>(newCount
);
498 void operator delete(void * p
) {
502 objc_protocol_list_t(uint32_t newCount
) : count(newCount
) { }
504 // use newProtocolList instead
505 void* operator new (size_t);
509 template <typename A
>
510 class objc_class_data_t
{
512 uint32_t instanceStart
;
513 // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
514 // on 64-bit archs, but no padding on 32-bit archs.
515 // This union is a way to model that.
517 uint32_t instanceSize
;
518 typename
A::P::uint_t pad
;
520 typename
A::P::uint_t ivarLayout
;
521 typename
A::P::uint_t name
;
522 typename
A::P::uint_t baseMethods
;
523 typename
A::P::uint_t baseProtocols
;
524 typename
A::P::uint_t ivars
;
525 typename
A::P::uint_t weakIvarLayout
;
526 typename
A::P::uint_t baseProperties
;
529 bool isMetaClass() { return A::P::E::get32(flags
) & 1; }
531 uint32_t getInstanceStart() { return A::P::E::get32(instanceStart
); }
532 void setInstanceStart(uint32_t newStart
) { A::P::E::set32(instanceStart
, newStart
); }
534 uint32_t getInstanceSize() { return A::P::E::get32(instanceSize
.instanceSize
); }
535 void setInstanceSize(uint32_t newSiz
) { A::P::E::set32(instanceSize
.instanceSize
, newSiz
); }
537 objc_method_list_t
<A
> *getMethodList(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(baseMethods
)); }
539 objc_protocol_list_t
<A
> *getProtocolList(SharedCache
<A
>* cache
) const { return (objc_protocol_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(baseProtocols
)); }
541 objc_ivar_list_t
<A
> *getIvarList(SharedCache
<A
>* cache
) const { return (objc_ivar_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(ivars
)); }
543 objc_property_list_t
<A
> *getPropertyList(SharedCache
<A
>* cache
) const { return (objc_property_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(baseProperties
)); }
545 const char * getName(SharedCache
<A
>* cache
) const { return (const char *)cache
->mappedAddressForVMAddress(A::P::getP(name
)); }
547 void setMethodList(SharedCache
<A
>* cache
, objc_method_list_t
<A
>* mlist
) {
548 A::P::setP(baseMethods
, cache
->VMAddressForMappedAddress(mlist
));
551 void setProtocolList(SharedCache
<A
>* cache
, objc_protocol_list_t
<A
>* protolist
) {
552 A::P::setP(baseProtocols
, cache
->VMAddressForMappedAddress(protolist
));
555 void setPropertyList(SharedCache
<A
>* cache
, objc_property_list_t
<A
>* proplist
) {
556 A::P::setP(baseProperties
, cache
->VMAddressForMappedAddress(proplist
));
559 void addMethodListPointer(std::vector
<void*>& pointersToAdd
) {
560 pointersToAdd
.push_back(&this->baseMethods
);
563 void addPropertyListPointer(std::vector
<void*>& pointersToAdd
) {
564 pointersToAdd
.push_back(&this->baseProperties
);
567 void addProtocolListPointer(std::vector
<void*>& pointersToAdd
) {
568 pointersToAdd
.push_back(&this->baseProtocols
);
572 template <typename A
>
574 typename
A::P::uint_t isa
;
575 typename
A::P::uint_t superclass
;
576 typename
A::P::uint_t method_cache
;
577 typename
A::P::uint_t vtable
;
578 typename
A::P::uint_t data
;
581 bool isMetaClass(SharedCache
<A
>* cache
) const { return getData(cache
)->isMetaClass(); }
583 objc_class_t
<A
> *getIsa(SharedCache
<A
> *cache
) const { return (objc_class_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(isa
)); }
585 objc_class_t
<A
> *getSuperclass(SharedCache
<A
> *cache
) const { return (objc_class_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(superclass
)); }
587 objc_class_data_t
<A
> *getData(SharedCache
<A
>* cache
) const { return (objc_class_data_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(data
)); }
589 objc_method_list_t
<A
> *getMethodList(SharedCache
<A
>* cache
) const { return getData(cache
)->getMethodList(cache
); }
591 objc_protocol_list_t
<A
> *getProtocolList(SharedCache
<A
>* cache
) const { return getData(cache
)->getProtocolList(cache
); }
593 objc_property_list_t
<A
> *getPropertyList(SharedCache
<A
>* cache
) const { return getData(cache
)->getPropertyList(cache
); }
595 const char * getName(SharedCache
<A
>* cache
) const {
596 return getData(cache
)->getName(cache
);
599 void setMethodList(SharedCache
<A
>* cache
, objc_method_list_t
<A
>* mlist
) {
600 getData(cache
)->setMethodList(cache
, mlist
);
603 void setProtocolList(SharedCache
<A
>* cache
, objc_protocol_list_t
<A
>* protolist
) {
604 getData(cache
)->setProtocolList(cache
, protolist
);
607 void setPropertyList(SharedCache
<A
>* cache
, objc_property_list_t
<A
>* proplist
) {
608 getData(cache
)->setPropertyList(cache
, proplist
);
611 void addMethodListPointer(SharedCache
<A
>* cache
, std::vector
<void*>& pointersToAdd
) {
612 getData(cache
)->addMethodListPointer(pointersToAdd
);
615 void addPropertyListPointer(SharedCache
<A
>* cache
, std::vector
<void*>& pointersToAdd
) {
616 getData(cache
)->addPropertyListPointer(pointersToAdd
);
619 void addProtocolListPointer(SharedCache
<A
>* cache
, std::vector
<void*>& pointersToAdd
) {
620 getData(cache
)->addProtocolListPointer(pointersToAdd
);
627 template <typename A
>
628 class objc_category_t
{
629 typename
A::P::uint_t name
;
630 typename
A::P::uint_t cls
;
631 typename
A::P::uint_t instanceMethods
;
632 typename
A::P::uint_t classMethods
;
633 typename
A::P::uint_t protocols
;
634 typename
A::P::uint_t instanceProperties
;
638 const char * getName(SharedCache
<A
> *cache
) const { return (const char *)cache
->mappedAddressForVMAddress(A::P::getP(name
)); }
640 objc_class_t
<A
> *getClass(SharedCache
<A
> *cache
) const { return (objc_class_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(cls
)); }
642 objc_method_list_t
<A
> *getInstanceMethods(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(instanceMethods
)); }
644 objc_method_list_t
<A
> *getClassMethods(SharedCache
<A
>* cache
) const { return (objc_method_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(classMethods
)); }
646 objc_protocol_list_t
<A
> *getProtocols(SharedCache
<A
>* cache
) const { return (objc_protocol_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(protocols
)); }
648 objc_property_list_t
<A
> *getInstanceProperties(SharedCache
<A
>* cache
) const { return (objc_property_list_t
<A
> *)cache
->mappedAddressForVMAddress(A::P::getP(instanceProperties
)); }
650 void getPointers(std::set
<void*>& pointersToRemove
) {
651 pointersToRemove
.insert(&name
);
652 pointersToRemove
.insert(&cls
);
653 pointersToRemove
.insert(&instanceMethods
);
654 pointersToRemove
.insert(&classMethods
);
655 pointersToRemove
.insert(&protocols
);
656 pointersToRemove
.insert(&instanceProperties
);
662 template <typename A
>
663 class objc_message_ref_t
{
664 typename
A::P::uint_t imp
;
665 typename
A::P::uint_t sel
;
668 typename
A::P::uint_t
getName() const { return A::P::getP(sel
); }
670 void setName(typename
A::P::uint_t newName
) { A::P::setP(sel
, newName
); }
673 // Call visitor.visitIvar() on every ivar in a given class.
674 template <typename A
, typename V
>
676 typedef typename
A::P P
;
677 typedef typename
A::P::uint_t pint_t
;
681 IvarWalker(V
& visitor
) : ivarVisitor(visitor
) { }
683 void walk(SharedCache
<A
>* cache
, const macho_header
<P
>* header
, objc_class_t
<A
> *cls
)
685 objc_class_data_t
<A
> *data
= cls
->getData(cache
);
686 objc_ivar_list_t
<A
> *ivars
= data
->getIvarList(cache
);
688 for (pint_t i
= 0; i
< ivars
->getCount(); i
++) {
689 objc_ivar_t
<A
>& ivar
= ivars
->get(i
);
690 //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
691 ivarVisitor
.visitIvar(cache
, header
, cls
, &ivar
);
694 //fprintf(stderr, "no ivars\n");
698 void visitClass(SharedCache
<A
>* cache
, const macho_header
<P
>* header
, objc_class_t
<A
> *cls
)
700 walk(cache
, header
, cls
);
704 // Call visitor.visitClass() on every class.
705 template <typename A
, typename V
>
707 typedef typename
A::P P
;
708 typedef typename
A::P::uint_t pint_t
;
712 ClassWalker(V
& visitor
) : classVisitor(visitor
) { }
714 void walk(SharedCache
<A
>* cache
, const macho_header
<P
>* header
)
716 PointerSection
<A
, objc_class_t
<A
> *>
717 classes(cache
, header
, "__DATA", "__objc_classlist");
719 for (pint_t i
= 0; i
< classes
.count(); i
++) {
720 objc_class_t
<A
> *cls
= classes
.get(i
);
721 //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
722 classVisitor
.visitClass(cache
, header
, cls
);
728 // Call visitor.visitMethodList(mlist) on every method list in a header.
729 template <typename A
, typename V
>
730 class MethodListWalker
{
732 typedef typename
A::P P
;
733 typedef typename
A::P::uint_t pint_t
;
739 MethodListWalker(V
& visitor
) : mVisitor(visitor
) { }
741 void walk(SharedCache
<A
>* cache
, const macho_header
<P
>* header
, bool walkProtocols
)
743 // Method lists in classes
744 PointerSection
<A
, objc_class_t
<A
> *>
745 classes(cache
, header
, "__DATA", "__objc_classlist");
747 for (pint_t i
= 0; i
< classes
.count(); i
++) {
748 objc_class_t
<A
> *cls
= classes
.get(i
);
749 objc_method_list_t
<A
> *mlist
;
750 if ((mlist
= cls
->getMethodList(cache
))) {
751 mVisitor
.visitMethodList(mlist
);
753 if ((mlist
= cls
->getIsa(cache
)->getMethodList(cache
))) {
754 mVisitor
.visitMethodList(mlist
);
758 // Method lists from categories
759 PointerSection
<A
, objc_category_t
<A
> *>
760 cats(cache
, header
, "__DATA", "__objc_catlist");
761 for (pint_t i
= 0; i
< cats
.count(); i
++) {
762 objc_category_t
<A
> *cat
= cats
.get(i
);
763 objc_method_list_t
<A
> *mlist
;
764 if ((mlist
= cat
->getInstanceMethods(cache
))) {
765 mVisitor
.visitMethodList(mlist
);
767 if ((mlist
= cat
->getClassMethods(cache
))) {
768 mVisitor
.visitMethodList(mlist
);
772 // Method description lists from protocols
773 if ( walkProtocols
) {
774 PointerSection
<A
, objc_protocol_t
<A
> *>
775 protocols(cache
, header
, "__DATA", "__objc_protolist");
776 for (pint_t i
= 0; i
< protocols
.count(); i
++) {
777 objc_protocol_t
<A
> *proto
= protocols
.get(i
);
778 objc_method_list_t
<A
> *mlist
;
779 if ((mlist
= proto
->getInstanceMethods(cache
))) {
780 mVisitor
.visitMethodList(mlist
);
782 if ((mlist
= proto
->getClassMethods(cache
))) {
783 mVisitor
.visitMethodList(mlist
);
785 if ((mlist
= proto
->getOptionalInstanceMethods(cache
))) {
786 mVisitor
.visitMethodList(mlist
);
788 if ((mlist
= proto
->getOptionalClassMethods(cache
))) {
789 mVisitor
.visitMethodList(mlist
);
797 // Update selector references. The visitor performs recording and uniquing.
798 template <typename A
, typename V
>
799 class SelectorOptimizer
{
801 typedef typename
A::P P
;
802 typedef typename
A::P::uint_t pint_t
;
806 friend class MethodListWalker
< A
, SelectorOptimizer
<A
,V
> >;
807 void visitMethodList(objc_method_list_t
<A
> *mlist
)
809 // Gather selectors. Update method names.
810 for (pint_t m
= 0; m
< mlist
->getCount(); m
++) {
811 pint_t oldValue
= mlist
->get(m
).getName();
812 pint_t newValue
= mVisitor
.visit(oldValue
);
813 mlist
->get(m
).setName(newValue
);
815 // Do not setFixedUp: the methods are not yet sorted.
820 SelectorOptimizer(V
& visitor
) : mVisitor(visitor
) { }
822 void optimize(SharedCache
<A
>* cache
, const macho_header
<P
>* header
)
824 // method lists of all kinds
825 MethodListWalker
< A
, SelectorOptimizer
<A
,V
> > mw(*this);
826 mw
.walk(cache
, header
, true);
828 // @selector references
829 PointerSection
<A
, const char *>
830 selrefs(cache
, header
, "__DATA", "__objc_selrefs");
831 for (pint_t i
= 0; i
< selrefs
.count(); i
++) {
832 pint_t oldValue
= selrefs
.getUnmapped(i
);
833 pint_t newValue
= mVisitor
.visit(oldValue
);
834 selrefs
.set(i
, newValue
);
837 // message references
838 ArraySection
<A
, objc_message_ref_t
<A
> >
839 msgrefs(cache
, header
, "__DATA", "__objc_msgrefs");
840 for (pint_t i
= 0; i
< msgrefs
.count(); i
++) {
841 objc_message_ref_t
<A
>& msg
= msgrefs
.get(i
);
842 pint_t oldValue
= msg
.getName();
843 pint_t newValue
= mVisitor
.visit(oldValue
);
844 msg
.setName(newValue
);
850 // Update selector references. The visitor performs recording and uniquing.
851 template <typename A
>
852 class IvarOffsetOptimizer
{
853 typedef typename
A::P P
;
856 uint32_t maxAlignment
;
862 IvarOffsetOptimizer() : fOptimized(0) { }
864 size_t optimized() const { return fOptimized
; }
866 // dual purpose ivar visitor function
867 // if slide!=0 then slides the ivar by that amount, otherwise computes maxAlignment
868 void visitIvar(SharedCache
<A
>* cache
, const macho_header
<P
>* /*unused, may be NULL*/, objc_class_t
<A
> *cls
, objc_ivar_t
<A
> *ivar
)
871 uint32_t alignment
= ivar
->getAlignment();
872 if (alignment
> maxAlignment
) maxAlignment
= alignment
;
874 // skip anonymous bitfields
875 if (ivar
->hasOffset()) {
876 uint32_t oldOffset
= (uint32_t)ivar
->getOffset(cache
);
877 ivar
->setOffset(cache
, oldOffset
+ slide
);
879 //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + slide, cls->getName(cache), ivar->getName(cache));
881 //fprintf(stderr, "NULL offset\n");
886 // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
887 // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
888 void visitClass(SharedCache
<A
>* cache
, const macho_header
<P
>* /*unused, may be NULL*/, objc_class_t
<A
> *cls
)
890 objc_class_t
<A
> *super
= cls
->getSuperclass(cache
);
892 // Recursively visit superclasses to ensure we have the correct superclass start
893 // Note that we don't need the macho_header, so just pass NULL.
894 visitClass(cache
, NULL
, super
);
896 objc_class_data_t
<A
> *data
= cls
->getData(cache
);
897 objc_class_data_t
<A
> *super_data
= super
->getData(cache
);
898 int32_t diff
= super_data
->getInstanceSize() - data
->getInstanceStart();
900 IvarWalker
<A
, IvarOffsetOptimizer
<A
> > ivarVisitor(*this);
904 // This walk computes maxAlignment
905 ivarVisitor
.walk(cache
, NULL
, cls
);
907 // Compute a slide value that preserves that alignment
908 uint32_t alignMask
= maxAlignment
- 1;
909 if (diff
& alignMask
) diff
= (diff
+ alignMask
) & ~alignMask
;
911 // Slide all of this class's ivars en masse
914 //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), slide, data->getInstanceStart(), super_data->getInstanceSize());
915 ivarVisitor
.walk(cache
, NULL
, cls
);
916 data
->setInstanceStart(data
->getInstanceStart() + slide
);
917 data
->setInstanceSize(data
->getInstanceSize() + slide
);
923 // Enumerates objc classes in the module and performs any ivar slides
924 void optimize(SharedCache
<A
>* cache
, const macho_header
<P
>* header
)
926 // The slide code cannot fix up GC layout strings so skip modules that support ore require GC
927 const macho_section
<P
> *imageInfoSection
= header
->getSection("__DATA", "__objc_imageinfo");
928 if (imageInfoSection
) {
929 objc_image_info
<A
> *info
= (objc_image_info
<A
> *)cache
->mappedAddressForVMAddress(imageInfoSection
->addr());
930 if (!info
->supportsGCFlagSet() && !info
->requiresGCFlagSet()) {
931 ClassWalker
<A
, IvarOffsetOptimizer
<A
> > classVisitor(*this);
932 classVisitor
.walk(cache
, header
);
934 //fprintf(stderr, "GC support present - skipped module\n");
941 // Sort methods in place by selector.
942 template <typename A
>
943 class MethodListSorter
{
945 typedef typename
A::P P
;
946 typedef typename
A::P::uint_t pint_t
;
950 friend class MethodListWalker
<A
, MethodListSorter
<A
> >;
951 void visitMethodList(objc_method_list_t
<A
> *mlist
)
953 typename objc_method_t
<A
>::SortBySELAddress sorter
;
954 std::stable_sort(mlist
->begin(), mlist
->end(), sorter
);
960 MethodListSorter() : fOptimized(0) { }
962 size_t optimized() const { return fOptimized
; }
964 void optimize(SharedCache
<A
>* cache
, macho_header
<P
>* header
)
966 MethodListWalker
<A
, MethodListSorter
<A
> > mw(*this);
967 mw
.walk(cache
, header
, false /* don't sort protocol method lists*/);
972 template <typename A
>
973 class HeaderInfoOptimizer
{
975 typedef typename
A::P P
;
976 typedef typename
A::P::uint_t pint_t
;
978 objc_header_info_t
<A
>* fHinfos
;
982 HeaderInfoOptimizer() : fHinfos(0), fCount(0) { }
984 const char *init(size_t count
, uint8_t*& buf
, size_t& bufSize
)
986 if (count
== 0) return NULL
;
988 if (bufSize
< 2*sizeof(uint32_t) + count
*sizeof(objc_header_info_t
<A
>)) {
989 return "libobjc's read/write section is too small (metadata not optimized)";
992 uint32_t *buf32
= (uint32_t *)buf
;
993 A::P::E::set32(buf32
[0], count
);
994 A::P::E::set32(buf32
[1], sizeof(objc_header_info_t
<A
>));
995 fHinfos
= (objc_header_info_t
<A
>*)(buf32
+2);
997 size_t total
= sizeof(uint32_t) + count
*sizeof(objc_header_info_t
<A
>);
1004 void update(SharedCache
<A
>* cache
, const macho_header
<P
>* mh
, std::vector
<void*>& pointersInData
)
1006 objc_header_info_t
<A
>* hi
= new(&fHinfos
[fCount
++]) objc_header_info_t
<A
>(cache
, mh
);
1007 hi
->addPointers(pointersInData
);
1010 objc_header_info_t
<A
>* hinfoForHeader(SharedCache
<A
>* cache
, const macho_header
<P
>* mh
)
1012 // fixme could be binary search
1013 pint_t mh_vmaddr
= cache
->VMAddressForMappedAddress(mh
);
1014 for (size_t i
= 0; i
< fCount
; i
++) {
1015 objc_header_info_t
<A
>* hi
= &fHinfos
[i
];
1016 if (hi
->header_vmaddr() == mh_vmaddr
) return hi
;