2 * Copyright (c) 2000 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.
28 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
29 * Added getsegdatafromheader();
31 * 29-Jan-92 Mike DeMoney (mike@next.com)
32 * Made into machine independent form from machdep/m68k/mach_header.c.
33 * Ifdef'ed out most of this since I couldn't find any references.
36 #if !defined(KERNEL_PRELOAD)
37 #include <kern/mach_header.h>
39 extern struct mach_header _mh_execute_header
;
41 struct section
*getsectbynamefromheader(
42 struct mach_header
*header
,
45 struct segment_command
*getsegbynamefromheader(
46 struct mach_header
*header
,
50 * return the last address (first avail)
52 vm_offset_t
getlastaddr(void)
54 struct segment_command
*sgp
;
55 vm_offset_t last_addr
= 0;
56 struct mach_header
*header
= &_mh_execute_header
;
59 sgp
= (struct segment_command
*)
60 ((char *)header
+ sizeof(struct mach_header
));
61 for (i
= 0; i
< header
->ncmds
; i
++){
62 if ( sgp
->cmd
== LC_SEGMENT
) {
63 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
64 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
66 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
75 extern struct mach_header _mh_execute_header
;
76 struct mach_header
**tl
;
77 tl
= (struct mach_header
**)malloc(2*sizeof(struct mach_header
*));
78 tl
[0] = &_mh_execute_header
;
79 tl
[1] = (struct mach_header
*)0;
85 * This routine returns the a pointer to the data for the named section in the
86 * named segment if it exist in the mach header passed to it. Also it returns
87 * the size of the section data indirectly through the pointer size. Otherwise
88 * it returns zero for the pointer and the size.
91 getsectdatafromheader(
92 struct mach_header
*mhp
,
97 const struct section
*sp
;
100 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
101 if(sp
== (struct section
*)0){
106 result
= (void *)sp
->addr
;
111 * This routine returns the a pointer to the data for the named segment
112 * if it exist in the mach header passed to it. Also it returns
113 * the size of the segment data indirectly through the pointer size.
114 * Otherwise it returns zero for the pointer and the size.
117 getsegdatafromheader(
118 struct mach_header
*mhp
,
122 const struct segment_command
*sc
;
125 sc
= getsegbynamefromheader(mhp
, segname
);
126 if(sc
== (struct segment_command
*)0){
131 result
= (void *)sc
->vmaddr
;
136 * This routine returns the section structure for the named section in the
137 * named segment for the mach_header pointer passed to it if it exist.
138 * Otherwise it returns zero.
141 getsectbynamefromheader(
142 struct mach_header
*mhp
,
146 struct segment_command
*sgp
;
150 sgp
= (struct segment_command
*)
151 ((char *)mhp
+ sizeof(struct mach_header
));
152 for(i
= 0; i
< mhp
->ncmds
; i
++){
153 if(sgp
->cmd
== LC_SEGMENT
)
154 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
155 mhp
->filetype
== MH_OBJECT
){
156 sp
= (struct section
*)((char *)sgp
+
157 sizeof(struct segment_command
));
158 for(j
= 0; j
< sgp
->nsects
; j
++){
159 if(strncmp(sp
->sectname
, sectname
,
160 sizeof(sp
->sectname
)) == 0 &&
161 strncmp(sp
->segname
, segname
,
162 sizeof(sp
->segname
)) == 0)
164 sp
= (struct section
*)((char *)sp
+
165 sizeof(struct section
));
168 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
170 return((struct section
*)0);
173 struct segment_command
*getsegbynamefromheader(
174 struct mach_header
*header
,
177 struct segment_command
*sgp
;
180 sgp
= (struct segment_command
*)
181 ((char *)header
+ sizeof(struct mach_header
));
182 for (i
= 0; i
< header
->ncmds
; i
++){
183 if ( sgp
->cmd
== LC_SEGMENT
184 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
186 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
188 return (struct segment_command
*)0;
193 * For now at least, all the rest of this seems unused.
194 * NOTE: The constant in here for segment alignment is machine-dependent,
195 * so if you include this, define a machine dependent constant for it's
199 struct segment_command seg
;
204 sizeof(fvm_data
), // cmdsize
210 VM_PROT_READ
, // maxprot
211 VM_PROT_READ
, // initprot,
228 struct segment_command
*fvm_seg
;
230 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
231 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
234 * Return the first segment_command in the header.
236 struct segment_command
*firstseg(void)
238 return firstsegfromheader(&_mh_execute_header
);
241 struct segment_command
*firstsegfromheader(struct mach_header
*header
)
243 struct segment_command
*sgp
;
246 sgp
= (struct segment_command
*)
247 ((char *)header
+ sizeof(struct mach_header
));
248 for (i
= 0; i
< header
->ncmds
; i
++){
249 if (sgp
->cmd
== LC_SEGMENT
)
251 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
253 return (struct segment_command
*)0;
256 struct segment_command
*nextseg(struct segment_command
*sgp
)
258 struct segment_command
*this;
260 this = nextsegfromheader(&_mh_execute_header
, sgp
);
263 * For the kernel's header add on the faked segment for the
264 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
266 if (!this && sgp
!= fvm_seg
)
272 struct segment_command
*nextsegfromheader(
273 struct mach_header
*header
,
274 struct segment_command
*seg
)
276 struct segment_command
*sgp
;
279 sgp
= (struct segment_command
*)
280 ((char *)header
+ sizeof(struct mach_header
));
281 for (i
= 0; i
< header
->ncmds
; i
++) {
284 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
287 if (i
== header
->ncmds
)
288 return (struct segment_command
*)0;
290 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
291 for (; i
< header
->ncmds
; i
++) {
292 if (sgp
->cmd
== LC_SEGMENT
)
294 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
297 return (struct segment_command
*)0;
302 * Return the address of the named Mach-O segment, or NULL.
304 struct segment_command
*getsegbyname(char *seg_name
)
306 struct segment_command
*this;
308 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
311 * For the kernel's header add on the faked segment for the
312 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
314 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
321 * This routine returns the a pointer the section structure of the named
322 * section in the named segment if it exist in the mach executable it is
323 * linked into. Otherwise it returns zero.
330 return(getsectbynamefromheader(
331 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
334 struct section
*firstsect(struct segment_command
*sgp
)
338 if (!sgp
|| sgp
->nsects
== 0)
339 return (struct section
*)0;
341 return (struct section
*)(sgp
+1);
344 struct section
*nextsect(struct segment_command
*sgp
, struct section
*sp
)
346 struct section
*fsp
= firstsect(sgp
);
348 if (sp
- fsp
>= sgp
->nsects
-1)
349 return (struct section
*)0;
354 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
)
356 struct fvmfile_command
*fvp
;
359 fvp
= (struct fvmfile_command
*)
360 ((char *)header
+ sizeof(struct mach_header
));
361 for (i
= 0; i
< header
->ncmds
; i
++){
362 if (fvp
->cmd
== LC_FVMFILE
)
364 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
366 return (struct fvmfile_command
*)0;
370 * Create a fake USER seg if a fvmfile_command is present.
372 struct segment_command
*getfakefvmseg(void)
374 struct segment_command
*sgp
= getsegbyname("__USER");
375 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
382 return (struct segment_command
*)0;
384 fvm_seg
= &fvm_data
.seg
;
388 sgp
->vmaddr
= fvp
->header_addr
;
389 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
391 strcpy(sp
->sectname
, fvp
->name
.ptr
);
392 sp
->addr
= sgp
->vmaddr
;
393 sp
->size
= sgp
->vmsize
;
396 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
397 sp
->sectname
, sp
->addr
, sp
->size
);
402 * Figure out the size the size of the data associated with a
403 * loaded mach_header.
405 static vm_offset_t
getsizeofmacho(struct mach_header
*header
)
407 struct segment_command
*sgp
;
409 vm_offset_t last_addr
;
412 for ( sgp
= firstsegfromheader(header
)
414 ; sgp
= nextsegfromheader(header
, sgp
))
416 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
417 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
422 #endif /* !defined(KERNEL_PRELOAD) */