2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * File: kern/mach_header.c
26 * Functions for accessing mach-o headers.
28 * NOTE: This file supports only 32 bit mach headers at the present
29 * time; it's primary use is by kld, and all externally
30 * referenced routines at the present time operate against
31 * the 32 bit mach header _mh_execute_header, which is the
32 * header for the currently executing kernel. Adding support
33 * for 64 bit kernels is possible, but is not necessary at the
37 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
38 * Added getsegdatafromheader();
40 * 29-Jan-92 Mike DeMoney (mike@next.com)
41 * Made into machine independent form from machdep/m68k/mach_header.c.
42 * Ifdef'ed out most of this since I couldn't find any references.
45 #if !defined(KERNEL_PRELOAD)
46 #include <kern/mach_header.h>
47 #include <string.h> // from libsa
49 extern struct mach_header _mh_execute_header
;
52 * return the last address (first avail)
54 * This routine operates against the currently executing kernel only
59 struct segment_command
*sgp
;
60 vm_offset_t last_addr
= 0;
61 struct mach_header
*header
= &_mh_execute_header
;
64 sgp
= (struct segment_command
*)
65 ((char *)header
+ sizeof(struct mach_header
));
66 for (i
= 0; i
< header
->ncmds
; i
++){
67 if ( sgp
->cmd
== LC_SEGMENT
) {
68 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
69 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
71 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
78 * This routine operates against the currently executing kernel only
83 struct mach_header
**tl
;
84 tl
= (struct mach_header
**)malloc(2*sizeof(struct mach_header
*));
85 tl
[0] = &_mh_execute_header
;
86 tl
[1] = (struct mach_header
*)0;
92 * This routine returns the a pointer to the data for the named section in the
93 * named segment if it exist in the mach header passed to it. Also it returns
94 * the size of the section data indirectly through the pointer size. Otherwise
95 * it returns zero for the pointer and the size.
97 * This routine can operate against any 32 bit mach header.
100 getsectdatafromheader(
101 struct mach_header
*mhp
,
103 const char *sectname
,
106 const struct section
*sp
;
109 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
110 if(sp
== (struct section
*)0){
115 result
= (void *)sp
->addr
;
120 * This routine returns the a pointer to the data for the named segment
121 * if it exist in the mach header passed to it. Also it returns
122 * the size of the segment data indirectly through the pointer size.
123 * Otherwise it returns zero for the pointer and the size.
125 * This routine can operate against any 32 bit mach header.
128 getsegdatafromheader(
129 struct mach_header
*mhp
,
133 const struct segment_command
*sc
;
136 sc
= getsegbynamefromheader(mhp
, segname
);
137 if(sc
== (struct segment_command
*)0){
142 result
= (void *)sc
->vmaddr
;
147 * This routine returns the section structure for the named section in the
148 * named segment for the mach_header pointer passed to it if it exist.
149 * Otherwise it returns zero.
151 * This routine can operate against any 32 bit mach header.
154 getsectbynamefromheader(
155 struct mach_header
*mhp
,
157 const char *sectname
)
159 struct segment_command
*sgp
;
163 sgp
= (struct segment_command
*)
164 ((char *)mhp
+ sizeof(struct mach_header
));
165 for(i
= 0; i
< mhp
->ncmds
; i
++){
166 if(sgp
->cmd
== LC_SEGMENT
)
167 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
168 mhp
->filetype
== MH_OBJECT
){
169 sp
= (struct section
*)((char *)sgp
+
170 sizeof(struct segment_command
));
171 for(j
= 0; j
< sgp
->nsects
; j
++){
172 if(strncmp(sp
->sectname
, sectname
,
173 sizeof(sp
->sectname
)) == 0 &&
174 strncmp(sp
->segname
, segname
,
175 sizeof(sp
->segname
)) == 0)
177 sp
= (struct section
*)((char *)sp
+
178 sizeof(struct section
));
181 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
183 return((struct section
*)0);
187 * This routine can operate against any 32 bit mach header.
189 struct segment_command
*
190 getsegbynamefromheader(
191 struct mach_header
*header
,
192 const char *seg_name
)
194 struct segment_command
*sgp
;
197 sgp
= (struct segment_command
*)
198 ((char *)header
+ sizeof(struct mach_header
));
199 for (i
= 0; i
< header
->ncmds
; i
++){
200 if ( sgp
->cmd
== LC_SEGMENT
201 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
203 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
205 return (struct segment_command
*)0;
210 * For now at least, all the rest of this seems unused.
211 * NOTE: The constant in here for segment alignment is machine-dependent,
212 * so if you include this, define a machine dependent constant for it's
216 struct segment_command seg
;
221 sizeof(fvm_data
), // cmdsize
227 VM_PROT_READ
, // maxprot
228 VM_PROT_READ
, // initprot,
247 struct segment_command
*fvm_seg
;
249 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
250 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
253 * Return the first segment_command in the header.
255 * This routine operates against the currently executing kernel only
257 struct segment_command
*
260 return firstsegfromheader(&_mh_execute_header
);
264 * This routine can operate against any 32 bit mach header, and returns a
265 * pointer to a 32 bit segment_command structure from the file prefixed by
266 * the header it is passed as its argument.
268 struct segment_command
*
269 firstsegfromheader(struct mach_header
*header
)
271 struct segment_command
*sgp
;
274 sgp
= (struct segment_command
*)
275 ((char *)header
+ sizeof(struct mach_header
));
276 for (i
= 0; i
< header
->ncmds
; i
++){
277 if (sgp
->cmd
== LC_SEGMENT
)
279 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
281 return (struct segment_command
*)0;
285 * This routine operates against a 32 bit mach segment_command structure
286 * pointer from the currently executing kernel only, to obtain the
287 * sequentially next segment_command structure in the currently executing
290 struct segment_command
*
291 nextseg(struct segment_command
*sgp
)
293 struct segment_command
*this;
295 this = nextsegfromheader(&_mh_execute_header
, sgp
);
298 * For the kernel's header add on the faked segment for the
299 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
301 if (!this && sgp
!= fvm_seg
)
308 * This routine operates against any 32 bit mach segment_command structure
309 * pointer and the provided 32 bit header, to obtain the sequentially next
310 * segment_command structure in that header.
312 struct segment_command
*
314 struct mach_header
*header
,
315 struct segment_command
*seg
)
317 struct segment_command
*sgp
;
320 sgp
= (struct segment_command
*)
321 ((char *)header
+ sizeof(struct mach_header
));
322 for (i
= 0; i
< header
->ncmds
; i
++) {
325 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
328 if (i
== header
->ncmds
)
329 return (struct segment_command
*)0;
331 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
332 for (; i
< header
->ncmds
; i
++) {
333 if (sgp
->cmd
== LC_SEGMENT
)
335 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
338 return (struct segment_command
*)0;
343 * Return the address of the named Mach-O segment from the currently
344 * executing 32 bit kernel, or NULL.
346 struct segment_command
*
347 getsegbyname(const char *seg_name
)
349 struct segment_command
*this;
351 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
354 * For the kernel's header add on the faked segment for the
355 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
357 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
364 * This routine returns the a pointer the section structure of the named
365 * section in the named segment if it exists in the currently executing
366 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
371 const char *sectname
)
373 return(getsectbynamefromheader(
374 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
378 * This routine can operate against any 32 bit segment_command structure to
379 * return the first 32 bit section immediately following that structure. If
380 * there are no sections associated with the segment_command structure, it
384 firstsect(struct segment_command
*sgp
)
386 if (!sgp
|| sgp
->nsects
== 0)
387 return (struct section
*)0;
389 return (struct section
*)(sgp
+1);
393 * This routine can operate against any 32 bit segment_command structure and
394 * 32 bit section to return the next consecutive 32 bit section immediately
395 * following the 32 bit section provided. If there are no sections following
396 * the provided section, it returns NULL.
399 nextsect(struct segment_command
*sgp
, struct section
*sp
)
401 struct section
*fsp
= firstsect(sgp
);
403 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
404 return (struct section
*)0;
410 * This routine can operate against any 32 bit mach header to return the
411 * first occurring 32 bit fvmfile_command section. If one is not present,
414 static struct fvmfile_command
*
415 fvmfilefromheader(struct mach_header
*header
)
417 struct fvmfile_command
*fvp
;
420 fvp
= (struct fvmfile_command
*)
421 ((char *)header
+ sizeof(struct mach_header
));
422 for (i
= 0; i
< header
->ncmds
; i
++){
423 if (fvp
->cmd
== LC_FVMFILE
)
425 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
427 return (struct fvmfile_command
*)0;
431 * Create a fake USER seg if a fvmfile_command is present.
433 * This routine operates against the currently executing kernel only
435 struct segment_command
*
438 struct segment_command
*sgp
= getsegbyname("__USER");
439 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
446 return (struct segment_command
*)0;
448 fvm_seg
= &fvm_data
.seg
;
452 sgp
->vmaddr
= fvp
->header_addr
;
453 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
455 strcpy(sp
->sectname
, fvp
->name
.ptr
);
456 sp
->addr
= sgp
->vmaddr
;
457 sp
->size
= sgp
->vmsize
;
460 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
461 sp
->sectname
, sp
->addr
, sp
->size
);
468 * Figure out the size the size of the data associated with a
469 * loaded mach_header.
471 * This routine can operate against any 32 bit mach header.
474 getsizeofmacho(struct mach_header
*header
)
476 struct segment_command
*sgp
;
477 vm_offset_t last_addr
;
480 for ( sgp
= firstsegfromheader(header
)
482 ; sgp
= nextsegfromheader(header
, sgp
))
484 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
485 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
490 #endif /* !defined(KERNEL_PRELOAD) */