2 * Copyright (c) 2000-2004 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.
27 * NOTE: This file supports only 32 bit mach headers at the present
28 * time; it's primary use is by kld, and all externally
29 * referenced routines at the present time operate against
30 * the 32 bit mach header _mh_execute_header, which is the
31 * header for the currently executing kernel. Adding support
32 * for 64 bit kernels is possible, but is not necessary at the
36 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
37 * Added getsegdatafromheader();
39 * 29-Jan-92 Mike DeMoney (mike@next.com)
40 * Made into machine independent form from machdep/m68k/mach_header.c.
41 * Ifdef'ed out most of this since I couldn't find any references.
44 #include <vm/vm_map.h>
45 #include <vm/vm_kern.h>
46 #include <mach-o/mach_header.h>
47 #include <string.h> // from libsa
51 extern struct mach_header _mh_execute_header
;
54 * return the last address (first avail)
56 * This routine operates against the currently executing kernel only
64 struct segment_command
*sgp
;
65 vm_offset_t last_addr
= 0;
66 struct mach_header
*header
= &_mh_execute_header
;
69 sgp
= (struct segment_command
*)
70 ((char *)header
+ sizeof(struct mach_header
));
71 for (i
= 0; i
< header
->ncmds
; i
++){
72 if ( sgp
->cmd
== LC_SEGMENT
) {
73 if (sgp
->vmaddr
+ sgp
->vmsize
> last_addr
)
74 last_addr
= sgp
->vmaddr
+ sgp
->vmsize
;
76 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
85 * This routine operates against the currently executing kernel only
90 struct mach_header
**tl
;
92 if (kmem_alloc(kernel_map
, (vm_offset_t
*) &tl
, 2*sizeof(struct mach_header
*)) != KERN_SUCCESS
)
95 tl
[0] = &_mh_execute_header
;
96 tl
[1] = (struct mach_header
*)0;
101 * This routine returns the a pointer to the data for the named section in the
102 * named segment if it exist in the mach header passed to it. Also it returns
103 * the size of the section data indirectly through the pointer size. Otherwise
104 * it returns zero for the pointer and the size.
106 * This routine can operate against any 32 bit mach header.
112 getsectdatafromheader(
113 struct mach_header
*mhp
,
115 const char *sectname
,
118 const struct section
*sp
;
121 sp
= getsectbynamefromheader(mhp
, segname
, sectname
);
122 if(sp
== (struct section
*)0){
127 result
= (void *)sp
->addr
;
132 * This routine returns the a pointer to the data for the named segment
133 * if it exist in the mach header passed to it. Also it returns
134 * the size of the segment data indirectly through the pointer size.
135 * Otherwise it returns zero for the pointer and the size.
141 getsegdatafromheader(
142 struct mach_header
*mhp
,
146 const struct segment_command
*sc
;
149 sc
= getsegbynamefromheader(mhp
, segname
);
150 if(sc
== (struct segment_command
*)0){
155 result
= (void *)sc
->vmaddr
;
160 * This routine returns the section structure for the named section in the
161 * named segment for the mach_header pointer passed to it if it exist.
162 * Otherwise it returns zero.
164 * This routine can operate against any 32 bit mach header.
170 getsectbynamefromheader(
171 struct mach_header
*mhp
,
173 const char *sectname
)
175 struct segment_command
*sgp
;
179 sgp
= (struct segment_command
*)
180 ((char *)mhp
+ sizeof(struct mach_header
));
181 for(i
= 0; i
< mhp
->ncmds
; i
++){
182 if(sgp
->cmd
== LC_SEGMENT
)
183 if(strncmp(sgp
->segname
, segname
, sizeof(sgp
->segname
)) == 0 ||
184 mhp
->filetype
== MH_OBJECT
){
185 sp
= (struct section
*)((char *)sgp
+
186 sizeof(struct segment_command
));
187 for(j
= 0; j
< sgp
->nsects
; j
++){
188 if(strncmp(sp
->sectname
, sectname
,
189 sizeof(sp
->sectname
)) == 0 &&
190 strncmp(sp
->segname
, segname
,
191 sizeof(sp
->segname
)) == 0)
193 sp
= (struct section
*)((char *)sp
+
194 sizeof(struct section
));
197 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
199 return((struct section
*)0);
206 * This routine can operate against any 32 bit mach header.
208 struct segment_command
*
209 getsegbynamefromheader(
210 struct mach_header
*header
,
211 const char *seg_name
)
213 struct segment_command
*sgp
;
216 sgp
= (struct segment_command
*)
217 ((char *)header
+ sizeof(struct mach_header
));
218 for (i
= 0; i
< header
->ncmds
; i
++){
219 if ( sgp
->cmd
== LC_SEGMENT
220 && !strncmp(sgp
->segname
, seg_name
, sizeof(sgp
->segname
)))
222 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
224 return (struct segment_command
*)0;
229 * For now at least, all the rest of this seems unused.
230 * NOTE: The constant in here for segment alignment is machine-dependent,
231 * so if you include this, define a machine dependent constant for it's
235 struct segment_command seg
;
240 sizeof(fvm_data
), // cmdsize
246 VM_PROT_READ
, // maxprot
247 VM_PROT_READ
, // initprot,
269 struct segment_command
*fvm_seg
;
271 static struct fvmfile_command
*fvmfilefromheader(struct mach_header
*header
);
272 static vm_offset_t
getsizeofmacho(struct mach_header
*header
);
275 * Return the first segment_command in the header.
280 struct segment_command
*
283 return firstsegfromheader(&_mh_execute_header
);
289 struct segment_command
*
290 firstsegfromheader(struct mach_header
*header
)
292 struct segment_command
*sgp
;
295 sgp
= (struct segment_command
*)
296 ((char *)header
+ sizeof(struct mach_header
));
297 for (i
= 0; i
< header
->ncmds
; i
++){
298 if (sgp
->cmd
== LC_SEGMENT
)
300 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
302 return (struct segment_command
*)0;
309 * This routine operates against a 32 bit mach segment_command structure
310 * pointer from the currently executing kernel only, to obtain the
311 * sequentially next segment_command structure in the currently executing
314 struct segment_command
*
315 nextseg(struct segment_command
*sgp
)
317 struct segment_command
*this;
319 this = nextsegfromheader(&_mh_execute_header
, sgp
);
322 * For the kernel's header add on the faked segment for the
323 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
325 if (!this && sgp
!= fvm_seg
)
335 * This routine operates against any 32 bit mach segment_command structure
336 * pointer and the provided 32 bit header, to obtain the sequentially next
337 * segment_command structure in that header.
339 struct segment_command
*
341 struct mach_header
*header
,
342 struct segment_command
*seg
)
344 struct segment_command
*sgp
;
347 sgp
= (struct segment_command
*)
348 ((char *)header
+ sizeof(struct mach_header
));
349 for (i
= 0; i
< header
->ncmds
; i
++) {
352 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
355 if (i
== header
->ncmds
)
356 return (struct segment_command
*)0;
358 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
359 for (; i
< header
->ncmds
; i
++) {
360 if (sgp
->cmd
== LC_SEGMENT
)
362 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
365 return (struct segment_command
*)0;
370 * Return the address of the named Mach-O segment from the currently
371 * executing 32 bit kernel, or NULL.
376 struct segment_command
*
377 getsegbyname(const char *seg_name
)
379 struct segment_command
*this;
381 this = getsegbynamefromheader(&_mh_execute_header
, seg_name
);
384 * For the kernel's header add on the faked segment for the
385 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
387 if (!this && strcmp(seg_name
, fvm_seg
->segname
) == 0)
394 * This routine returns the a pointer the section structure of the named
395 * section in the named segment if it exists in the currently executing
396 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
404 const char *sectname
)
406 return(getsectbynamefromheader(
407 (struct mach_header
*)&_mh_execute_header
, segname
, sectname
));
414 * This routine can operate against any 32 bit segment_command structure to
415 * return the first 32 bit section immediately following that structure. If
416 * there are no sections associated with the segment_command structure, it
420 firstsect(struct segment_command
*sgp
)
422 if (!sgp
|| sgp
->nsects
== 0)
423 return (struct section
*)0;
425 return (struct section
*)(sgp
+1);
432 * This routine can operate against any 32 bit segment_command structure and
433 * 32 bit section to return the next consecutive 32 bit section immediately
434 * following the 32 bit section provided. If there are no sections following
435 * the provided section, it returns NULL.
438 nextsect(struct segment_command
*sgp
, struct section
*sp
)
440 struct section
*fsp
= firstsect(sgp
);
442 if (((unsigned long)(sp
- fsp
) + 1) >= sgp
->nsects
)
443 return (struct section
*)0;
449 * This routine can operate against any 32 bit mach header to return the
450 * first occurring 32 bit fvmfile_command section. If one is not present,
453 static struct fvmfile_command
*
454 fvmfilefromheader(struct mach_header
*header
)
456 struct fvmfile_command
*fvp
;
459 fvp
= (struct fvmfile_command
*)
460 ((char *)header
+ sizeof(struct mach_header
));
461 for (i
= 0; i
< header
->ncmds
; i
++){
462 if (fvp
->cmd
== LC_FVMFILE
)
464 fvp
= (struct fvmfile_command
*)((char *)fvp
+ fvp
->cmdsize
);
466 return (struct fvmfile_command
*)0;
470 * Create a fake USER seg if a fvmfile_command is present.
472 * This routine operates against the currently executing kernel only
477 struct segment_command
*
480 struct segment_command
*sgp
= getsegbyname("__USER");
481 struct fvmfile_command
*fvp
= fvmfilefromheader(&_mh_execute_header
);
488 return (struct segment_command
*)0;
490 fvm_seg
= &fvm_data
.seg
;
494 sgp
->vmaddr
= fvp
->header_addr
;
495 sgp
->vmsize
= getsizeofmacho((struct mach_header
*)(sgp
->vmaddr
));
497 strcpy(sp
->sectname
, fvp
->name
.ptr
);
498 sp
->addr
= sgp
->vmaddr
;
499 sp
->size
= sgp
->vmsize
;
502 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
503 sp
->sectname
, sp
->addr
, sp
->size
);
509 * Figure out the size the size of the data associated with a
510 * loaded mach_header.
512 * This routine operates against the currently executing kernel only
515 getsizeofmacho(struct mach_header
*header
)
517 struct segment_command
*sgp
;
518 vm_offset_t last_addr
;
521 for ( sgp
= firstsegfromheader(header
)
523 ; sgp
= nextsegfromheader(header
, sgp
))
525 if (sgp
->fileoff
+ sgp
->filesize
> last_addr
)
526 last_addr
= sgp
->fileoff
+ sgp
->filesize
;
534 * This routine returns the section command for the symbol table in the
535 * named segment for the mach_header pointer passed to it if it exist.
536 * Otherwise it returns zero.
538 struct symtab_command
*
539 getsectcmdsymtabfromheader(
540 struct mach_header
*mhp
)
542 struct segment_command
*sgp
;
545 sgp
= (struct segment_command
*)
546 ((char *)mhp
+ sizeof(struct mach_header
));
547 for(i
= 0; i
< mhp
->ncmds
; i
++){
548 if(sgp
->cmd
== LC_SYMTAB
)
549 return((struct symtab_command
*)sgp
);
550 sgp
= (struct segment_command
*)((char *)sgp
+ sgp
->cmdsize
);
555 boolean_t
getsymtab(struct mach_header
*header
,
559 vm_size_t
*strtabsize
)
561 struct segment_command
*seglink_cmd
;
562 struct symtab_command
*symtab_cmd
;
566 if(header
->magic
!= MH_MAGIC
) { /* Check if this is a valid header format */
567 printf("Attempt to use invalid header (magic = %08X) to find symbol table\n",
568 header
->magic
); /* Tell them what's wrong */
569 return (FALSE
); /* Bye y'all... */
572 seglink_cmd
= getsegbynamefromheader(header
,"__LINKEDIT");
573 if (seglink_cmd
== NULL
) {
578 symtab_cmd
= getsectcmdsymtabfromheader(header
);
579 if (symtab_cmd
== NULL
)
582 *nsyms
= symtab_cmd
->nsyms
;
583 if(symtab_cmd
->nsyms
== 0) return (FALSE
); /* No symbols */
585 *strtabsize
= symtab_cmd
->strsize
;
586 if(symtab_cmd
->strsize
== 0) return (FALSE
); /* Symbol length is 0 */
588 *symtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->symoff
-
589 seglink_cmd
->fileoff
;
591 *strtab
= seglink_cmd
->vmaddr
+ symtab_cmd
->stroff
-
592 seglink_cmd
->fileoff
;
600 void * getsegdatafromheader( struct mach_header
*mhp
, char *segname
, int *size
)