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 #include <vm/vm_map.h>
40 #include <vm/vm_kern.h>
41 #include <mach-o/mach_header.h>
45 extern struct mach_header _mh_execute_header
;
47 struct section
*getsectbynamefromheader(
48 struct mach_header
*header
,
51 struct segment_command
*getsegbynamefromheader(
52 struct mach_header
*header
,
56 * return the last address (first avail)
61 vm_offset_t
getlastaddr(void)
63 struct segment_command
*sgp
;
64 vm_offset_t last_addr
= 0;
65 struct mach_header
*header
= &_mh_execute_header
;
68 sgp
= (struct segment_command
*)
69 ((char *)header
+ sizeof(struct mach_header
));
70 for (i
= 0; i
< header
->ncmds
; i
++){
71 if ( sgp
->cmd
== LC_SEGMENT
) {
72 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
73 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
75 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
86 extern struct mach_header _mh_execute_header
;
87 struct mach_header
**tl
;
89 if (kmem_alloc(kernel_map
, (vm_offset_t
*) &tl
, 2*sizeof(struct mach_header
*)) != KERN_SUCCESS
)
92 tl
[0] = &_mh_execute_header
;
93 tl
[1] = (struct mach_header
*)0;
98 * This routine returns the a pointer to the data for the named section in the
99 * named segment if it exist in the mach header passed to it. Also it returns
100 * the size of the section data indirectly through the pointer size. Otherwise
101 * it returns zero for the pointer and the size.
107 getsectdatafromheader(
108 struct mach_header
*mhp
,
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.
136 getsegdatafromheader(
137 struct mach_header
*mhp
,
141 const struct segment_command
*sc
;
144 sc
= getsegbynamefromheader(mhp
, segname
);
145 if(sc
== (struct segment_command
*)0){
150 result
= (void *)sc
->vmaddr
;
155 * This routine returns the section structure for the named section in the
156 * named segment for the mach_header pointer passed to it if it exist.
157 * Otherwise it returns zero.
163 getsectbynamefromheader(
164 struct mach_header
*mhp
,
168 struct segment_command
*sgp
;
172 sgp
= (struct segment_command
*)
173 ((char *)mhp
+ sizeof(struct mach_header
));
174 for(i
= 0; i
< mhp
->ncmds
; i
++){
175 if(sgp
->cmd
== LC_SEGMENT
)
176 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
177 mhp
->filetype
== MH_OBJECT
){
178 sp
= (struct section
*)((char *)sgp
+
179 sizeof(struct segment_command
));
180 for(j
= 0; j
< sgp
->nsects
; j
++){
181 if(strncmp(sp
->sectname
, sectname
,
182 sizeof(sp
->sectname
)) == 0 &&
183 strncmp(sp
->segname
, segname
,
184 sizeof(sp
->segname
)) == 0)
186 sp
= (struct section
*)((char *)sp
+
187 sizeof(struct section
));
190 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
192 return((struct section
*)0);
198 struct segment_command
*getsegbynamefromheader(
199 struct mach_header
*header
,
202 struct segment_command
*sgp
;
205 sgp
= (struct segment_command
*)
206 ((char *)header
+ sizeof(struct mach_header
));
207 for (i
= 0; i
< header
->ncmds
; i
++){
208 if ( sgp
->cmd
== LC_SEGMENT
209 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
211 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
213 return (struct segment_command
*)0;
218 * For now at least, all the rest of this seems unused.
219 * NOTE: The constant in here for segment alignment is machine-dependent,
220 * so if you include this, define a machine dependent constant for it's
224 struct segment_command seg
;
229 sizeof(fvm_data
), // cmdsize
235 VM_PROT_READ
, // maxprot
236 VM_PROT_READ
, // initprot,
256 struct segment_command
*fvm_seg
;
258 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
259 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
262 * Return the first segment_command in the header.
267 struct segment_command
*firstseg(void)
269 return firstsegfromheader(&_mh_execute_header
);
275 struct segment_command
*firstsegfromheader(struct mach_header
*header
)
277 struct segment_command
*sgp
;
280 sgp
= (struct segment_command
*)
281 ((char *)header
+ sizeof(struct mach_header
));
282 for (i
= 0; i
< header
->ncmds
; i
++){
283 if (sgp
->cmd
== LC_SEGMENT
)
285 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
287 return (struct segment_command
*)0;
293 struct segment_command
*nextseg(struct segment_command
*sgp
)
295 struct segment_command
*this;
297 this = nextsegfromheader(&_mh_execute_header
, sgp
);
300 * For the kernel's header add on the faked segment for the
301 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
303 if (!this && sgp
!= fvm_seg
)
312 struct segment_command
*nextsegfromheader(
313 struct mach_header
*header
,
314 struct segment_command
*seg
)
316 struct segment_command
*sgp
;
319 sgp
= (struct segment_command
*)
320 ((char *)header
+ sizeof(struct mach_header
));
321 for (i
= 0; i
< header
->ncmds
; i
++) {
324 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
327 if (i
== header
->ncmds
)
328 return (struct segment_command
*)0;
330 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
331 for (; i
< header
->ncmds
; i
++) {
332 if (sgp
->cmd
== LC_SEGMENT
)
334 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
337 return (struct segment_command
*)0;
342 * Return the address of the named Mach-O segment, or NULL.
347 struct segment_command
*getsegbyname(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 exist in the mach executable it is
366 * linked into. Otherwise it returns zero.
376 return(getsectbynamefromheader(
377 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
383 struct section
*firstsect(struct segment_command
*sgp
)
387 if (!sgp
|| sgp
->nsects
== 0)
388 return (struct section
*)0;
390 return (struct section
*)(sgp
+1);
396 struct section
*nextsect(struct segment_command
*sgp
, struct section
*sp
)
398 struct section
*fsp
= firstsect(sgp
);
400 if (sp
- fsp
>= sgp
->nsects
-1)
401 return (struct section
*)0;
406 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
)
408 struct fvmfile_command
*fvp
;
411 fvp
= (struct fvmfile_command
*)
412 ((char *)header
+ sizeof(struct mach_header
));
413 for (i
= 0; i
< header
->ncmds
; i
++){
414 if (fvp
->cmd
== LC_FVMFILE
)
416 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
418 return (struct fvmfile_command
*)0;
422 * Create a fake USER seg if a fvmfile_command is present.
427 struct segment_command
*getfakefvmseg(void)
429 struct segment_command
*sgp
= getsegbyname("__USER");
430 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
437 return (struct segment_command
*)0;
439 fvm_seg
= &fvm_data
.seg
;
443 sgp
->vmaddr
= fvp
->header_addr
;
444 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
446 strcpy(sp
->sectname
, fvp
->name
.ptr
);
447 sp
->addr
= sgp
->vmaddr
;
448 sp
->size
= sgp
->vmsize
;
451 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
452 sp
->sectname
, sp
->addr
, sp
->size
);
458 * Figure out the size the size of the data associated with a
459 * loaded mach_header.
461 static vm_offset_t
getsizeofmacho(struct mach_header
*header
)
463 struct segment_command
*sgp
;
465 vm_offset_t last_addr
;
468 for ( sgp
= firstsegfromheader(header
)
470 ; sgp
= nextsegfromheader(header
, sgp
))
472 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
473 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
481 * This routine returns the section command for the symbol table in the
482 * named segment for the mach_header pointer passed to it if it exist.
483 * Otherwise it returns zero.
485 struct symtab_command
*
486 getsectcmdsymtabfromheader(
487 struct mach_header
*mhp
)
489 struct segment_command
*sgp
;
493 sgp
= (struct segment_command
*)
494 ((char *)mhp
+ sizeof(struct mach_header
));
495 for(i
= 0; i
< mhp
->ncmds
; i
++){
496 if(sgp
->cmd
== LC_SYMTAB
)
497 return((struct symtab_command
*)sgp
);
498 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
503 boolean_t
getsymtab(struct mach_header
*header
,
507 vm_size_t
*strtabsize
)
509 struct segment_command
*seglink_cmd
;
510 struct symtab_command
*symtab_cmd
;
514 if(header
->magic
!= MH_MAGIC
) { /* Check if this is a valid header format */
515 printf("Attempt to use invalid header (magic = %08X) to find symbol table\n",
516 header
->magic
); /* Tell them what's wrong */
517 return (FALSE
); /* Bye y'all... */
520 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
521 if (seglink_cmd
== NULL
) {
526 symtab_cmd
= getsectcmdsymtabfromheader(header
);
527 if (symtab_cmd
== NULL
)
530 *nsyms
= symtab_cmd
->nsyms
;
531 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
533 *strtabsize
= symtab_cmd
->strsize
;
534 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
536 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
537 seglink_cmd
->fileoff
;
539 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
540 seglink_cmd
->fileoff
;
548 void * getsegdatafromheader( struct mach_header
*mhp
, char *segname
, int *size
)