2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * File: kern/mach_header.c
28 * Functions for accessing mach-o headers.
31 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
32 * Added getsegdatafromheader();
34 * 29-Jan-92 Mike DeMoney (mike@next.com)
35 * Made into machine independent form from machdep/m68k/mach_header.c.
36 * Ifdef'ed out most of this since I couldn't find any references.
39 #if !defined(KERNEL_PRELOAD)
40 #include <kern/mach_header.h>
42 extern struct mach_header _mh_execute_header
;
44 struct section
*getsectbynamefromheader(
45 struct mach_header
*header
,
48 struct segment_command
*getsegbynamefromheader(
49 struct mach_header
*header
,
53 * return the last address (first avail)
55 vm_offset_t
getlastaddr(void)
57 struct segment_command
*sgp
;
58 vm_offset_t last_addr
= 0;
59 struct mach_header
*header
= &_mh_execute_header
;
62 sgp
= (struct segment_command
*)
63 ((char *)header
+ sizeof(struct mach_header
));
64 for (i
= 0; i
< header
->ncmds
; i
++){
65 if ( sgp
->cmd
== LC_SEGMENT
) {
66 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
67 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
69 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
78 extern struct mach_header _mh_execute_header
;
79 struct mach_header
**tl
;
80 tl
= (struct mach_header
**)malloc(2*sizeof(struct mach_header
*));
81 tl
[0] = &_mh_execute_header
;
82 tl
[1] = (struct mach_header
*)0;
88 * This routine returns the a pointer to the data for the named section in the
89 * named segment if it exist in the mach header passed to it. Also it returns
90 * the size of the section data indirectly through the pointer size. Otherwise
91 * it returns zero for the pointer and the size.
94 getsectdatafromheader(
95 struct mach_header
*mhp
,
100 const struct section
*sp
;
103 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
104 if(sp
== (struct section
*)0){
109 result
= (void *)sp
->addr
;
114 * This routine returns the a pointer to the data for the named segment
115 * if it exist in the mach header passed to it. Also it returns
116 * the size of the segment data indirectly through the pointer size.
117 * Otherwise it returns zero for the pointer and the size.
120 getsegdatafromheader(
121 struct mach_header
*mhp
,
125 const struct segment_command
*sc
;
128 sc
= getsegbynamefromheader(mhp
, segname
);
129 if(sc
== (struct segment_command
*)0){
134 result
= (void *)sc
->vmaddr
;
139 * This routine returns the section structure for the named section in the
140 * named segment for the mach_header pointer passed to it if it exist.
141 * Otherwise it returns zero.
144 getsectbynamefromheader(
145 struct mach_header
*mhp
,
149 struct segment_command
*sgp
;
153 sgp
= (struct segment_command
*)
154 ((char *)mhp
+ sizeof(struct mach_header
));
155 for(i
= 0; i
< mhp
->ncmds
; i
++){
156 if(sgp
->cmd
== LC_SEGMENT
)
157 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
158 mhp
->filetype
== MH_OBJECT
){
159 sp
= (struct section
*)((char *)sgp
+
160 sizeof(struct segment_command
));
161 for(j
= 0; j
< sgp
->nsects
; j
++){
162 if(strncmp(sp
->sectname
, sectname
,
163 sizeof(sp
->sectname
)) == 0 &&
164 strncmp(sp
->segname
, segname
,
165 sizeof(sp
->segname
)) == 0)
167 sp
= (struct section
*)((char *)sp
+
168 sizeof(struct section
));
171 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
173 return((struct section
*)0);
176 struct segment_command
*getsegbynamefromheader(
177 struct mach_header
*header
,
180 struct segment_command
*sgp
;
183 sgp
= (struct segment_command
*)
184 ((char *)header
+ sizeof(struct mach_header
));
185 for (i
= 0; i
< header
->ncmds
; i
++){
186 if ( sgp
->cmd
== LC_SEGMENT
187 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
189 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
191 return (struct segment_command
*)0;
196 * For now at least, all the rest of this seems unused.
197 * NOTE: The constant in here for segment alignment is machine-dependent,
198 * so if you include this, define a machine dependent constant for it's
202 struct segment_command seg
;
207 sizeof(fvm_data
), // cmdsize
213 VM_PROT_READ
, // maxprot
214 VM_PROT_READ
, // initprot,
231 struct segment_command
*fvm_seg
;
233 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
234 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
237 * Return the first segment_command in the header.
239 struct segment_command
*firstseg(void)
241 return firstsegfromheader(&_mh_execute_header
);
244 struct segment_command
*firstsegfromheader(struct mach_header
*header
)
246 struct segment_command
*sgp
;
249 sgp
= (struct segment_command
*)
250 ((char *)header
+ sizeof(struct mach_header
));
251 for (i
= 0; i
< header
->ncmds
; i
++){
252 if (sgp
->cmd
== LC_SEGMENT
)
254 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
256 return (struct segment_command
*)0;
259 struct segment_command
*nextseg(struct segment_command
*sgp
)
261 struct segment_command
*this;
263 this = nextsegfromheader(&_mh_execute_header
, sgp
);
266 * For the kernel's header add on the faked segment for the
267 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
269 if (!this && sgp
!= fvm_seg
)
275 struct segment_command
*nextsegfromheader(
276 struct mach_header
*header
,
277 struct segment_command
*seg
)
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
++) {
287 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
290 if (i
== header
->ncmds
)
291 return (struct segment_command
*)0;
293 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
294 for (; i
< header
->ncmds
; i
++) {
295 if (sgp
->cmd
== LC_SEGMENT
)
297 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
300 return (struct segment_command
*)0;
305 * Return the address of the named Mach-O segment, or NULL.
307 struct segment_command
*getsegbyname(char *seg_name
)
309 struct segment_command
*this;
311 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
314 * For the kernel's header add on the faked segment for the
315 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
317 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
324 * This routine returns the a pointer the section structure of the named
325 * section in the named segment if it exist in the mach executable it is
326 * linked into. Otherwise it returns zero.
333 return(getsectbynamefromheader(
334 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
337 struct section
*firstsect(struct segment_command
*sgp
)
341 if (!sgp
|| sgp
->nsects
== 0)
342 return (struct section
*)0;
344 return (struct section
*)(sgp
+1);
347 struct section
*nextsect(struct segment_command
*sgp
, struct section
*sp
)
349 struct section
*fsp
= firstsect(sgp
);
351 if (sp
- fsp
>= sgp
->nsects
-1)
352 return (struct section
*)0;
357 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
)
359 struct fvmfile_command
*fvp
;
362 fvp
= (struct fvmfile_command
*)
363 ((char *)header
+ sizeof(struct mach_header
));
364 for (i
= 0; i
< header
->ncmds
; i
++){
365 if (fvp
->cmd
== LC_FVMFILE
)
367 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
369 return (struct fvmfile_command
*)0;
373 * Create a fake USER seg if a fvmfile_command is present.
375 struct segment_command
*getfakefvmseg(void)
377 struct segment_command
*sgp
= getsegbyname("__USER");
378 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
385 return (struct segment_command
*)0;
387 fvm_seg
= &fvm_data
.seg
;
391 sgp
->vmaddr
= fvp
->header_addr
;
392 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
394 strcpy(sp
->sectname
, fvp
->name
.ptr
);
395 sp
->addr
= sgp
->vmaddr
;
396 sp
->size
= sgp
->vmsize
;
399 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
400 sp
->sectname
, sp
->addr
, sp
->size
);
405 * Figure out the size the size of the data associated with a
406 * loaded mach_header.
408 static vm_offset_t
getsizeofmacho(struct mach_header
*header
)
410 struct segment_command
*sgp
;
412 vm_offset_t last_addr
;
415 for ( sgp
= firstsegfromheader(header
)
417 ; sgp
= nextsegfromheader(header
, sgp
))
419 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
420 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
425 #endif /* !defined(KERNEL_PRELOAD) */