]> git.saurik.com Git - apple/xnu.git/blob - libkern/kernel_mach_header.c
xnu-7195.101.1.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 }
67 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
68 }
69 return last_addr;
70 }
71
72 /*
73 * Find the specified load command in the Mach-O headers, and return
74 * the command. If there is no such load command, NULL is returned.
75 */
76 void *
77 getcommandfromheader(kernel_mach_header_t *mhp, uint32_t cmd)
78 {
79 struct load_command *lcp;
80 unsigned long i;
81
82 lcp = (struct load_command *) (mhp + 1);
83 for (i = 0; i < mhp->ncmds; i++) {
84 if (lcp->cmd == cmd) {
85 return (void *)lcp;
86 }
87
88 lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize);
89 }
90
91 return NULL;
92 }
93
94 /*
95 * Find the UUID load command in the Mach-O headers, and return
96 * the address of the UUID blob and size in "*size". If the
97 * Mach-O image is missing a UUID, NULL is returned.
98 */
99 void *
100 getuuidfromheader(kernel_mach_header_t *mhp, unsigned long *size)
101 {
102 struct uuid_command *cmd = (struct uuid_command *)
103 getcommandfromheader(mhp, LC_UUID);
104
105 if (cmd != NULL) {
106 if (size) {
107 *size = sizeof(cmd->uuid);
108 }
109 return cmd->uuid;
110 }
111
112 return NULL;
113 }
114
115 /*
116 * This routine returns the a pointer to the data for the named section in the
117 * named segment if it exist in the mach header passed to it. Also it returns
118 * the size of the section data indirectly through the pointer size. Otherwise
119 * it returns zero for the pointer and the size.
120 *
121 * This routine can operate against any kernel mach header.
122 */
123 void *
124 getsectdatafromheader(
125 kernel_mach_header_t *mhp,
126 const char *segname,
127 const char *sectname,
128 unsigned long *size)
129 {
130 const kernel_section_t *sp;
131 void *result;
132
133 sp = getsectbynamefromheader(mhp, segname, sectname);
134 if (sp == (kernel_section_t *)0) {
135 *size = 0;
136 return (char *)0;
137 }
138 *size = sp->size;
139 result = (void *)sp->addr;
140 return result;
141 }
142
143 /*
144 * This routine returns the offset for the named section in the
145 * named segment if it exist in the mach header passed to it. Otherwise
146 * it returns zero.
147 *
148 * This routine can operate against any kernel mach header.
149 */
150 uint32_t
151 getsectoffsetfromheader(
152 kernel_mach_header_t *mhp,
153 const char *segname,
154 const char *sectname)
155 {
156 const kernel_section_t *sp;
157
158 sp = getsectbynamefromheader(mhp, segname, sectname);
159 if (sp == (kernel_section_t *)0) {
160 return 0;
161 }
162
163 return sp->offset;
164 }
165
166 /*
167 * This routine returns the a pointer to the data for the named segment
168 * if it exist in the mach header passed to it. Also it returns
169 * the size of the segment data indirectly through the pointer size.
170 * Otherwise it returns zero for the pointer and the size.
171 */
172 void *
173 getsegdatafromheader(
174 kernel_mach_header_t *mhp,
175 const char *segname,
176 unsigned long *size)
177 {
178 const kernel_segment_command_t *sc;
179 void *result;
180
181 sc = getsegbynamefromheader(mhp, segname);
182 if (sc == (kernel_segment_command_t *)0) {
183 *size = 0;
184 return (char *)0;
185 }
186 *size = sc->vmsize;
187 result = (void *)sc->vmaddr;
188 return result;
189 }
190
191 /*
192 * This routine returns the section structure for the named section in the
193 * named segment for the mach_header pointer passed to it if it exist.
194 * Otherwise it returns zero.
195 *
196 * This routine can operate against any kernel mach header.
197 */
198 kernel_section_t *
199 getsectbynamefromheader(
200 kernel_mach_header_t *mhp,
201 const char *segname,
202 const char *sectname)
203 {
204 kernel_segment_command_t *sgp;
205 kernel_section_t *sp;
206 unsigned long i, j;
207
208 sgp = (kernel_segment_command_t *)
209 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
210 for (i = 0; i < mhp->ncmds; i++) {
211 if (sgp->cmd == LC_SEGMENT_KERNEL) {
212 if (strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
213 mhp->filetype == MH_OBJECT) {
214 sp = (kernel_section_t *)((uintptr_t)sgp +
215 sizeof(kernel_segment_command_t));
216 for (j = 0; j < sgp->nsects; j++) {
217 if (strncmp(sp->sectname, sectname,
218 sizeof(sp->sectname)) == 0 &&
219 strncmp(sp->segname, segname,
220 sizeof(sp->segname)) == 0) {
221 return sp;
222 }
223 sp = (kernel_section_t *)((uintptr_t)sp +
224 sizeof(kernel_section_t));
225 }
226 }
227 }
228 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
229 }
230 return (kernel_section_t *)NULL;
231 }
232
233 /*
234 * This routine can operate against any kernel mach header.
235 */
236 kernel_segment_command_t *
237 getsegbynamefromheader(
238 kernel_mach_header_t *header,
239 const char *seg_name)
240 {
241 kernel_segment_command_t *sgp;
242 unsigned long i;
243
244 sgp = (kernel_segment_command_t *)
245 ((uintptr_t)header + sizeof(kernel_mach_header_t));
246 for (i = 0; i < header->ncmds; i++) {
247 if (sgp->cmd == LC_SEGMENT_KERNEL
248 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname))) {
249 return sgp;
250 }
251 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
252 }
253 return (kernel_segment_command_t *)NULL;
254 }
255
256 /*
257 * Return the first segment_command in the header.
258 */
259 kernel_segment_command_t *
260 firstseg(void)
261 {
262 return firstsegfromheader(&_mh_execute_header);
263 }
264
265 kernel_segment_command_t *
266 firstsegfromheader(kernel_mach_header_t *header)
267 {
268 u_int i = 0;
269 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
270 ((uintptr_t)header + sizeof(*header));
271
272 for (i = 0; i < header->ncmds; i++) {
273 if (sgp->cmd == LC_SEGMENT_KERNEL) {
274 return sgp;
275 }
276 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
277 }
278 return (kernel_segment_command_t *)NULL;
279 }
280
281 /*
282 * This routine operates against any kernel mach segment_command structure
283 * pointer and the provided kernel header, to obtain the sequentially next
284 * segment_command structure in that header.
285 */
286 kernel_segment_command_t *
287 nextsegfromheader(
288 kernel_mach_header_t *header,
289 kernel_segment_command_t *seg)
290 {
291 u_int i = 0;
292 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
293 ((uintptr_t)header + sizeof(*header));
294
295 /* Find the index of the passed-in segment */
296 for (i = 0; sgp != seg && i < header->ncmds; i++) {
297 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
298 }
299
300 /* Increment to the next load command */
301 i++;
302 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
303
304 /* Return the next segment command, if any */
305 for (; i < header->ncmds; i++) {
306 if (sgp->cmd == LC_SEGMENT_KERNEL) {
307 return sgp;
308 }
309
310 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
311 }
312
313 return (kernel_segment_command_t *)NULL;
314 }
315
316
317 /*
318 * Return the address of the named Mach-O segment from the currently
319 * executing kernel kernel, or NULL.
320 */
321 kernel_segment_command_t *
322 getsegbyname(const char *seg_name)
323 {
324 return getsegbynamefromheader(&_mh_execute_header, seg_name);
325 }
326
327 /*
328 * This routine returns the a pointer the section structure of the named
329 * section in the named segment if it exists in the currently executing
330 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
331 */
332 kernel_section_t *
333 getsectbyname(
334 const char *segname,
335 const char *sectname)
336 {
337 return getsectbynamefromheader(
338 (kernel_mach_header_t *)&_mh_execute_header, segname, sectname);
339 }
340
341 /*
342 * This routine can operate against any kernel segment_command structure to
343 * return the first kernel section immediately following that structure. If
344 * there are no sections associated with the segment_command structure, it
345 * returns NULL.
346 */
347 kernel_section_t *
348 firstsect(kernel_segment_command_t *sgp)
349 {
350 if (!sgp || sgp->nsects == 0) {
351 return (kernel_section_t *)NULL;
352 }
353
354 return (kernel_section_t *)(sgp + 1);
355 }
356
357 /*
358 * This routine can operate against any kernel segment_command structure and
359 * kernel section to return the next consecutive kernel section immediately
360 * following the kernel section provided. If there are no sections following
361 * the provided section, it returns NULL.
362 */
363 kernel_section_t *
364 nextsect(kernel_segment_command_t *sgp, kernel_section_t *sp)
365 {
366 kernel_section_t *fsp = firstsect(sgp);
367
368 if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects) {
369 return (kernel_section_t *)NULL;
370 }
371
372 return sp + 1;
373 }