]> git.saurik.com Git - apple/xnu.git/blob - libkern/kernel_mach_header.c
xnu-2050.48.11.tar.gz
[apple/xnu.git] / libkern / kernel_mach_header.c
1 /*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * File: libkern/kernel_mach_header.c
30 *
31 * Functions for accessing mach-o headers.
32 *
33 * NOTE: This file supports only kernel mach headers at the present
34 * time; it's primary use is by kld, and all externally
35 * referenced routines at the present time operate against
36 * the kernel mach header _mh_execute_header, which is the
37 * header for the currently executing kernel.
38 *
39 */
40
41 #include <vm/vm_map.h>
42 #include <vm/vm_kern.h>
43 #include <libkern/kernel_mach_header.h>
44 #include <string.h> // from libsa
45
46 /*
47 * return the last address (first avail)
48 *
49 * This routine operates against the currently executing kernel only
50 */
51 vm_offset_t
52 getlastaddr(void)
53 {
54 kernel_segment_command_t *sgp;
55 vm_offset_t last_addr = 0;
56 kernel_mach_header_t *header = &_mh_execute_header;
57 unsigned long i;
58
59 sgp = (kernel_segment_command_t *)
60 ((uintptr_t)header + sizeof(kernel_mach_header_t));
61 for (i = 0; i < header->ncmds; i++){
62 if (sgp->cmd == LC_SEGMENT_KERNEL) {
63 if (sgp->vmaddr + sgp->vmsize > last_addr)
64 last_addr = sgp->vmaddr + sgp->vmsize;
65 }
66 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
67 }
68 return last_addr;
69 }
70
71 /*
72 * Find the specified load command in the Mach-O headers, and return
73 * the command. If there is no such load command, NULL is returned.
74 */
75 void *
76 getcommandfromheader(kernel_mach_header_t *mhp, uint32_t cmd) {
77 struct load_command *lcp;
78 unsigned long i;
79
80 lcp = (struct load_command *) (mhp + 1);
81 for(i = 0; i < mhp->ncmds; i++){
82 if(lcp->cmd == cmd) {
83 return (void *)lcp;
84 }
85
86 lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize);
87 }
88
89 return NULL;
90 }
91
92 /*
93 * Find the UUID load command in the Mach-O headers, and return
94 * the address of the UUID blob and size in "*size". If the
95 * Mach-O image is missing a UUID, NULL is returned.
96 */
97 void *
98 getuuidfromheader(kernel_mach_header_t *mhp, unsigned long *size)
99 {
100 struct uuid_command *cmd = (struct uuid_command *)
101 getcommandfromheader(mhp, LC_UUID);
102
103 if (cmd != NULL) {
104 if (size) {
105 *size = sizeof(cmd->uuid);
106 }
107 return cmd->uuid;
108 }
109
110 return NULL;
111 }
112
113 /*
114 * This routine returns the a pointer to the data for the named section in the
115 * named segment if it exist in the mach header passed to it. Also it returns
116 * the size of the section data indirectly through the pointer size. Otherwise
117 * it returns zero for the pointer and the size.
118 *
119 * This routine can operate against any kernel mach header.
120 */
121 void *
122 getsectdatafromheader(
123 kernel_mach_header_t *mhp,
124 const char *segname,
125 const char *sectname,
126 unsigned long *size)
127 {
128 const kernel_section_t *sp;
129 void *result;
130
131 sp = getsectbynamefromheader(mhp, segname, sectname);
132 if(sp == (kernel_section_t *)0){
133 *size = 0;
134 return((char *)0);
135 }
136 *size = sp->size;
137 result = (void *)sp->addr;
138 return result;
139 }
140
141 /*
142 * This routine returns the a pointer to the data for the named segment
143 * if it exist in the mach header passed to it. Also it returns
144 * the size of the segment data indirectly through the pointer size.
145 * Otherwise it returns zero for the pointer and the size.
146 */
147 void *
148 getsegdatafromheader(
149 kernel_mach_header_t *mhp,
150 const char *segname,
151 unsigned long *size)
152 {
153 const kernel_segment_command_t *sc;
154 void *result;
155
156 sc = getsegbynamefromheader(mhp, segname);
157 if(sc == (kernel_segment_command_t *)0){
158 *size = 0;
159 return((char *)0);
160 }
161 *size = sc->vmsize;
162 result = (void *)sc->vmaddr;
163 return result;
164 }
165
166 /*
167 * This routine returns the section structure for the named section in the
168 * named segment for the mach_header pointer passed to it if it exist.
169 * Otherwise it returns zero.
170 *
171 * This routine can operate against any kernel mach header.
172 */
173 kernel_section_t *
174 getsectbynamefromheader(
175 kernel_mach_header_t *mhp,
176 const char *segname,
177 const char *sectname)
178 {
179 kernel_segment_command_t *sgp;
180 kernel_section_t *sp;
181 unsigned long i, j;
182
183 sgp = (kernel_segment_command_t *)
184 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
185 for(i = 0; i < mhp->ncmds; i++){
186 if(sgp->cmd == LC_SEGMENT_KERNEL)
187 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
188 mhp->filetype == MH_OBJECT){
189 sp = (kernel_section_t *)((uintptr_t)sgp +
190 sizeof(kernel_segment_command_t));
191 for(j = 0; j < sgp->nsects; j++){
192 if(strncmp(sp->sectname, sectname,
193 sizeof(sp->sectname)) == 0 &&
194 strncmp(sp->segname, segname,
195 sizeof(sp->segname)) == 0)
196 return(sp);
197 sp = (kernel_section_t *)((uintptr_t)sp +
198 sizeof(kernel_section_t));
199 }
200 }
201 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
202 }
203 return((kernel_section_t *)NULL);
204 }
205
206 /*
207 * This routine can operate against any kernel mach header.
208 */
209 kernel_segment_command_t *
210 getsegbynamefromheader(
211 kernel_mach_header_t *header,
212 const char *seg_name)
213 {
214 kernel_segment_command_t *sgp;
215 unsigned long i;
216
217 sgp = (kernel_segment_command_t *)
218 ((uintptr_t)header + sizeof(kernel_mach_header_t));
219 for (i = 0; i < header->ncmds; i++){
220 if ( sgp->cmd == LC_SEGMENT_KERNEL
221 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
222 return sgp;
223 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
224 }
225 return (kernel_segment_command_t *)NULL;
226 }
227
228 /*
229 * Return the first segment_command in the header.
230 */
231 kernel_segment_command_t *
232 firstseg(void)
233 {
234 return firstsegfromheader(&_mh_execute_header);
235 }
236
237 kernel_segment_command_t *
238 firstsegfromheader(kernel_mach_header_t *header)
239 {
240 u_int i = 0;
241 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
242 ((uintptr_t)header + sizeof(*header));
243
244 for (i = 0; i < header->ncmds; i++){
245 if (sgp->cmd == LC_SEGMENT_KERNEL)
246 return sgp;
247 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
248 }
249 return (kernel_segment_command_t *)NULL;
250 }
251
252 /*
253 * This routine operates against any kernel mach segment_command structure
254 * pointer and the provided kernel header, to obtain the sequentially next
255 * segment_command structure in that header.
256 */
257 kernel_segment_command_t *
258 nextsegfromheader(
259 kernel_mach_header_t *header,
260 kernel_segment_command_t *seg)
261 {
262 u_int i = 0;
263 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
264 ((uintptr_t)header + sizeof(*header));
265
266 /* Find the index of the passed-in segment */
267 for (i = 0; sgp != seg && i < header->ncmds; i++) {
268 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
269 }
270
271 /* Increment to the next load command */
272 i++;
273 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
274
275 /* Return the next segment command, if any */
276 for (; i < header->ncmds; i++) {
277 if (sgp->cmd == LC_SEGMENT_KERNEL) return sgp;
278
279 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
280 }
281
282 return (kernel_segment_command_t *)NULL;
283 }
284
285
286 /*
287 * Return the address of the named Mach-O segment from the currently
288 * executing kernel kernel, or NULL.
289 */
290 kernel_segment_command_t *
291 getsegbyname(const char *seg_name)
292 {
293 return(getsegbynamefromheader(&_mh_execute_header, seg_name));
294 }
295
296 /*
297 * This routine returns the a pointer the section structure of the named
298 * section in the named segment if it exists in the currently executing
299 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
300 */
301 kernel_section_t *
302 getsectbyname(
303 const char *segname,
304 const char *sectname)
305 {
306 return(getsectbynamefromheader(
307 (kernel_mach_header_t *)&_mh_execute_header, segname, sectname));
308 }
309
310 /*
311 * This routine can operate against any kernel segment_command structure to
312 * return the first kernel section immediately following that structure. If
313 * there are no sections associated with the segment_command structure, it
314 * returns NULL.
315 */
316 kernel_section_t *
317 firstsect(kernel_segment_command_t *sgp)
318 {
319 if (!sgp || sgp->nsects == 0)
320 return (kernel_section_t *)NULL;
321
322 return (kernel_section_t *)(sgp+1);
323 }
324
325 /*
326 * This routine can operate against any kernel segment_command structure and
327 * kernel section to return the next consecutive kernel section immediately
328 * following the kernel section provided. If there are no sections following
329 * the provided section, it returns NULL.
330 */
331 kernel_section_t *
332 nextsect(kernel_segment_command_t *sgp, kernel_section_t *sp)
333 {
334 kernel_section_t *fsp = firstsect(sgp);
335
336 if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects)
337 return (kernel_section_t *)NULL;
338
339 return sp+1;
340 }