2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * File: kern/mach_header.c
33 * Functions for accessing mach-o headers.
35 * NOTE: This file supports only 32 bit mach headers at the present
36 * time; it's primary use is by kld, and all externally
37 * referenced routines at the present time operate against
38 * the 32 bit mach header _mh_execute_header, which is the
39 * header for the currently executing kernel. Adding support
40 * for 64 bit kernels is possible, but is not necessary at the
44 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
45 * Added getsegdatafromheader();
47 * 29-Jan-92 Mike DeMoney (mike@next.com)
48 * Made into machine independent form from machdep/m68k/mach_header.c.
49 * Ifdef'ed out most of this since I couldn't find any references.
52 #include <vm/vm_map.h>
53 #include <vm/vm_kern.h>
54 #include <mach-o/mach_header.h>
55 #include <string.h> // from libsa
59 extern struct mach_header _mh_execute_header
;
62 * return the last address (first avail)
64 * This routine operates against the currently executing kernel only
72 struct segment_command
*sgp
;
73 vm_offset_t last_addr
= 0;
74 struct mach_header
*header
= &_mh_execute_header
;
77 sgp
= (struct segment_command
*)
78 ((char *)header
+ sizeof(struct mach_header
));
79 for (i
= 0; i
< header
->ncmds
; i
++){
80 if ( sgp
->cmd
== LC_SEGMENT
) {
81 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
82 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
84 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
93 * This routine operates against the currently executing kernel only
98 struct mach_header
**tl
;
100 if (kmem_alloc(kernel_map
, (vm_offset_t
*) &tl
, 2*sizeof(struct mach_header
*)) != KERN_SUCCESS
)
103 tl
[0] = &_mh_execute_header
;
104 tl
[1] = (struct mach_header
*)0;
109 * This routine returns the a pointer to the data for the named section in the
110 * named segment if it exist in the mach header passed to it. Also it returns
111 * the size of the section data indirectly through the pointer size. Otherwise
112 * it returns zero for the pointer and the size.
114 * This routine can operate against any 32 bit mach header.
120 getsectdatafromheader(
121 struct mach_header
*mhp
,
123 const char *sectname
,
126 const struct section
*sp
;
129 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
130 if(sp
== (struct section
*)0){
135 result
= (void *)sp
->addr
;
140 * This routine returns the a pointer to the data for the named segment
141 * if it exist in the mach header passed to it. Also it returns
142 * the size of the segment data indirectly through the pointer size.
143 * Otherwise it returns zero for the pointer and the size.
149 getsegdatafromheader(
150 struct mach_header
*mhp
,
154 const struct segment_command
*sc
;
157 sc
= getsegbynamefromheader(mhp
, segname
);
158 if(sc
== (struct segment_command
*)0){
163 result
= (void *)sc
->vmaddr
;
168 * This routine returns the section structure for the named section in the
169 * named segment for the mach_header pointer passed to it if it exist.
170 * Otherwise it returns zero.
172 * This routine can operate against any 32 bit mach header.
178 getsectbynamefromheader(
179 struct mach_header
*mhp
,
181 const char *sectname
)
183 struct segment_command
*sgp
;
187 sgp
= (struct segment_command
*)
188 ((char *)mhp
+ sizeof(struct mach_header
));
189 for(i
= 0; i
< mhp
->ncmds
; i
++){
190 if(sgp
->cmd
== LC_SEGMENT
)
191 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
192 mhp
->filetype
== MH_OBJECT
){
193 sp
= (struct section
*)((char *)sgp
+
194 sizeof(struct segment_command
));
195 for(j
= 0; j
< sgp
->nsects
; j
++){
196 if(strncmp(sp
->sectname
, sectname
,
197 sizeof(sp
->sectname
)) == 0 &&
198 strncmp(sp
->segname
, segname
,
199 sizeof(sp
->segname
)) == 0)
201 sp
= (struct section
*)((char *)sp
+
202 sizeof(struct section
));
205 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
207 return((struct section
*)0);
214 * This routine can operate against any 32 bit mach header.
216 struct segment_command
*
217 getsegbynamefromheader(
218 struct mach_header
*header
,
219 const char *seg_name
)
221 struct segment_command
*sgp
;
224 sgp
= (struct segment_command
*)
225 ((char *)header
+ sizeof(struct mach_header
));
226 for (i
= 0; i
< header
->ncmds
; i
++){
227 if ( sgp
->cmd
== LC_SEGMENT
228 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
230 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
232 return (struct segment_command
*)0;
237 * For now at least, all the rest of this seems unused.
238 * NOTE: The constant in here for segment alignment is machine-dependent,
239 * so if you include this, define a machine dependent constant for it's
243 struct segment_command seg
;
248 sizeof(fvm_data
), // cmdsize
254 VM_PROT_READ
, // maxprot
255 VM_PROT_READ
, // initprot,
277 struct segment_command
*fvm_seg
;
279 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
280 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
283 * Return the first segment_command in the header.
288 struct segment_command
*
291 return firstsegfromheader(&_mh_execute_header
);
297 struct segment_command
*
298 firstsegfromheader(struct mach_header
*header
)
300 struct segment_command
*sgp
;
303 sgp
= (struct segment_command
*)
304 ((char *)header
+ sizeof(struct mach_header
));
305 for (i
= 0; i
< header
->ncmds
; i
++){
306 if (sgp
->cmd
== LC_SEGMENT
)
308 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
310 return (struct segment_command
*)0;
317 * This routine operates against a 32 bit mach segment_command structure
318 * pointer from the currently executing kernel only, to obtain the
319 * sequentially next segment_command structure in the currently executing
322 struct segment_command
*
323 nextseg(struct segment_command
*sgp
)
325 struct segment_command
*this;
327 this = nextsegfromheader(&_mh_execute_header
, sgp
);
330 * For the kernel's header add on the faked segment for the
331 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
333 if (!this && sgp
!= fvm_seg
)
343 * This routine operates against any 32 bit mach segment_command structure
344 * pointer and the provided 32 bit header, to obtain the sequentially next
345 * segment_command structure in that header.
347 struct segment_command
*
349 struct mach_header
*header
,
350 struct segment_command
*seg
)
352 struct segment_command
*sgp
;
355 sgp
= (struct segment_command
*)
356 ((char *)header
+ sizeof(struct mach_header
));
357 for (i
= 0; i
< header
->ncmds
; i
++) {
360 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
363 if (i
== header
->ncmds
)
364 return (struct segment_command
*)0;
366 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
367 for (; i
< header
->ncmds
; i
++) {
368 if (sgp
->cmd
== LC_SEGMENT
)
370 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
373 return (struct segment_command
*)0;
378 * Return the address of the named Mach-O segment from the currently
379 * executing 32 bit kernel, or NULL.
384 struct segment_command
*
385 getsegbyname(const char *seg_name
)
387 struct segment_command
*this;
389 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
392 * For the kernel's header add on the faked segment for the
393 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
395 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
402 * This routine returns the a pointer the section structure of the named
403 * section in the named segment if it exists in the currently executing
404 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
412 const char *sectname
)
414 return(getsectbynamefromheader(
415 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
422 * This routine can operate against any 32 bit segment_command structure to
423 * return the first 32 bit section immediately following that structure. If
424 * there are no sections associated with the segment_command structure, it
428 firstsect(struct segment_command
*sgp
)
430 if (!sgp
|| sgp
->nsects
== 0)
431 return (struct section
*)0;
433 return (struct section
*)(sgp
+1);
440 * This routine can operate against any 32 bit segment_command structure and
441 * 32 bit section to return the next consecutive 32 bit section immediately
442 * following the 32 bit section provided. If there are no sections following
443 * the provided section, it returns NULL.
446 nextsect(struct segment_command
*sgp
, struct section
*sp
)
448 struct section
*fsp
= firstsect(sgp
);
450 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
451 return (struct section
*)0;
457 * This routine can operate against any 32 bit mach header to return the
458 * first occurring 32 bit fvmfile_command section. If one is not present,
461 static struct fvmfile_command
*
462 fvmfilefromheader(struct mach_header
*header
)
464 struct fvmfile_command
*fvp
;
467 fvp
= (struct fvmfile_command
*)
468 ((char *)header
+ sizeof(struct mach_header
));
469 for (i
= 0; i
< header
->ncmds
; i
++){
470 if (fvp
->cmd
== LC_FVMFILE
)
472 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
474 return (struct fvmfile_command
*)0;
478 * Create a fake USER seg if a fvmfile_command is present.
480 * This routine operates against the currently executing kernel only
485 struct segment_command
*
488 struct segment_command
*sgp
= getsegbyname("__USER");
489 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
496 return (struct segment_command
*)0;
498 fvm_seg
= &fvm_data
.seg
;
502 sgp
->vmaddr
= fvp
->header_addr
;
503 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
505 strcpy(sp
->sectname
, fvp
->name
.ptr
);
506 sp
->addr
= sgp
->vmaddr
;
507 sp
->size
= sgp
->vmsize
;
510 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
511 sp
->sectname
, sp
->addr
, sp
->size
);
517 * Figure out the size the size of the data associated with a
518 * loaded mach_header.
520 * This routine operates against the currently executing kernel only
523 getsizeofmacho(struct mach_header
*header
)
525 struct segment_command
*sgp
;
526 vm_offset_t last_addr
;
529 for ( sgp
= firstsegfromheader(header
)
531 ; sgp
= nextsegfromheader(header
, sgp
))
533 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
534 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
542 * This routine returns the section command for the symbol table in the
543 * named segment for the mach_header pointer passed to it if it exist.
544 * Otherwise it returns zero.
546 struct symtab_command
*
547 getsectcmdsymtabfromheader(
548 struct mach_header
*mhp
)
550 struct segment_command
*sgp
;
553 sgp
= (struct segment_command
*)
554 ((char *)mhp
+ sizeof(struct mach_header
));
555 for(i
= 0; i
< mhp
->ncmds
; i
++){
556 if(sgp
->cmd
== LC_SYMTAB
)
557 return((struct symtab_command
*)sgp
);
558 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
563 boolean_t
getsymtab(struct mach_header
*header
,
567 vm_size_t
*strtabsize
)
569 struct segment_command
*seglink_cmd
;
570 struct symtab_command
*symtab_cmd
;
574 if(header
->magic
!= MH_MAGIC
) { /* Check if this is a valid header format */
575 printf("Attempt to use invalid header (magic = %08X) to find symbol table\n",
576 header
->magic
); /* Tell them what's wrong */
577 return (FALSE
); /* Bye y'all... */
580 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
581 if (seglink_cmd
== NULL
) {
586 symtab_cmd
= getsectcmdsymtabfromheader(header
);
587 if (symtab_cmd
== NULL
)
590 *nsyms
= symtab_cmd
->nsyms
;
591 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
593 *strtabsize
= symtab_cmd
->strsize
;
594 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
596 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
597 seglink_cmd
->fileoff
;
599 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
600 seglink_cmd
->fileoff
;
608 void * getsegdatafromheader( struct mach_header
*mhp
, char *segname
, int *size
)