2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * File: kern/mach_header.c
33 * Functions for accessing mach-o headers.
35 * NOTE: This file supports only 32 bit mach headers at the present
36 * time; it's primary use is by kld, and all externally
37 * referenced routines at the present time operate against
38 * the 32 bit mach header _mh_execute_header, which is the
39 * header for the currently executing kernel. Adding support
40 * for 64 bit kernels is possible, but is not necessary at the
44 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
45 * Added getsegdatafromheader();
47 * 29-Jan-92 Mike DeMoney (mike@next.com)
48 * Made into machine independent form from machdep/m68k/mach_header.c.
49 * Ifdef'ed out most of this since I couldn't find any references.
52 #if !defined(KERNEL_PRELOAD)
53 #include <kern/mach_header.h>
54 #include <string.h> // from libsa
56 extern struct mach_header _mh_execute_header
;
59 * return the last address (first avail)
61 * This routine operates against the currently executing kernel only
66 struct segment_command
*sgp
;
67 vm_offset_t last_addr
= 0;
68 struct mach_header
*header
= &_mh_execute_header
;
71 sgp
= (struct segment_command
*)
72 ((char *)header
+ sizeof(struct mach_header
));
73 for (i
= 0; i
< header
->ncmds
; i
++){
74 if ( sgp
->cmd
== LC_SEGMENT
) {
75 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
76 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
78 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
85 * This routine operates against the currently executing kernel only
90 struct mach_header
**tl
;
91 tl
= (struct mach_header
**)malloc(2*sizeof(struct mach_header
*));
92 tl
[0] = &_mh_execute_header
;
93 tl
[1] = (struct mach_header
*)0;
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 32 bit mach header.
107 getsectdatafromheader(
108 struct mach_header
*mhp
,
110 const char *sectname
,
113 const struct section
*sp
;
116 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
117 if(sp
== (struct section
*)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.
132 * This routine can operate against any 32 bit mach header.
135 getsegdatafromheader(
136 struct mach_header
*mhp
,
140 const struct segment_command
*sc
;
143 sc
= getsegbynamefromheader(mhp
, segname
);
144 if(sc
== (struct segment_command
*)0){
149 result
= (void *)sc
->vmaddr
;
154 * This routine returns the section structure for the named section in the
155 * named segment for the mach_header pointer passed to it if it exist.
156 * Otherwise it returns zero.
158 * This routine can operate against any 32 bit mach header.
161 getsectbynamefromheader(
162 struct mach_header
*mhp
,
164 const char *sectname
)
166 struct segment_command
*sgp
;
170 sgp
= (struct segment_command
*)
171 ((char *)mhp
+ sizeof(struct mach_header
));
172 for(i
= 0; i
< mhp
->ncmds
; i
++){
173 if(sgp
->cmd
== LC_SEGMENT
)
174 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
175 mhp
->filetype
== MH_OBJECT
){
176 sp
= (struct section
*)((char *)sgp
+
177 sizeof(struct segment_command
));
178 for(j
= 0; j
< sgp
->nsects
; j
++){
179 if(strncmp(sp
->sectname
, sectname
,
180 sizeof(sp
->sectname
)) == 0 &&
181 strncmp(sp
->segname
, segname
,
182 sizeof(sp
->segname
)) == 0)
184 sp
= (struct section
*)((char *)sp
+
185 sizeof(struct section
));
188 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
190 return((struct section
*)0);
194 * This routine can operate against any 32 bit mach header.
196 struct segment_command
*
197 getsegbynamefromheader(
198 struct mach_header
*header
,
199 const char *seg_name
)
201 struct segment_command
*sgp
;
204 sgp
= (struct segment_command
*)
205 ((char *)header
+ sizeof(struct mach_header
));
206 for (i
= 0; i
< header
->ncmds
; i
++){
207 if ( sgp
->cmd
== LC_SEGMENT
208 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
210 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
212 return (struct segment_command
*)0;
217 * For now at least, all the rest of this seems unused.
218 * NOTE: The constant in here for segment alignment is machine-dependent,
219 * so if you include this, define a machine dependent constant for it's
223 struct segment_command seg
;
228 sizeof(fvm_data
), // cmdsize
234 VM_PROT_READ
, // maxprot
235 VM_PROT_READ
, // initprot,
254 struct segment_command
*fvm_seg
;
256 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
257 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
260 * Return the first segment_command in the header.
262 * This routine operates against the currently executing kernel only
264 struct segment_command
*
267 return firstsegfromheader(&_mh_execute_header
);
271 * This routine can operate against any 32 bit mach header, and returns a
272 * pointer to a 32 bit segment_command structure from the file prefixed by
273 * the header it is passed as its argument.
275 struct segment_command
*
276 firstsegfromheader(struct mach_header
*header
)
278 struct segment_command
*sgp
;
281 sgp
= (struct segment_command
*)
282 ((char *)header
+ sizeof(struct mach_header
));
283 for (i
= 0; i
< header
->ncmds
; i
++){
284 if (sgp
->cmd
== LC_SEGMENT
)
286 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
288 return (struct segment_command
*)0;
292 * This routine operates against a 32 bit mach segment_command structure
293 * pointer from the currently executing kernel only, to obtain the
294 * sequentially next segment_command structure in the currently executing
297 struct segment_command
*
298 nextseg(struct segment_command
*sgp
)
300 struct segment_command
*this;
302 this = nextsegfromheader(&_mh_execute_header
, sgp
);
305 * For the kernel's header add on the faked segment for the
306 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
308 if (!this && sgp
!= fvm_seg
)
315 * This routine operates against any 32 bit mach segment_command structure
316 * pointer and the provided 32 bit header, to obtain the sequentially next
317 * segment_command structure in that header.
319 struct segment_command
*
321 struct mach_header
*header
,
322 struct segment_command
*seg
)
324 struct segment_command
*sgp
;
327 sgp
= (struct segment_command
*)
328 ((char *)header
+ sizeof(struct mach_header
));
329 for (i
= 0; i
< header
->ncmds
; i
++) {
332 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
335 if (i
== header
->ncmds
)
336 return (struct segment_command
*)0;
338 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
339 for (; i
< header
->ncmds
; i
++) {
340 if (sgp
->cmd
== LC_SEGMENT
)
342 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
345 return (struct segment_command
*)0;
350 * Return the address of the named Mach-O segment from the currently
351 * executing 32 bit kernel, or NULL.
353 struct segment_command
*
354 getsegbyname(const char *seg_name
)
356 struct segment_command
*this;
358 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
361 * For the kernel's header add on the faked segment for the
362 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
364 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
371 * This routine returns the a pointer the section structure of the named
372 * section in the named segment if it exists in the currently executing
373 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
378 const char *sectname
)
380 return(getsectbynamefromheader(
381 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
385 * This routine can operate against any 32 bit segment_command structure to
386 * return the first 32 bit section immediately following that structure. If
387 * there are no sections associated with the segment_command structure, it
391 firstsect(struct segment_command
*sgp
)
393 if (!sgp
|| sgp
->nsects
== 0)
394 return (struct section
*)0;
396 return (struct section
*)(sgp
+1);
400 * This routine can operate against any 32 bit segment_command structure and
401 * 32 bit section to return the next consecutive 32 bit section immediately
402 * following the 32 bit section provided. If there are no sections following
403 * the provided section, it returns NULL.
406 nextsect(struct segment_command
*sgp
, struct section
*sp
)
408 struct section
*fsp
= firstsect(sgp
);
410 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
411 return (struct section
*)0;
417 * This routine can operate against any 32 bit mach header to return the
418 * first occurring 32 bit fvmfile_command section. If one is not present,
421 static struct fvmfile_command
*
422 fvmfilefromheader(struct mach_header
*header
)
424 struct fvmfile_command
*fvp
;
427 fvp
= (struct fvmfile_command
*)
428 ((char *)header
+ sizeof(struct mach_header
));
429 for (i
= 0; i
< header
->ncmds
; i
++){
430 if (fvp
->cmd
== LC_FVMFILE
)
432 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
434 return (struct fvmfile_command
*)0;
438 * Create a fake USER seg if a fvmfile_command is present.
440 * This routine operates against the currently executing kernel only
442 struct segment_command
*
445 struct segment_command
*sgp
= getsegbyname("__USER");
446 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
453 return (struct segment_command
*)0;
455 fvm_seg
= &fvm_data
.seg
;
459 sgp
->vmaddr
= fvp
->header_addr
;
460 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
462 strcpy(sp
->sectname
, fvp
->name
.ptr
);
463 sp
->addr
= sgp
->vmaddr
;
464 sp
->size
= sgp
->vmsize
;
467 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
468 sp
->sectname
, sp
->addr
, sp
->size
);
475 * Figure out the size the size of the data associated with a
476 * loaded mach_header.
478 * This routine can operate against any 32 bit mach header.
481 getsizeofmacho(struct mach_header
*header
)
483 struct segment_command
*sgp
;
484 vm_offset_t last_addr
;
487 for ( sgp
= firstsegfromheader(header
)
489 ; sgp
= nextsegfromheader(header
, sgp
))
491 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
492 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
497 #endif /* !defined(KERNEL_PRELOAD) */