2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * File: kern/mach_header.c
26 * Functions for accessing mach-o headers.
28 * NOTE: This file supports only 32 bit mach headers at the present
29 * time; it's primary use is by kld, and all externally
30 * referenced routines at the present time operate against
31 * the 32 bit mach header _mh_execute_header, which is the
32 * header for the currently executing kernel. Adding support
33 * for 64 bit kernels is possible, but is not necessary at the
37 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
38 * Added getsegdatafromheader();
40 * 29-Jan-92 Mike DeMoney (mike@next.com)
41 * Made into machine independent form from machdep/m68k/mach_header.c.
42 * Ifdef'ed out most of this since I couldn't find any references.
45 #include <vm/vm_map.h>
46 #include <vm/vm_kern.h>
47 #include <mach-o/mach_header.h>
48 #include <string.h> // from libsa
52 extern struct mach_header _mh_execute_header
;
55 * return the last address (first avail)
57 * This routine operates against the currently executing kernel only
65 struct segment_command
*sgp
;
66 vm_offset_t last_addr
= 0;
67 struct mach_header
*header
= &_mh_execute_header
;
70 sgp
= (struct segment_command
*)
71 ((char *)header
+ sizeof(struct mach_header
));
72 for (i
= 0; i
< header
->ncmds
; i
++){
73 if ( sgp
->cmd
== LC_SEGMENT
) {
74 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
75 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
77 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
86 * This routine operates against the currently executing kernel only
91 struct mach_header
**tl
;
93 if (kmem_alloc(kernel_map
, (vm_offset_t
*) &tl
, 2*sizeof(struct mach_header
*)) != KERN_SUCCESS
)
96 tl
[0] = &_mh_execute_header
;
97 tl
[1] = (struct mach_header
*)0;
102 * This routine returns the a pointer to the data for the named section in the
103 * named segment if it exist in the mach header passed to it. Also it returns
104 * the size of the section data indirectly through the pointer size. Otherwise
105 * it returns zero for the pointer and the size.
107 * This routine can operate against any 32 bit mach header.
113 getsectdatafromheader(
114 struct mach_header
*mhp
,
116 const char *sectname
,
119 const struct section
*sp
;
122 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
123 if(sp
== (struct section
*)0){
128 result
= (void *)sp
->addr
;
133 * This routine returns the a pointer to the data for the named segment
134 * if it exist in the mach header passed to it. Also it returns
135 * the size of the segment data indirectly through the pointer size.
136 * Otherwise it returns zero for the pointer and the size.
142 getsegdatafromheader(
143 struct mach_header
*mhp
,
147 const struct segment_command
*sc
;
150 sc
= getsegbynamefromheader(mhp
, segname
);
151 if(sc
== (struct segment_command
*)0){
156 result
= (void *)sc
->vmaddr
;
161 * This routine returns the section structure for the named section in the
162 * named segment for the mach_header pointer passed to it if it exist.
163 * Otherwise it returns zero.
165 * This routine can operate against any 32 bit mach header.
171 getsectbynamefromheader(
172 struct mach_header
*mhp
,
174 const char *sectname
)
176 struct segment_command
*sgp
;
180 sgp
= (struct segment_command
*)
181 ((char *)mhp
+ sizeof(struct mach_header
));
182 for(i
= 0; i
< mhp
->ncmds
; i
++){
183 if(sgp
->cmd
== LC_SEGMENT
)
184 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
185 mhp
->filetype
== MH_OBJECT
){
186 sp
= (struct section
*)((char *)sgp
+
187 sizeof(struct segment_command
));
188 for(j
= 0; j
< sgp
->nsects
; j
++){
189 if(strncmp(sp
->sectname
, sectname
,
190 sizeof(sp
->sectname
)) == 0 &&
191 strncmp(sp
->segname
, segname
,
192 sizeof(sp
->segname
)) == 0)
194 sp
= (struct section
*)((char *)sp
+
195 sizeof(struct section
));
198 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
200 return((struct section
*)0);
207 * This routine can operate against any 32 bit mach header.
209 struct segment_command
*
210 getsegbynamefromheader(
211 struct mach_header
*header
,
212 const char *seg_name
)
214 struct segment_command
*sgp
;
217 sgp
= (struct segment_command
*)
218 ((char *)header
+ sizeof(struct mach_header
));
219 for (i
= 0; i
< header
->ncmds
; i
++){
220 if ( sgp
->cmd
== LC_SEGMENT
221 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
223 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
225 return (struct segment_command
*)0;
230 * For now at least, all the rest of this seems unused.
231 * NOTE: The constant in here for segment alignment is machine-dependent,
232 * so if you include this, define a machine dependent constant for it's
236 struct segment_command seg
;
241 sizeof(fvm_data
), // cmdsize
247 VM_PROT_READ
, // maxprot
248 VM_PROT_READ
, // initprot,
270 struct segment_command
*fvm_seg
;
272 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
273 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
276 * Return the first segment_command in the header.
281 struct segment_command
*
284 return firstsegfromheader(&_mh_execute_header
);
290 struct segment_command
*
291 firstsegfromheader(struct mach_header
*header
)
293 struct segment_command
*sgp
;
296 sgp
= (struct segment_command
*)
297 ((char *)header
+ sizeof(struct mach_header
));
298 for (i
= 0; i
< header
->ncmds
; i
++){
299 if (sgp
->cmd
== LC_SEGMENT
)
301 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
303 return (struct segment_command
*)0;
310 * This routine operates against a 32 bit mach segment_command structure
311 * pointer from the currently executing kernel only, to obtain the
312 * sequentially next segment_command structure in the currently executing
315 struct segment_command
*
316 nextseg(struct segment_command
*sgp
)
318 struct segment_command
*this;
320 this = nextsegfromheader(&_mh_execute_header
, sgp
);
323 * For the kernel's header add on the faked segment for the
324 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
326 if (!this && sgp
!= fvm_seg
)
336 * This routine operates against any 32 bit mach segment_command structure
337 * pointer and the provided 32 bit header, to obtain the sequentially next
338 * segment_command structure in that header.
340 struct segment_command
*
342 struct mach_header
*header
,
343 struct segment_command
*seg
)
345 struct segment_command
*sgp
;
348 sgp
= (struct segment_command
*)
349 ((char *)header
+ sizeof(struct mach_header
));
350 for (i
= 0; i
< header
->ncmds
; i
++) {
353 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
356 if (i
== header
->ncmds
)
357 return (struct segment_command
*)0;
359 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
360 for (; i
< header
->ncmds
; i
++) {
361 if (sgp
->cmd
== LC_SEGMENT
)
363 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
366 return (struct segment_command
*)0;
371 * Return the address of the named Mach-O segment from the currently
372 * executing 32 bit kernel, or NULL.
377 struct segment_command
*
378 getsegbyname(const char *seg_name
)
380 struct segment_command
*this;
382 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
385 * For the kernel's header add on the faked segment for the
386 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
388 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
395 * This routine returns the a pointer the section structure of the named
396 * section in the named segment if it exists in the currently executing
397 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
405 const char *sectname
)
407 return(getsectbynamefromheader(
408 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
415 * This routine can operate against any 32 bit segment_command structure to
416 * return the first 32 bit section immediately following that structure. If
417 * there are no sections associated with the segment_command structure, it
421 firstsect(struct segment_command
*sgp
)
423 if (!sgp
|| sgp
->nsects
== 0)
424 return (struct section
*)0;
426 return (struct section
*)(sgp
+1);
433 * This routine can operate against any 32 bit segment_command structure and
434 * 32 bit section to return the next consecutive 32 bit section immediately
435 * following the 32 bit section provided. If there are no sections following
436 * the provided section, it returns NULL.
439 nextsect(struct segment_command
*sgp
, struct section
*sp
)
441 struct section
*fsp
= firstsect(sgp
);
443 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
444 return (struct section
*)0;
450 * This routine can operate against any 32 bit mach header to return the
451 * first occurring 32 bit fvmfile_command section. If one is not present,
454 static struct fvmfile_command
*
455 fvmfilefromheader(struct mach_header
*header
)
457 struct fvmfile_command
*fvp
;
460 fvp
= (struct fvmfile_command
*)
461 ((char *)header
+ sizeof(struct mach_header
));
462 for (i
= 0; i
< header
->ncmds
; i
++){
463 if (fvp
->cmd
== LC_FVMFILE
)
465 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
467 return (struct fvmfile_command
*)0;
471 * Create a fake USER seg if a fvmfile_command is present.
473 * This routine operates against the currently executing kernel only
478 struct segment_command
*
481 struct segment_command
*sgp
= getsegbyname("__USER");
482 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
489 return (struct segment_command
*)0;
491 fvm_seg
= &fvm_data
.seg
;
495 sgp
->vmaddr
= fvp
->header_addr
;
496 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
498 strcpy(sp
->sectname
, fvp
->name
.ptr
);
499 sp
->addr
= sgp
->vmaddr
;
500 sp
->size
= sgp
->vmsize
;
503 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
504 sp
->sectname
, sp
->addr
, sp
->size
);
510 * Figure out the size the size of the data associated with a
511 * loaded mach_header.
513 * This routine operates against the currently executing kernel only
516 getsizeofmacho(struct mach_header
*header
)
518 struct segment_command
*sgp
;
519 vm_offset_t last_addr
;
522 for ( sgp
= firstsegfromheader(header
)
524 ; sgp
= nextsegfromheader(header
, sgp
))
526 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
527 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
535 * This routine returns the section command for the symbol table in the
536 * named segment for the mach_header pointer passed to it if it exist.
537 * Otherwise it returns zero.
539 struct symtab_command
*
540 getsectcmdsymtabfromheader(
541 struct mach_header
*mhp
)
543 struct segment_command
*sgp
;
546 sgp
= (struct segment_command
*)
547 ((char *)mhp
+ sizeof(struct mach_header
));
548 for(i
= 0; i
< mhp
->ncmds
; i
++){
549 if(sgp
->cmd
== LC_SYMTAB
)
550 return((struct symtab_command
*)sgp
);
551 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
556 boolean_t
getsymtab(struct mach_header
*header
,
560 vm_size_t
*strtabsize
)
562 struct segment_command
*seglink_cmd
;
563 struct symtab_command
*symtab_cmd
;
567 if(header
->magic
!= MH_MAGIC
) { /* Check if this is a valid header format */
568 printf("Attempt to use invalid header (magic = %08X) to find symbol table\n",
569 header
->magic
); /* Tell them what's wrong */
570 return (FALSE
); /* Bye y'all... */
573 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
574 if (seglink_cmd
== NULL
) {
579 symtab_cmd
= getsectcmdsymtabfromheader(header
);
580 if (symtab_cmd
== NULL
)
583 *nsyms
= symtab_cmd
->nsyms
;
584 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
586 *strtabsize
= symtab_cmd
->strsize
;
587 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
589 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
590 seglink_cmd
->fileoff
;
592 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
593 seglink_cmd
->fileoff
;
601 void * getsegdatafromheader( struct mach_header
*mhp
, char *segname
, int *size
)