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 #include <vm/vm_map.h>
37 #include <vm/vm_kern.h>
38 #include <mach-o/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)
58 vm_offset_t
getlastaddr(void)
60 struct segment_command
*sgp
;
61 vm_offset_t last_addr
= 0;
62 struct mach_header
*header
= &_mh_execute_header
;
65 sgp
= (struct segment_command
*)
66 ((char *)header
+ sizeof(struct mach_header
));
67 for (i
= 0; i
< header
->ncmds
; i
++){
68 if ( sgp
->cmd
== LC_SEGMENT
) {
69 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
70 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
72 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
83 extern struct mach_header _mh_execute_header
;
84 struct mach_header
**tl
;
86 if (kmem_alloc(kernel_map
, (vm_offset_t
*) &tl
, 2*sizeof(struct mach_header
*)) != KERN_SUCCESS
)
89 tl
[0] = &_mh_execute_header
;
90 tl
[1] = (struct mach_header
*)0;
95 * This routine returns the a pointer to the data for the named section in the
96 * named segment if it exist in the mach header passed to it. Also it returns
97 * the size of the section data indirectly through the pointer size. Otherwise
98 * it returns zero for the pointer and the size.
104 getsectdatafromheader(
105 struct mach_header
*mhp
,
110 const struct section
*sp
;
113 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
114 if(sp
== (struct section
*)0){
119 result
= (void *)sp
->addr
;
124 * This routine returns the a pointer to the data for the named segment
125 * if it exist in the mach header passed to it. Also it returns
126 * the size of the segment data indirectly through the pointer size.
127 * Otherwise it returns zero for the pointer and the size.
133 getsegdatafromheader(
134 struct mach_header
*mhp
,
138 const struct segment_command
*sc
;
141 sc
= getsegbynamefromheader(mhp
, segname
);
142 if(sc
== (struct segment_command
*)0){
147 result
= (void *)sc
->vmaddr
;
152 * This routine returns the section structure for the named section in the
153 * named segment for the mach_header pointer passed to it if it exist.
154 * Otherwise it returns zero.
160 getsectbynamefromheader(
161 struct mach_header
*mhp
,
165 struct segment_command
*sgp
;
169 sgp
= (struct segment_command
*)
170 ((char *)mhp
+ sizeof(struct mach_header
));
171 for(i
= 0; i
< mhp
->ncmds
; i
++){
172 if(sgp
->cmd
== LC_SEGMENT
)
173 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
174 mhp
->filetype
== MH_OBJECT
){
175 sp
= (struct section
*)((char *)sgp
+
176 sizeof(struct segment_command
));
177 for(j
= 0; j
< sgp
->nsects
; j
++){
178 if(strncmp(sp
->sectname
, sectname
,
179 sizeof(sp
->sectname
)) == 0 &&
180 strncmp(sp
->segname
, segname
,
181 sizeof(sp
->segname
)) == 0)
183 sp
= (struct section
*)((char *)sp
+
184 sizeof(struct section
));
187 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
189 return((struct section
*)0);
195 struct segment_command
*getsegbynamefromheader(
196 struct mach_header
*header
,
199 struct segment_command
*sgp
;
202 sgp
= (struct segment_command
*)
203 ((char *)header
+ sizeof(struct mach_header
));
204 for (i
= 0; i
< header
->ncmds
; i
++){
205 if ( sgp
->cmd
== LC_SEGMENT
206 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
208 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
210 return (struct segment_command
*)0;
215 * For now at least, all the rest of this seems unused.
216 * NOTE: The constant in here for segment alignment is machine-dependent,
217 * so if you include this, define a machine dependent constant for it's
221 struct segment_command seg
;
226 sizeof(fvm_data
), // cmdsize
232 VM_PROT_READ
, // maxprot
233 VM_PROT_READ
, // initprot,
253 struct segment_command
*fvm_seg
;
255 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
256 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
259 * Return the first segment_command in the header.
264 struct segment_command
*firstseg(void)
266 return firstsegfromheader(&_mh_execute_header
);
272 struct segment_command
*firstsegfromheader(struct mach_header
*header
)
274 struct segment_command
*sgp
;
277 sgp
= (struct segment_command
*)
278 ((char *)header
+ sizeof(struct mach_header
));
279 for (i
= 0; i
< header
->ncmds
; i
++){
280 if (sgp
->cmd
== LC_SEGMENT
)
282 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
284 return (struct segment_command
*)0;
290 struct segment_command
*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
)
309 struct segment_command
*nextsegfromheader(
310 struct mach_header
*header
,
311 struct segment_command
*seg
)
313 struct segment_command
*sgp
;
316 sgp
= (struct segment_command
*)
317 ((char *)header
+ sizeof(struct mach_header
));
318 for (i
= 0; i
< header
->ncmds
; i
++) {
321 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
324 if (i
== header
->ncmds
)
325 return (struct segment_command
*)0;
327 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
328 for (; i
< header
->ncmds
; i
++) {
329 if (sgp
->cmd
== LC_SEGMENT
)
331 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
334 return (struct segment_command
*)0;
339 * Return the address of the named Mach-O segment, or NULL.
344 struct segment_command
*getsegbyname(char *seg_name
)
346 struct segment_command
*this;
348 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
351 * For the kernel's header add on the faked segment for the
352 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
354 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
361 * This routine returns the a pointer the section structure of the named
362 * section in the named segment if it exist in the mach executable it is
363 * linked into. Otherwise it returns zero.
373 return(getsectbynamefromheader(
374 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
380 struct section
*firstsect(struct segment_command
*sgp
)
384 if (!sgp
|| sgp
->nsects
== 0)
385 return (struct section
*)0;
387 return (struct section
*)(sgp
+1);
393 struct section
*nextsect(struct segment_command
*sgp
, struct section
*sp
)
395 struct section
*fsp
= firstsect(sgp
);
397 if (sp
- fsp
>= sgp
->nsects
-1)
398 return (struct section
*)0;
403 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
)
405 struct fvmfile_command
*fvp
;
408 fvp
= (struct fvmfile_command
*)
409 ((char *)header
+ sizeof(struct mach_header
));
410 for (i
= 0; i
< header
->ncmds
; i
++){
411 if (fvp
->cmd
== LC_FVMFILE
)
413 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
415 return (struct fvmfile_command
*)0;
419 * Create a fake USER seg if a fvmfile_command is present.
424 struct segment_command
*getfakefvmseg(void)
426 struct segment_command
*sgp
= getsegbyname("__USER");
427 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
434 return (struct segment_command
*)0;
436 fvm_seg
= &fvm_data
.seg
;
440 sgp
->vmaddr
= fvp
->header_addr
;
441 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
443 strcpy(sp
->sectname
, fvp
->name
.ptr
);
444 sp
->addr
= sgp
->vmaddr
;
445 sp
->size
= sgp
->vmsize
;
448 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
449 sp
->sectname
, sp
->addr
, sp
->size
);
455 * Figure out the size the size of the data associated with a
456 * loaded mach_header.
458 static vm_offset_t
getsizeofmacho(struct mach_header
*header
)
460 struct segment_command
*sgp
;
462 vm_offset_t last_addr
;
465 for ( sgp
= firstsegfromheader(header
)
467 ; sgp
= nextsegfromheader(header
, sgp
))
469 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
470 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
478 * This routine returns the section command for the symbol table in the
479 * named segment for the mach_header pointer passed to it if it exist.
480 * Otherwise it returns zero.
482 struct symtab_command
*
483 getsectcmdsymtabfromheader(
484 struct mach_header
*mhp
)
486 struct segment_command
*sgp
;
490 sgp
= (struct segment_command
*)
491 ((char *)mhp
+ sizeof(struct mach_header
));
492 for(i
= 0; i
< mhp
->ncmds
; i
++){
493 if(sgp
->cmd
== LC_SYMTAB
)
494 return((struct symtab_command
*)sgp
);
495 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
500 boolean_t
getsymtab(struct mach_header
*header
,
504 vm_size_t
*strtabsize
)
506 struct segment_command
*seglink_cmd
;
507 struct symtab_command
*symtab_cmd
;
511 if(header
->magic
!= MH_MAGIC
) { /* Check if this is a valid header format */
512 printf("Attempt to use invalid header (magic = %08X) to find symbol table\n",
513 header
->magic
); /* Tell them what's wrong */
514 return (FALSE
); /* Bye y'all... */
517 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
518 if (seglink_cmd
== NULL
) {
523 symtab_cmd
= getsectcmdsymtabfromheader(header
);
524 if (symtab_cmd
== NULL
)
527 *nsyms
= symtab_cmd
->nsyms
;
528 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
530 *strtabsize
= symtab_cmd
->strsize
;
531 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
533 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
534 seglink_cmd
->fileoff
;
536 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
537 seglink_cmd
->fileoff
;
545 void * getsegdatafromheader( struct mach_header
*mhp
, char *segname
, int *size
)