]>
git.saurik.com Git - apple/xnu.git/blob - libkern/kernel_mach_header.c
0edc6b64de899500862f2153380f7ff28c3e2e1a
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
;
66 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
72 * Find the UUID load command in the Mach-O headers, and return
73 * the address of the UUID blob and size in "*size". If the
74 * Mach-O image is missing a UUID, NULL is returned.
77 getuuidfromheader(kernel_mach_header_t
*mhp
, unsigned long *size
)
79 struct uuid_command
*uuidp
;
82 uuidp
= (struct uuid_command
*)
83 ((uintptr_t)mhp
+ sizeof(kernel_mach_header_t
));
84 for(i
= 0; i
< mhp
->ncmds
; i
++){
85 if(uuidp
->cmd
== LC_UUID
) {
87 *size
= sizeof(uuidp
->uuid
);
89 return (void *)uuidp
->uuid
;
92 uuidp
= (struct uuid_command
*)((uintptr_t)uuidp
+ uuidp
->cmdsize
);
99 * This routine returns the a pointer to the data for the named section in the
100 * named segment if it exist in the mach header passed to it. Also it returns
101 * the size of the section data indirectly through the pointer size. Otherwise
102 * it returns zero for the pointer and the size.
104 * This routine can operate against any kernel mach header.
107 getsectdatafromheader(
108 kernel_mach_header_t
*mhp
,
110 const char *sectname
,
113 const kernel_section_t
*sp
;
116 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
117 if(sp
== (kernel_section_t
*)0){
122 result
= (void *)sp
->addr
;
127 * This routine returns the a pointer to the data for the named segment
128 * if it exist in the mach header passed to it. Also it returns
129 * the size of the segment data indirectly through the pointer size.
130 * Otherwise it returns zero for the pointer and the size.
133 getsegdatafromheader(
134 kernel_mach_header_t
*mhp
,
138 const kernel_segment_command_t
*sc
;
141 sc
= getsegbynamefromheader(mhp
, segname
);
142 if(sc
== (kernel_segment_command_t
*)0){
147 result
= (void *)sc
->vmaddr
;
152 * This routine returns the section structure for the named section in the
153 * named segment for the mach_header pointer passed to it if it exist.
154 * Otherwise it returns zero.
156 * This routine can operate against any kernel mach header.
159 getsectbynamefromheader(
160 kernel_mach_header_t
*mhp
,
162 const char *sectname
)
164 kernel_segment_command_t
*sgp
;
165 kernel_section_t
*sp
;
168 sgp
= (kernel_segment_command_t
*)
169 ((uintptr_t)mhp
+ sizeof(kernel_mach_header_t
));
170 for(i
= 0; i
< mhp
->ncmds
; i
++){
171 if(sgp
->cmd
== LC_SEGMENT_KERNEL
)
172 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
173 mhp
->filetype
== MH_OBJECT
){
174 sp
= (kernel_section_t
*)((uintptr_t)sgp
+
175 sizeof(kernel_segment_command_t
));
176 for(j
= 0; j
< sgp
->nsects
; j
++){
177 if(strncmp(sp
->sectname
, sectname
,
178 sizeof(sp
->sectname
)) == 0 &&
179 strncmp(sp
->segname
, segname
,
180 sizeof(sp
->segname
)) == 0)
182 sp
= (kernel_section_t
*)((uintptr_t)sp
+
183 sizeof(kernel_section_t
));
186 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
188 return((kernel_section_t
*)NULL
);
192 * This routine can operate against any kernel mach header.
194 kernel_segment_command_t
*
195 getsegbynamefromheader(
196 kernel_mach_header_t
*header
,
197 const char *seg_name
)
199 kernel_segment_command_t
*sgp
;
202 sgp
= (kernel_segment_command_t
*)
203 ((uintptr_t)header
+ sizeof(kernel_mach_header_t
));
204 for (i
= 0; i
< header
->ncmds
; i
++){
205 if ( sgp
->cmd
== LC_SEGMENT_KERNEL
206 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
208 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
210 return (kernel_segment_command_t
*)NULL
;
214 * Return the first segment_command in the header.
216 kernel_segment_command_t
*
219 return firstsegfromheader(&_mh_execute_header
);
222 kernel_segment_command_t
*
223 firstsegfromheader(kernel_mach_header_t
*header
)
226 kernel_segment_command_t
*sgp
= (kernel_segment_command_t
*)
227 ((uintptr_t)header
+ sizeof(*header
));
229 for (i
= 0; i
< header
->ncmds
; i
++){
230 if (sgp
->cmd
== LC_SEGMENT_KERNEL
)
232 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
234 return (kernel_segment_command_t
*)NULL
;
238 * This routine operates against any kernel mach segment_command structure
239 * pointer and the provided kernel header, to obtain the sequentially next
240 * segment_command structure in that header.
242 kernel_segment_command_t
*
244 kernel_mach_header_t
*header
,
245 kernel_segment_command_t
*seg
)
248 kernel_segment_command_t
*sgp
= (kernel_segment_command_t
*)
249 ((uintptr_t)header
+ sizeof(*header
));
251 /* Find the index of the passed-in segment */
252 for (i
= 0; sgp
!= seg
&& i
< header
->ncmds
; i
++) {
253 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
256 /* Increment to the next load command */
258 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
260 /* Return the next segment command, if any */
261 for (; i
< header
->ncmds
; i
++) {
262 if (sgp
->cmd
== LC_SEGMENT_KERNEL
) return sgp
;
264 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
267 return (kernel_segment_command_t
*)NULL
;
272 * Return the address of the named Mach-O segment from the currently
273 * executing kernel kernel, or NULL.
275 kernel_segment_command_t
*
276 getsegbyname(const char *seg_name
)
278 return(getsegbynamefromheader(&_mh_execute_header
, seg_name
));
282 * This routine returns the a pointer the section structure of the named
283 * section in the named segment if it exists in the currently executing
284 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
289 const char *sectname
)
291 return(getsectbynamefromheader(
292 (kernel_mach_header_t
*)&_mh_execute_header
, segname
, sectname
));
296 * This routine can operate against any kernel segment_command structure to
297 * return the first kernel section immediately following that structure. If
298 * there are no sections associated with the segment_command structure, it
302 firstsect(kernel_segment_command_t
*sgp
)
304 if (!sgp
|| sgp
->nsects
== 0)
305 return (kernel_section_t
*)NULL
;
307 return (kernel_section_t
*)(sgp
+1);
311 * This routine can operate against any kernel segment_command structure and
312 * kernel section to return the next consecutive kernel section immediately
313 * following the kernel section provided. If there are no sections following
314 * the provided section, it returns NULL.
317 nextsect(kernel_segment_command_t
*sgp
, kernel_section_t
*sp
)
319 kernel_section_t
*fsp
= firstsect(sgp
);
321 if (((uintptr_t)(sp
- fsp
) + 1) >= sgp
->nsects
)
322 return (kernel_section_t
*)NULL
;
329 * This routine returns the section command for the symbol table in the
330 * named segment for the mach_header pointer passed to it if it exist.
331 * Otherwise it returns zero.
333 static struct symtab_command
*
334 getsectcmdsymtabfromheader(
335 kernel_mach_header_t
*mhp
)
337 kernel_segment_command_t
*sgp
;
340 sgp
= (kernel_segment_command_t
*)
341 ((uintptr_t)mhp
+ sizeof(kernel_mach_header_t
));
342 for(i
= 0; i
< mhp
->ncmds
; i
++){
343 if(sgp
->cmd
== LC_SYMTAB
)
344 return((struct symtab_command
*)sgp
);
345 sgp
= (kernel_segment_command_t
*)((uintptr_t)sgp
+ sgp
->cmdsize
);
347 return((struct symtab_command
*)NULL
);
350 boolean_t
getsymtab(kernel_mach_header_t
*header
,
354 vm_size_t
*strtabsize
)
356 kernel_segment_command_t
*seglink_cmd
;
357 struct symtab_command
*symtab_cmd
;
361 if((header
->magic
!= MH_MAGIC
)
362 && (header
->magic
!= MH_MAGIC_64
)) { /* Check if this is a valid header format */
363 return (FALSE
); /* Bye y'all... */
366 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
367 if (seglink_cmd
== NULL
) {
372 symtab_cmd
= getsectcmdsymtabfromheader(header
);
373 if (symtab_cmd
== NULL
)
376 *nsyms
= symtab_cmd
->nsyms
;
377 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
379 *strtabsize
= symtab_cmd
->strsize
;
380 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
382 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
383 seglink_cmd
->fileoff
;
385 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
386 seglink_cmd
->fileoff
;