2 * Copyright (c) 2000-2006 Apple Computer, 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: kern/mach_header.c
31 * Functions for accessing mach-o headers.
33 * NOTE: This file supports only 32 bit 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 32 bit mach header _mh_execute_header, which is the
37 * header for the currently executing kernel. Adding support
38 * for 64 bit kernels is possible, but is not necessary at the
42 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
43 * Added getsegdatafromheader();
45 * 29-Jan-92 Mike DeMoney (mike@next.com)
46 * Made into machine independent form from machdep/m68k/mach_header.c.
47 * Ifdef'ed out most of this since I couldn't find any references.
50 #if !defined(KERNEL_PRELOAD)
51 #include <kern/mach_header.h>
52 #include <string.h> // from libsa
54 #include <libkern/libkern.h>
57 extern struct mach_header _mh_execute_header
;
60 * return the last address (first avail)
62 * This routine operates against the currently executing kernel only
67 struct segment_command
*sgp
;
68 vm_offset_t last_addr
= 0;
69 struct mach_header
*header
= &_mh_execute_header
;
72 sgp
= (struct segment_command
*)
73 ((char *)header
+ sizeof(struct mach_header
));
74 for (i
= 0; i
< header
->ncmds
; i
++){
75 if ( sgp
->cmd
== LC_SEGMENT
) {
76 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
77 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
79 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
86 * This routine operates against the currently executing kernel only
91 struct mach_header
**tl
;
92 tl
= (struct mach_header
**)malloc(2*sizeof(struct mach_header
*));
93 tl
[0] = &_mh_execute_header
;
94 tl
[1] = (struct mach_header
*)0;
100 * This routine returns the a pointer to the data for the named section in the
101 * named segment if it exist in the mach header passed to it. Also it returns
102 * the size of the section data indirectly through the pointer size. Otherwise
103 * it returns zero for the pointer and the size.
105 * This routine can operate against any 32 bit mach header.
108 getsectdatafromheader(
109 struct mach_header
*mhp
,
111 const char *sectname
,
114 const struct section
*sp
;
117 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
118 if(sp
== (struct section
*)0){
123 result
= (void *)sp
->addr
;
128 * This routine returns the a pointer to the data for the named segment
129 * if it exist in the mach header passed to it. Also it returns
130 * the size of the segment data indirectly through the pointer size.
131 * Otherwise it returns zero for the pointer and the size.
133 * This routine can operate against any 32 bit mach header.
136 getsegdatafromheader(
137 struct mach_header
*mhp
,
141 const struct segment_command
*sc
;
144 sc
= getsegbynamefromheader(mhp
, segname
);
145 if(sc
== (struct segment_command
*)0){
150 result
= (void *)sc
->vmaddr
;
155 * This routine returns the section structure for the named section in the
156 * named segment for the mach_header pointer passed to it if it exist.
157 * Otherwise it returns zero.
159 * This routine can operate against any 32 bit mach header.
162 getsectbynamefromheader(
163 struct mach_header
*mhp
,
165 const char *sectname
)
167 struct segment_command
*sgp
;
171 sgp
= (struct segment_command
*)
172 ((char *)mhp
+ sizeof(struct mach_header
));
173 for(i
= 0; i
< mhp
->ncmds
; i
++){
174 if(sgp
->cmd
== LC_SEGMENT
)
175 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
176 mhp
->filetype
== MH_OBJECT
){
177 sp
= (struct section
*)((char *)sgp
+
178 sizeof(struct segment_command
));
179 for(j
= 0; j
< sgp
->nsects
; j
++){
180 if(strncmp(sp
->sectname
, sectname
,
181 sizeof(sp
->sectname
)) == 0 &&
182 strncmp(sp
->segname
, segname
,
183 sizeof(sp
->segname
)) == 0)
185 sp
= (struct section
*)((char *)sp
+
186 sizeof(struct section
));
189 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
191 return((struct section
*)0);
195 * This routine can operate against any 32 bit mach header.
197 struct segment_command
*
198 getsegbynamefromheader(
199 struct mach_header
*header
,
200 const char *seg_name
)
202 struct segment_command
*sgp
;
205 sgp
= (struct segment_command
*)
206 ((char *)header
+ sizeof(struct mach_header
));
207 for (i
= 0; i
< header
->ncmds
; i
++){
208 if ( sgp
->cmd
== LC_SEGMENT
209 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
211 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
213 return (struct segment_command
*)0;
218 * For now at least, all the rest of this seems unused.
219 * NOTE: The constant in here for segment alignment is machine-dependent,
220 * so if you include this, define a machine dependent constant for it's
224 struct segment_command seg
;
229 sizeof(fvm_data
), // cmdsize
235 VM_PROT_READ
, // maxprot
236 VM_PROT_READ
, // initprot,
255 struct segment_command
*fvm_seg
;
257 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
258 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
261 * Return the first segment_command in the header.
263 * This routine operates against the currently executing kernel only
265 struct segment_command
*
268 return firstsegfromheader(&_mh_execute_header
);
272 * This routine can operate against any 32 bit mach header, and returns a
273 * pointer to a 32 bit segment_command structure from the file prefixed by
274 * the header it is passed as its argument.
276 struct segment_command
*
277 firstsegfromheader(struct mach_header
*header
)
279 struct segment_command
*sgp
;
282 sgp
= (struct segment_command
*)
283 ((char *)header
+ sizeof(struct mach_header
));
284 for (i
= 0; i
< header
->ncmds
; i
++){
285 if (sgp
->cmd
== LC_SEGMENT
)
287 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
289 return (struct segment_command
*)0;
293 * This routine operates against a 32 bit mach segment_command structure
294 * pointer from the currently executing kernel only, to obtain the
295 * sequentially next segment_command structure in the currently executing
298 struct segment_command
*
299 nextseg(struct segment_command
*sgp
)
301 struct segment_command
*this;
303 this = nextsegfromheader(&_mh_execute_header
, sgp
);
306 * For the kernel's header add on the faked segment for the
307 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
309 if (!this && sgp
!= fvm_seg
)
316 * This routine operates against any 32 bit mach segment_command structure
317 * pointer and the provided 32 bit header, to obtain the sequentially next
318 * segment_command structure in that header.
320 struct segment_command
*
322 struct mach_header
*header
,
323 struct segment_command
*seg
)
325 struct segment_command
*sgp
;
328 sgp
= (struct segment_command
*)
329 ((char *)header
+ sizeof(struct mach_header
));
330 for (i
= 0; i
< header
->ncmds
; i
++) {
333 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
336 if (i
== header
->ncmds
)
337 return (struct segment_command
*)0;
339 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
340 for (; i
< header
->ncmds
; i
++) {
341 if (sgp
->cmd
== LC_SEGMENT
)
343 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
346 return (struct segment_command
*)0;
351 * Return the address of the named Mach-O segment from the currently
352 * executing 32 bit kernel, or NULL.
354 struct segment_command
*
355 getsegbyname(const char *seg_name
)
357 struct segment_command
*this;
359 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
362 * For the kernel's header add on the faked segment for the
363 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
365 if (!this && strncmp(seg_name
, fvm_seg
->segname
,
366 sizeof(fvm_seg
->segname
)) == 0)
373 * This routine returns the a pointer the section structure of the named
374 * section in the named segment if it exists in the currently executing
375 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
380 const char *sectname
)
382 return(getsectbynamefromheader(
383 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
387 * This routine can operate against any 32 bit segment_command structure to
388 * return the first 32 bit section immediately following that structure. If
389 * there are no sections associated with the segment_command structure, it
393 firstsect(struct segment_command
*sgp
)
395 if (!sgp
|| sgp
->nsects
== 0)
396 return (struct section
*)0;
398 return (struct section
*)(sgp
+1);
402 * This routine can operate against any 32 bit segment_command structure and
403 * 32 bit section to return the next consecutive 32 bit section immediately
404 * following the 32 bit section provided. If there are no sections following
405 * the provided section, it returns NULL.
408 nextsect(struct segment_command
*sgp
, struct section
*sp
)
410 struct section
*fsp
= firstsect(sgp
);
412 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
413 return (struct section
*)0;
419 * This routine can operate against any 32 bit mach header to return the
420 * first occurring 32 bit fvmfile_command section. If one is not present,
423 static struct fvmfile_command
*
424 fvmfilefromheader(struct mach_header
*header
)
426 struct fvmfile_command
*fvp
;
429 fvp
= (struct fvmfile_command
*)
430 ((char *)header
+ sizeof(struct mach_header
));
431 for (i
= 0; i
< header
->ncmds
; i
++){
432 if (fvp
->cmd
== LC_FVMFILE
)
434 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
436 return (struct fvmfile_command
*)0;
440 * Create a fake USER seg if a fvmfile_command is present.
442 * This routine operates against the currently executing kernel only
444 struct segment_command
*
447 struct segment_command
*sgp
= getsegbyname("__USER");
448 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
455 return (struct segment_command
*)0;
457 fvm_seg
= &fvm_data
.seg
;
461 sgp
->vmaddr
= fvp
->header_addr
;
462 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
464 strlcpy(sp
->sectname
, fvp
->name
.ptr
, sizeof(sp
->sectname
));
465 sp
->addr
= sgp
->vmaddr
;
466 sp
->size
= sgp
->vmsize
;
469 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
470 sp
->sectname
, sp
->addr
, sp
->size
);
477 * Figure out the size the size of the data associated with a
478 * loaded mach_header.
480 * This routine can operate against any 32 bit mach header.
483 getsizeofmacho(struct mach_header
*header
)
485 struct segment_command
*sgp
;
486 vm_offset_t last_addr
;
489 for ( sgp
= firstsegfromheader(header
)
491 ; sgp
= nextsegfromheader(header
, sgp
))
493 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
494 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
499 #endif /* !defined(KERNEL_PRELOAD) */