dyld-750.6.tar.gz
[apple/dyld.git] / dyld3 / shared-cache / ObjC1Abstraction.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 #define OBJC_IMAGE_SUPPORTS_GC (1<<1)
26 #define OBJC_IMAGE_REQUIRES_GC (1<<2)
27
28 template <typename P>
29 struct objc_image_info {
30     uint32_t version;
31     uint32_t flags;
32
33     uint32_t getFlags()         INLINE { return P::E::get32(flags); }
34     
35     bool supportsGCFlagSet()    INLINE { return getFlags() & OBJC_IMAGE_SUPPORTS_GC; }
36     bool requiresGCFlagSet()    INLINE { return getFlags() & OBJC_IMAGE_REQUIRES_GC; }
37     
38     void setFlag(uint32_t bits) INLINE { uint32_t old = P::E::get32(flags); P::E::set32(flags, old | bits); }
39     void setOptimizedByDyld() INLINE { setFlag(1<<3); }
40 };
41
42 template <typename P>
43 struct objc_method {
44     uint32_t method_name;   // SEL
45     uint32_t method_types;  // char *
46     uint32_t method_imp;    // IMP     
47     
48     uint32_t getName() const INLINE { return P::E::get32(method_name); }
49     void setName(uint32_t newName) INLINE { P::E::set32(method_name, newName); }
50 };
51
52 template <typename P>
53 struct objc_method_list {
54     enum { OBJC_FIXED_UP = 1771 };
55     uint32_t obsolete;      // struct objc_method_list *
56     uint32_t method_count;  // int
57     struct objc_method<P> method_list[0];
58     
59     uint32_t getCount() const INLINE { return P::E::get32(method_count); }
60     void setFixedUp(bool fixed) INLINE { P::E::set32(obsolete, fixed ? OBJC_FIXED_UP : 0); }
61 };
62
63 template <typename P>
64 struct objc_class {
65     uint32_t isa;            // struct objc_class *
66     uint32_t super_class;    // struct objc_class *
67     uint32_t name;           // const char *
68     uint32_t version;        // long
69     uint32_t info;           // long
70     uint32_t instance_size;  // long
71     uint32_t ivars;          // struct objc_ivar_list *
72     uint32_t methodList;     // struct objc_method_list *
73     uint32_t method_cache;   // struct objc_cache *
74     uint32_t protocols;      // objc_protocol_list *
75     uint32_t ivar_layout;    // const char *
76     uint32_t ext;            // struct objc_class_ext *
77
78     struct objc_class<P> *getIsa(ContentAccessor* cache) const INLINE { return (struct objc_class<P> *)cache->contentForVMAddr(P::E::get32(isa)); }
79     struct objc_method_list<P> *getMethodList(ContentAccessor* cache) const INLINE { return (struct objc_method_list<P> *)cache->contentForVMAddr(P::E::get32(methodList)); }
80 };
81
82 template <typename P>
83 struct objc_category {
84     uint32_t category_name;        // char *
85     uint32_t class_name;           // char *
86     uint32_t instance_methods;     // struct objc_method_list *
87     uint32_t class_methods;        // struct objc_method_list *
88     uint32_t protocols;            // objc_protocol_list *
89     uint32_t size;                 // uint32_t
90     uint32_t instance_properties;  // struct objc_property_list *
91     
92     struct objc_method_list<P> *getInstanceMethods(ContentAccessor* cache) const INLINE { return (struct objc_method_list<P> *)cache->contentForVMAddr(P::E::get32(instance_methods)); }
93     struct objc_method_list<P> *getClassMethods(ContentAccessor* cache) const INLINE { return (struct objc_method_list<P> *)cache->contentForVMAddr(P::E::get32(class_methods)); }
94 };
95
96 template <typename P>
97 struct objc_symtab {
98     uint32_t sel_ref_cnt;  // unsigned long
99     uint32_t refs;         // SEL *
100     uint16_t cls_def_cnt;  // unsigned short
101     uint16_t cat_def_cnt;  // unsigned short
102     uint32_t defs[0];      // void *
103     
104     uint16_t getClassCount(void) const INLINE { return P::E::get16(cls_def_cnt); }
105     uint16_t getCategoryCount(void) const INLINE { return P::E::get16(cat_def_cnt); }
106     struct objc_class<P> *getClass(ContentAccessor* cache, int index) const INLINE { return (struct objc_class<P> *)cache->contentForVMAddr(P::E::get32(defs[index])); }
107     struct objc_category<P> *getCategory(ContentAccessor* cache, int index) const INLINE { return (struct objc_category<P> *)cache->contentForVMAddr(P::E::get32(defs[getClassCount() + index])); }
108 };
109
110 template <typename P>
111 struct objc_module {
112     uint32_t version;  // unsigned long
113     uint32_t size;     // unsigned long
114     uint32_t name;     // char*
115     uint32_t symtab;   // Symtab
116     
117     struct objc_symtab<P> *getSymtab(ContentAccessor* cache) const INLINE { return (struct objc_symtab<P> *)cache->contentForVMAddr(P::E::get32(symtab)); }
118 };
119
120 template <typename P>
121 struct objc_method_description {
122     uint32_t name;   // SEL
123     uint32_t types;  // char *
124     
125     uint32_t getName() const INLINE { return P::E::get32(name); }
126     void setName(uint32_t newName) INLINE { P::E::set32(name, newName); }
127 };
128
129 template <typename P>
130 struct objc_method_description_list {
131     uint32_t count;  // int
132     struct objc_method_description<P> list[0];
133     
134     uint32_t getCount() const INLINE { return P::E::get32(count); }
135 };
136
137 template <typename P>
138 struct objc_protocol {
139     uint32_t isa;               // danger! contains strange values!
140     uint32_t protocol_name;     // const char *
141     uint32_t protocol_list;     // struct objc_protocol_list
142     uint32_t instance_methods;  // struct objc_method_description_list *
143     uint32_t class_methods;     // struct objc_method_description_list *
144     
145     struct objc_method_description_list<P> *getInstanceMethodDescriptions(ContentAccessor* cache) const INLINE { return (struct objc_method_description_list<P> *)cache->contentForVMAddr(P::E::get32(instance_methods)); }
146     struct objc_method_description_list<P> *getClassMethodDescriptions(ContentAccessor* cache) const INLINE { return (struct objc_method_description_list<P> *)cache->contentForVMAddr(P::E::get32(class_methods)); }
147 };
148
149
150 template <typename P, typename V>
151 class LegacySelectorUpdater {
152     typedef typename P::uint_t pint_t;
153
154     static void visitMethodList(objc_method_list<P> *mlist, V& visitor)
155     {
156         for (uint32_t m = 0; m < mlist->getCount(); m++) {
157             pint_t oldValue = mlist->method_list[m].getName();
158             pint_t newValue = visitor.visit(oldValue);
159             mlist->method_list[m].setName((uint32_t)newValue);
160         }
161         mlist->setFixedUp(true);
162     }
163
164     static void visitMethodDescriptionList(objc_method_description_list<P> *mlist, V& visitor)
165     {
166         for (pint_t m = 0; m < mlist->getCount(); m++) {
167             pint_t oldValue = mlist->list[m].getName();
168             pint_t newValue = visitor.visit(oldValue);
169             mlist->list[m].setName((uint32_t)newValue);
170         }
171     }
172
173 public:
174
175     static void update(ContentAccessor* cache, const macho_header<P>* header, V& visitor)
176     {
177         ArraySection<P, objc_module<P> >
178             modules(cache, header, "__OBJC", "__module_info");
179         for (uint64_t m = 0; m < modules.count(); m++) {
180             objc_symtab<P> *symtab = modules.get(m).getSymtab(cache);
181             if (!symtab) continue;
182
183             // Method lists in classes
184             for (int c = 0; c < symtab->getClassCount(); c++) {
185                 objc_class<P> *cls = symtab->getClass(cache, c);
186                 objc_class<P> *isa = cls->getIsa(cache);
187                 objc_method_list<P> *mlist;
188                 if ((mlist = cls->getMethodList(cache))) {
189                     visitMethodList(mlist, visitor);
190                 }
191                 if ((mlist = isa->getMethodList(cache))) {
192                     visitMethodList(mlist, visitor);
193                 }
194             }
195             
196             // Method lists from categories
197             for (int c = 0; c < symtab->getCategoryCount(); c++) {
198                 objc_category<P> *cat = symtab->getCategory(cache, c);
199                 objc_method_list<P> *mlist;
200                 if ((mlist = cat->getInstanceMethods(cache))) {
201                     visitMethodList(mlist, visitor);
202                 }
203                 if ((mlist = cat->getClassMethods(cache))) {
204                     visitMethodList(mlist, visitor);
205                 }
206             }
207         }
208
209         // Method description lists from protocols        
210         ArraySection<P, objc_protocol<P>>
211             protocols(cache, header, "__OBJC", "__protocol");
212         for (uint64_t p = 0; p < protocols.count(); p++) {
213             objc_protocol<P>& protocol = protocols.get(p);
214             objc_method_description_list<P> *mlist;
215             if ((mlist = protocol.getInstanceMethodDescriptions(cache))) {
216                 visitMethodDescriptionList(mlist, visitor);
217             }
218             if ((mlist = protocol.getClassMethodDescriptions(cache))) {
219                 visitMethodDescriptionList(mlist, visitor);
220             }
221         }
222
223         // Message refs
224         PointerSection<P, const char *> selrefs(cache, header, "__OBJC", "__message_refs");
225         for (pint_t s = 0; s < selrefs.count(); s++) {
226             pint_t oldValue = selrefs.getVMAddress(s);
227             pint_t newValue = visitor.visit(oldValue);
228             selrefs.setVMAddress(s, newValue);
229         }
230     }
231 };