2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * File: kern/mach_header.c
25 * Functions for accessing mach-o headers.
27 * NOTE: This file supports only 32 bit mach headers at the present
28 * time; it's primary use is by kld, and all externally
29 * referenced routines at the present time operate against
30 * the 32 bit mach header _mh_execute_header, which is the
31 * header for the currently executing kernel. Adding support
32 * for 64 bit kernels is possible, but is not necessary at the
36 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
37 * Added getsegdatafromheader();
39 * 29-Jan-92 Mike DeMoney (mike@next.com)
40 * Made into machine independent form from machdep/m68k/mach_header.c.
41 * Ifdef'ed out most of this since I couldn't find any references.
44 #if !defined(KERNEL_PRELOAD)
45 #include <kern/mach_header.h>
46 #include <string.h> // from libsa
48 extern struct mach_header _mh_execute_header
;
51 * return the last address (first avail)
53 * This routine operates against the currently executing kernel only
58 struct segment_command
*sgp
;
59 vm_offset_t last_addr
= 0;
60 struct mach_header
*header
= &_mh_execute_header
;
63 sgp
= (struct segment_command
*)
64 ((char *)header
+ sizeof(struct mach_header
));
65 for (i
= 0; i
< header
->ncmds
; i
++){
66 if ( sgp
->cmd
== LC_SEGMENT
) {
67 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
68 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
70 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
77 * This routine operates against the currently executing kernel only
82 struct mach_header
**tl
;
83 tl
= (struct mach_header
**)malloc(2*sizeof(struct mach_header
*));
84 tl
[0] = &_mh_execute_header
;
85 tl
[1] = (struct mach_header
*)0;
91 * This routine returns the a pointer to the data for the named section in the
92 * named segment if it exist in the mach header passed to it. Also it returns
93 * the size of the section data indirectly through the pointer size. Otherwise
94 * it returns zero for the pointer and the size.
96 * This routine can operate against any 32 bit mach header.
99 getsectdatafromheader(
100 struct mach_header
*mhp
,
102 const char *sectname
,
105 const struct section
*sp
;
108 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
109 if(sp
== (struct section
*)0){
114 result
= (void *)sp
->addr
;
119 * This routine returns the a pointer to the data for the named segment
120 * if it exist in the mach header passed to it. Also it returns
121 * the size of the segment data indirectly through the pointer size.
122 * Otherwise it returns zero for the pointer and the size.
124 * This routine can operate against any 32 bit mach header.
127 getsegdatafromheader(
128 struct mach_header
*mhp
,
132 const struct segment_command
*sc
;
135 sc
= getsegbynamefromheader(mhp
, segname
);
136 if(sc
== (struct segment_command
*)0){
141 result
= (void *)sc
->vmaddr
;
146 * This routine returns the section structure for the named section in the
147 * named segment for the mach_header pointer passed to it if it exist.
148 * Otherwise it returns zero.
150 * This routine can operate against any 32 bit mach header.
153 getsectbynamefromheader(
154 struct mach_header
*mhp
,
156 const char *sectname
)
158 struct segment_command
*sgp
;
162 sgp
= (struct segment_command
*)
163 ((char *)mhp
+ sizeof(struct mach_header
));
164 for(i
= 0; i
< mhp
->ncmds
; i
++){
165 if(sgp
->cmd
== LC_SEGMENT
)
166 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
167 mhp
->filetype
== MH_OBJECT
){
168 sp
= (struct section
*)((char *)sgp
+
169 sizeof(struct segment_command
));
170 for(j
= 0; j
< sgp
->nsects
; j
++){
171 if(strncmp(sp
->sectname
, sectname
,
172 sizeof(sp
->sectname
)) == 0 &&
173 strncmp(sp
->segname
, segname
,
174 sizeof(sp
->segname
)) == 0)
176 sp
= (struct section
*)((char *)sp
+
177 sizeof(struct section
));
180 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
182 return((struct section
*)0);
186 * This routine can operate against any 32 bit mach header.
188 struct segment_command
*
189 getsegbynamefromheader(
190 struct mach_header
*header
,
191 const char *seg_name
)
193 struct segment_command
*sgp
;
196 sgp
= (struct segment_command
*)
197 ((char *)header
+ sizeof(struct mach_header
));
198 for (i
= 0; i
< header
->ncmds
; i
++){
199 if ( sgp
->cmd
== LC_SEGMENT
200 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
202 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
204 return (struct segment_command
*)0;
209 * For now at least, all the rest of this seems unused.
210 * NOTE: The constant in here for segment alignment is machine-dependent,
211 * so if you include this, define a machine dependent constant for it's
215 struct segment_command seg
;
220 sizeof(fvm_data
), // cmdsize
226 VM_PROT_READ
, // maxprot
227 VM_PROT_READ
, // initprot,
246 struct segment_command
*fvm_seg
;
248 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
249 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
252 * Return the first segment_command in the header.
254 * This routine operates against the currently executing kernel only
256 struct segment_command
*
259 return firstsegfromheader(&_mh_execute_header
);
263 * This routine can operate against any 32 bit mach header, and returns a
264 * pointer to a 32 bit segment_command structure from the file prefixed by
265 * the header it is passed as its argument.
267 struct segment_command
*
268 firstsegfromheader(struct mach_header
*header
)
270 struct segment_command
*sgp
;
273 sgp
= (struct segment_command
*)
274 ((char *)header
+ sizeof(struct mach_header
));
275 for (i
= 0; i
< header
->ncmds
; i
++){
276 if (sgp
->cmd
== LC_SEGMENT
)
278 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
280 return (struct segment_command
*)0;
284 * This routine operates against a 32 bit mach segment_command structure
285 * pointer from the currently executing kernel only, to obtain the
286 * sequentially next segment_command structure in the currently executing
289 struct segment_command
*
290 nextseg(struct segment_command
*sgp
)
292 struct segment_command
*this;
294 this = nextsegfromheader(&_mh_execute_header
, sgp
);
297 * For the kernel's header add on the faked segment for the
298 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
300 if (!this && sgp
!= fvm_seg
)
307 * This routine operates against any 32 bit mach segment_command structure
308 * pointer and the provided 32 bit header, to obtain the sequentially next
309 * segment_command structure in that header.
311 struct segment_command
*
313 struct mach_header
*header
,
314 struct segment_command
*seg
)
316 struct segment_command
*sgp
;
319 sgp
= (struct segment_command
*)
320 ((char *)header
+ sizeof(struct mach_header
));
321 for (i
= 0; i
< header
->ncmds
; i
++) {
324 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
327 if (i
== header
->ncmds
)
328 return (struct segment_command
*)0;
330 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
331 for (; i
< header
->ncmds
; i
++) {
332 if (sgp
->cmd
== LC_SEGMENT
)
334 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
337 return (struct segment_command
*)0;
342 * Return the address of the named Mach-O segment from the currently
343 * executing 32 bit kernel, or NULL.
345 struct segment_command
*
346 getsegbyname(const char *seg_name
)
348 struct segment_command
*this;
350 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
353 * For the kernel's header add on the faked segment for the
354 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
356 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
363 * This routine returns the a pointer the section structure of the named
364 * section in the named segment if it exists in the currently executing
365 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
370 const char *sectname
)
372 return(getsectbynamefromheader(
373 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
377 * This routine can operate against any 32 bit segment_command structure to
378 * return the first 32 bit section immediately following that structure. If
379 * there are no sections associated with the segment_command structure, it
383 firstsect(struct segment_command
*sgp
)
385 if (!sgp
|| sgp
->nsects
== 0)
386 return (struct section
*)0;
388 return (struct section
*)(sgp
+1);
392 * This routine can operate against any 32 bit segment_command structure and
393 * 32 bit section to return the next consecutive 32 bit section immediately
394 * following the 32 bit section provided. If there are no sections following
395 * the provided section, it returns NULL.
398 nextsect(struct segment_command
*sgp
, struct section
*sp
)
400 struct section
*fsp
= firstsect(sgp
);
402 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
403 return (struct section
*)0;
409 * This routine can operate against any 32 bit mach header to return the
410 * first occurring 32 bit fvmfile_command section. If one is not present,
413 static struct fvmfile_command
*
414 fvmfilefromheader(struct mach_header
*header
)
416 struct fvmfile_command
*fvp
;
419 fvp
= (struct fvmfile_command
*)
420 ((char *)header
+ sizeof(struct mach_header
));
421 for (i
= 0; i
< header
->ncmds
; i
++){
422 if (fvp
->cmd
== LC_FVMFILE
)
424 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
426 return (struct fvmfile_command
*)0;
430 * Create a fake USER seg if a fvmfile_command is present.
432 * This routine operates against the currently executing kernel only
434 struct segment_command
*
437 struct segment_command
*sgp
= getsegbyname("__USER");
438 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
445 return (struct segment_command
*)0;
447 fvm_seg
= &fvm_data
.seg
;
451 sgp
->vmaddr
= fvp
->header_addr
;
452 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
454 strcpy(sp
->sectname
, fvp
->name
.ptr
);
455 sp
->addr
= sgp
->vmaddr
;
456 sp
->size
= sgp
->vmsize
;
459 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
460 sp
->sectname
, sp
->addr
, sp
->size
);
467 * Figure out the size the size of the data associated with a
468 * loaded mach_header.
470 * This routine can operate against any 32 bit mach header.
473 getsizeofmacho(struct mach_header
*header
)
475 struct segment_command
*sgp
;
476 vm_offset_t last_addr
;
479 for ( sgp
= firstsegfromheader(header
)
481 ; sgp
= nextsegfromheader(header
, sgp
))
483 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
484 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
489 #endif /* !defined(KERNEL_PRELOAD) */