2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * File: kern/mach_header.c
31 * Functions for accessing mach-o headers.
33 * NOTE: This file supports only 32 bit mach headers at the present
34 * time; it's primary use is by kld, and all externally
35 * referenced routines at the present time operate against
36 * the 32 bit mach header _mh_execute_header, which is the
37 * header for the currently executing kernel. Adding support
38 * for 64 bit kernels is possible, but is not necessary at the
42 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
43 * Added getsegdatafromheader();
45 * 29-Jan-92 Mike DeMoney (mike@next.com)
46 * Made into machine independent form from machdep/m68k/mach_header.c.
47 * Ifdef'ed out most of this since I couldn't find any references.
50 #include <vm/vm_map.h>
51 #include <vm/vm_kern.h>
52 #include <mach-o/mach_header.h>
53 #include <string.h> // from libsa
57 extern struct mach_header _mh_execute_header
;
60 * return the last address (first avail)
62 * This routine operates against the currently executing kernel only
70 struct segment_command
*sgp
;
71 vm_offset_t last_addr
= 0;
72 struct mach_header
*header
= &_mh_execute_header
;
75 sgp
= (struct segment_command
*)
76 ((char *)header
+ sizeof(struct mach_header
));
77 for (i
= 0; i
< header
->ncmds
; i
++){
78 if ( sgp
->cmd
== LC_SEGMENT
) {
79 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
80 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
82 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
91 * This routine operates against the currently executing kernel only
96 struct mach_header
**tl
;
98 if (kmem_alloc(kernel_map
, (vm_offset_t
*) &tl
, 2*sizeof(struct mach_header
*)) != KERN_SUCCESS
)
101 tl
[0] = &_mh_execute_header
;
102 tl
[1] = (struct mach_header
*)0;
107 * This routine returns the a pointer to the data for the named section in the
108 * named segment if it exist in the mach header passed to it. Also it returns
109 * the size of the section data indirectly through the pointer size. Otherwise
110 * it returns zero for the pointer and the size.
112 * This routine can operate against any 32 bit mach header.
118 getsectdatafromheader(
119 struct mach_header
*mhp
,
121 const char *sectname
,
124 const struct section
*sp
;
127 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
128 if(sp
== (struct section
*)0){
133 result
= (void *)sp
->addr
;
138 * This routine returns the a pointer to the data for the named segment
139 * if it exist in the mach header passed to it. Also it returns
140 * the size of the segment data indirectly through the pointer size.
141 * Otherwise it returns zero for the pointer and the size.
147 getsegdatafromheader(
148 struct mach_header
*mhp
,
152 const struct segment_command
*sc
;
155 sc
= getsegbynamefromheader(mhp
, segname
);
156 if(sc
== (struct segment_command
*)0){
161 result
= (void *)sc
->vmaddr
;
166 * This routine returns the section structure for the named section in the
167 * named segment for the mach_header pointer passed to it if it exist.
168 * Otherwise it returns zero.
170 * This routine can operate against any 32 bit mach header.
176 getsectbynamefromheader(
177 struct mach_header
*mhp
,
179 const char *sectname
)
181 struct segment_command
*sgp
;
185 sgp
= (struct segment_command
*)
186 ((char *)mhp
+ sizeof(struct mach_header
));
187 for(i
= 0; i
< mhp
->ncmds
; i
++){
188 if(sgp
->cmd
== LC_SEGMENT
)
189 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
190 mhp
->filetype
== MH_OBJECT
){
191 sp
= (struct section
*)((char *)sgp
+
192 sizeof(struct segment_command
));
193 for(j
= 0; j
< sgp
->nsects
; j
++){
194 if(strncmp(sp
->sectname
, sectname
,
195 sizeof(sp
->sectname
)) == 0 &&
196 strncmp(sp
->segname
, segname
,
197 sizeof(sp
->segname
)) == 0)
199 sp
= (struct section
*)((char *)sp
+
200 sizeof(struct section
));
203 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
205 return((struct section
*)0);
212 * This routine can operate against any 32 bit mach header.
214 struct segment_command
*
215 getsegbynamefromheader(
216 struct mach_header
*header
,
217 const char *seg_name
)
219 struct segment_command
*sgp
;
222 sgp
= (struct segment_command
*)
223 ((char *)header
+ sizeof(struct mach_header
));
224 for (i
= 0; i
< header
->ncmds
; i
++){
225 if ( sgp
->cmd
== LC_SEGMENT
226 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
228 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
230 return (struct segment_command
*)0;
235 * For now at least, all the rest of this seems unused.
236 * NOTE: The constant in here for segment alignment is machine-dependent,
237 * so if you include this, define a machine dependent constant for it's
241 struct segment_command seg
;
246 sizeof(fvm_data
), // cmdsize
252 VM_PROT_READ
, // maxprot
253 VM_PROT_READ
, // initprot,
275 struct segment_command
*fvm_seg
;
277 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
278 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
281 * Return the first segment_command in the header.
286 struct segment_command
*
289 return firstsegfromheader(&_mh_execute_header
);
295 struct segment_command
*
296 firstsegfromheader(struct mach_header
*header
)
298 struct segment_command
*sgp
;
301 sgp
= (struct segment_command
*)
302 ((char *)header
+ sizeof(struct mach_header
));
303 for (i
= 0; i
< header
->ncmds
; i
++){
304 if (sgp
->cmd
== LC_SEGMENT
)
306 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
308 return (struct segment_command
*)0;
315 * This routine operates against a 32 bit mach segment_command structure
316 * pointer from the currently executing kernel only, to obtain the
317 * sequentially next segment_command structure in the currently executing
320 struct segment_command
*
321 nextseg(struct segment_command
*sgp
)
323 struct segment_command
*this;
325 this = nextsegfromheader(&_mh_execute_header
, sgp
);
328 * For the kernel's header add on the faked segment for the
329 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
331 if (!this && sgp
!= fvm_seg
)
341 * This routine operates against any 32 bit mach segment_command structure
342 * pointer and the provided 32 bit header, to obtain the sequentially next
343 * segment_command structure in that header.
345 struct segment_command
*
347 struct mach_header
*header
,
348 struct segment_command
*seg
)
350 struct segment_command
*sgp
;
353 sgp
= (struct segment_command
*)
354 ((char *)header
+ sizeof(struct mach_header
));
355 for (i
= 0; i
< header
->ncmds
; i
++) {
358 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
361 if (i
== header
->ncmds
)
362 return (struct segment_command
*)0;
364 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
365 for (; i
< header
->ncmds
; i
++) {
366 if (sgp
->cmd
== LC_SEGMENT
)
368 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
371 return (struct segment_command
*)0;
376 * Return the address of the named Mach-O segment from the currently
377 * executing 32 bit kernel, or NULL.
382 struct segment_command
*
383 getsegbyname(const char *seg_name
)
385 struct segment_command
*this;
387 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
390 * For the kernel's header add on the faked segment for the
391 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
393 if (!this && strncmp(seg_name
, fvm_seg
->segname
,
394 sizeof(fvm_seg
->segname
)) == 0)
401 * This routine returns the a pointer the section structure of the named
402 * section in the named segment if it exists in the currently executing
403 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
411 const char *sectname
)
413 return(getsectbynamefromheader(
414 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
421 * This routine can operate against any 32 bit segment_command structure to
422 * return the first 32 bit section immediately following that structure. If
423 * there are no sections associated with the segment_command structure, it
427 firstsect(struct segment_command
*sgp
)
429 if (!sgp
|| sgp
->nsects
== 0)
430 return (struct section
*)0;
432 return (struct section
*)(sgp
+1);
439 * This routine can operate against any 32 bit segment_command structure and
440 * 32 bit section to return the next consecutive 32 bit section immediately
441 * following the 32 bit section provided. If there are no sections following
442 * the provided section, it returns NULL.
445 nextsect(struct segment_command
*sgp
, struct section
*sp
)
447 struct section
*fsp
= firstsect(sgp
);
449 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
450 return (struct section
*)0;
456 * This routine can operate against any 32 bit mach header to return the
457 * first occurring 32 bit fvmfile_command section. If one is not present,
460 static struct fvmfile_command
*
461 fvmfilefromheader(struct mach_header
*header
)
463 struct fvmfile_command
*fvp
;
466 fvp
= (struct fvmfile_command
*)
467 ((char *)header
+ sizeof(struct mach_header
));
468 for (i
= 0; i
< header
->ncmds
; i
++){
469 if (fvp
->cmd
== LC_FVMFILE
)
471 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
473 return (struct fvmfile_command
*)0;
477 * Create a fake USER seg if a fvmfile_command is present.
479 * This routine operates against the currently executing kernel only
484 struct segment_command
*
487 struct segment_command
*sgp
= getsegbyname("__USER");
488 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
495 return (struct segment_command
*)0;
497 fvm_seg
= &fvm_data
.seg
;
501 sgp
->vmaddr
= fvp
->header_addr
;
502 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
504 strlcpy(sp
->sectname
, fvp
->name
.ptr
, sizeof(sp
->sectname
) /* 16 */);
505 sp
->addr
= sgp
->vmaddr
;
506 sp
->size
= sgp
->vmsize
;
509 printf("fake fvm seg __USER/\"%s\" at 0x%lx, size 0x%lx\n",
510 sp
->sectname
, sp
->addr
, sp
->size
);
516 * Figure out the size the size of the data associated with a
517 * loaded mach_header.
519 * This routine operates against the currently executing kernel only
522 getsizeofmacho(struct mach_header
*header
)
524 struct segment_command
*sgp
;
525 vm_offset_t last_addr
;
528 for ( sgp
= firstsegfromheader(header
)
530 ; sgp
= nextsegfromheader(header
, sgp
))
532 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
533 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
541 * This routine returns the section command for the symbol table in the
542 * named segment for the mach_header pointer passed to it if it exist.
543 * Otherwise it returns zero.
545 struct symtab_command
*
546 getsectcmdsymtabfromheader(
547 struct mach_header
*mhp
)
549 struct segment_command
*sgp
;
552 sgp
= (struct segment_command
*)
553 ((char *)mhp
+ sizeof(struct mach_header
));
554 for(i
= 0; i
< mhp
->ncmds
; i
++){
555 if(sgp
->cmd
== LC_SYMTAB
)
556 return((struct symtab_command
*)sgp
);
557 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
562 boolean_t
getsymtab(struct mach_header
*header
,
566 vm_size_t
*strtabsize
)
568 struct segment_command
*seglink_cmd
;
569 struct symtab_command
*symtab_cmd
;
573 if(header
->magic
!= MH_MAGIC
) { /* Check if this is a valid header format */
574 printf("Attempt to use invalid header (magic = %08lX) to find symbol table\n",
575 header
->magic
); /* Tell them what's wrong */
576 return (FALSE
); /* Bye y'all... */
579 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
580 if (seglink_cmd
== NULL
) {
585 symtab_cmd
= getsectcmdsymtabfromheader(header
);
586 if (symtab_cmd
== NULL
)
589 *nsyms
= symtab_cmd
->nsyms
;
590 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
592 *strtabsize
= symtab_cmd
->strsize
;
593 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
595 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
596 seglink_cmd
->fileoff
;
598 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
599 seglink_cmd
->fileoff
;
607 void * getsegdatafromheader( struct mach_header
*mhp
, char *segname
, int *size
)