]>
git.saurik.com Git - apple/xnu.git/blob - libkern/kernel_mach_header.c
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * File: libkern/kernel_mach_header.c
31 * Functions for accessing mach-o headers.
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.
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
47 * return the last address (first avail)
49 * This routine operates against the currently executing kernel only
54 kernel_segment_command_t
*sgp
;
55 vm_offset_t last_addr
= 0;
56 kernel_mach_header_t
*header
= &_mh_execute_header
;
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
;
67 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
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.
77 getcommandfromheader(kernel_mach_header_t
*mhp
, uint32_t cmd
)
79 struct load_command
*lcp
;
82 lcp
= (struct load_command
*) (mhp
+ 1);
83 for (i
= 0; i
< mhp
->ncmds
; i
++) {
84 if (lcp
->cmd
== cmd
) {
88 lcp
= (struct load_command
*)((uintptr_t)lcp
+ lcp
->cmdsize
);
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.
100 getuuidfromheader(kernel_mach_header_t
*mhp
, unsigned long *size
)
102 struct uuid_command
*cmd
= (struct uuid_command
*)
103 getcommandfromheader(mhp
, LC_UUID
);
107 *size
= sizeof(cmd
->uuid
);
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.
121 * This routine can operate against any kernel mach header.
124 getsectdatafromheader(
125 kernel_mach_header_t
*mhp
,
127 const char *sectname
,
130 const kernel_section_t
*sp
;
133 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
134 if (sp
== (kernel_section_t
*)0) {
139 result
= (void *)sp
->addr
;
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
148 * This routine can operate against any kernel mach header.
151 getsectoffsetfromheader(
152 kernel_mach_header_t
*mhp
,
154 const char *sectname
)
156 const kernel_section_t
*sp
;
158 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
159 if (sp
== (kernel_section_t
*)0) {
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.
173 getsegdatafromheader(
174 kernel_mach_header_t
*mhp
,
178 const kernel_segment_command_t
*sc
;
181 sc
= getsegbynamefromheader(mhp
, segname
);
182 if (sc
== (kernel_segment_command_t
*)0) {
187 result
= (void *)sc
->vmaddr
;
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.
196 * This routine can operate against any kernel mach header.
199 getsectbynamefromheader(
200 kernel_mach_header_t
*mhp
,
202 const char *sectname
)
204 kernel_segment_command_t
*sgp
;
205 kernel_section_t
*sp
;
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) {
223 sp
= (kernel_section_t
*)((uintptr_t)sp
+
224 sizeof(kernel_section_t
));
228 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
230 return (kernel_section_t
*)NULL
;
234 * This routine can operate against any kernel mach header.
236 kernel_segment_command_t
*
237 getsegbynamefromheader(
238 kernel_mach_header_t
*header
,
239 const char *seg_name
)
241 kernel_segment_command_t
*sgp
;
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
))) {
251 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
253 return (kernel_segment_command_t
*)NULL
;
257 * Return the first segment_command in the header.
259 kernel_segment_command_t
*
262 return firstsegfromheader(&_mh_execute_header
);
265 kernel_segment_command_t
*
266 firstsegfromheader(kernel_mach_header_t
*header
)
269 kernel_segment_command_t
*sgp
= (kernel_segment_command_t
*)
270 ((uintptr_t)header
+ sizeof(*header
));
272 for (i
= 0; i
< header
->ncmds
; i
++) {
273 if (sgp
->cmd
== LC_SEGMENT_KERNEL
) {
276 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
278 return (kernel_segment_command_t
*)NULL
;
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.
286 kernel_segment_command_t
*
288 kernel_mach_header_t
*header
,
289 kernel_segment_command_t
*seg
)
292 kernel_segment_command_t
*sgp
= (kernel_segment_command_t
*)
293 ((uintptr_t)header
+ sizeof(*header
));
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
);
300 /* Increment to the next load command */
302 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
304 /* Return the next segment command, if any */
305 for (; i
< header
->ncmds
; i
++) {
306 if (sgp
->cmd
== LC_SEGMENT_KERNEL
) {
310 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
313 return (kernel_segment_command_t
*)NULL
;
318 * Return the address of the named Mach-O segment from the currently
319 * executing kernel kernel, or NULL.
321 kernel_segment_command_t
*
322 getsegbyname(const char *seg_name
)
324 return getsegbynamefromheader(&_mh_execute_header
, seg_name
);
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.
335 const char *sectname
)
337 return getsectbynamefromheader(
338 (kernel_mach_header_t
*)&_mh_execute_header
, segname
, sectname
);
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
348 firstsect(kernel_segment_command_t
*sgp
)
350 if (!sgp
|| sgp
->nsects
== 0) {
351 return (kernel_section_t
*)NULL
;
354 return (kernel_section_t
*)(sgp
+ 1);
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.
364 nextsect(kernel_segment_command_t
*sgp
, kernel_section_t
*sp
)
366 kernel_section_t
*fsp
= firstsect(sgp
);
368 if (((uintptr_t)(sp
- fsp
) + 1) >= sgp
->nsects
) {
369 return (kernel_section_t
*)NULL
;