]> git.saurik.com Git - apple/xnu.git/blame - osfmk/mach-o/mach_header.c
xnu-792.24.17.tar.gz
[apple/xnu.git] / osfmk / mach-o / mach_header.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
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.
8f6c56a5 11 *
6601e61a
A
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
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22/*
23 * File: kern/mach_header.c
24 *
25 * Functions for accessing mach-o headers.
26 *
91447636
A
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
33 * present time.
34 *
1c79356b
A
35 * HISTORY
36 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
37 * Added getsegdatafromheader();
38 *
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.
42 */
43
44#include <vm/vm_map.h>
45#include <vm/vm_kern.h>
46#include <mach-o/mach_header.h>
91447636 47#include <string.h> // from libsa
1c79356b
A
48
49#ifdef __MACHO__
50
51extern struct mach_header _mh_execute_header;
52
1c79356b
A
53/*
54 * return the last address (first avail)
91447636
A
55 *
56 * This routine operates against the currently executing kernel only
1c79356b
A
57 */
58#ifdef MACH_BSD
59__private_extern__
60#endif
91447636
A
61vm_offset_t
62getlastaddr(void)
1c79356b
A
63{
64 struct segment_command *sgp;
65 vm_offset_t last_addr = 0;
66 struct mach_header *header = &_mh_execute_header;
91447636 67 unsigned long i;
1c79356b
A
68
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;
75 }
76 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
77 }
78 return last_addr;
79}
80
81#ifdef XXX_MACH_BSD
82__private_extern__
83#endif
91447636
A
84/*
85 * This routine operates against the currently executing kernel only
86 */
1c79356b
A
87struct mach_header **
88getmachheaders(void)
89{
1c79356b
A
90 struct mach_header **tl;
91
92 if (kmem_alloc(kernel_map, (vm_offset_t *) &tl, 2*sizeof(struct mach_header *)) != KERN_SUCCESS)
93 return NULL;
94
95 tl[0] = &_mh_execute_header;
96 tl[1] = (struct mach_header *)0;
97 return tl;
98}
99
100/*
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.
91447636
A
105 *
106 * This routine can operate against any 32 bit mach header.
1c79356b
A
107 */
108#ifdef MACH_BSD
109__private_extern__
110#endif
111void *
112getsectdatafromheader(
113 struct mach_header *mhp,
91447636
A
114 const char *segname,
115 const char *sectname,
1c79356b
A
116 int *size)
117{
118 const struct section *sp;
119 void *result;
120
121 sp = getsectbynamefromheader(mhp, segname, sectname);
122 if(sp == (struct section *)0){
123 *size = 0;
124 return((char *)0);
125 }
126 *size = sp->size;
127 result = (void *)sp->addr;
128 return result;
129}
130
131/*
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.
136 */
137#ifdef MACH_BSD
138__private_extern__
139#endif
140void *
141getsegdatafromheader(
142 struct mach_header *mhp,
91447636 143 const char *segname,
1c79356b
A
144 int *size)
145{
146 const struct segment_command *sc;
147 void *result;
148
149 sc = getsegbynamefromheader(mhp, segname);
150 if(sc == (struct segment_command *)0){
151 *size = 0;
152 return((char *)0);
153 }
154 *size = sc->vmsize;
155 result = (void *)sc->vmaddr;
156 return result;
157}
158
159/*
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.
91447636
A
163 *
164 * This routine can operate against any 32 bit mach header.
1c79356b
A
165 */
166#ifdef MACH_BSD
167__private_extern__
168#endif
169struct section *
170getsectbynamefromheader(
171 struct mach_header *mhp,
91447636
A
172 const char *segname,
173 const char *sectname)
1c79356b
A
174{
175 struct segment_command *sgp;
176 struct section *sp;
91447636 177 unsigned long i, j;
1c79356b
A
178
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)
192 return(sp);
193 sp = (struct section *)((char *)sp +
194 sizeof(struct section));
195 }
196 }
197 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
198 }
199 return((struct section *)0);
200}
201
202#ifdef MACH_BSD
203__private_extern__
204#endif
91447636
A
205/*
206 * This routine can operate against any 32 bit mach header.
207 */
208struct segment_command *
209getsegbynamefromheader(
1c79356b 210 struct mach_header *header,
91447636 211 const char *seg_name)
1c79356b
A
212{
213 struct segment_command *sgp;
91447636 214 unsigned long i;
1c79356b
A
215
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)))
221 return sgp;
222 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
223 }
224 return (struct segment_command *)0;
225}
226
227
228/*
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
232 * value.
233 */
234static struct {
235 struct segment_command seg;
236 struct section sect;
237} fvm_data = {
238 {
239 LC_SEGMENT, // cmd
240 sizeof(fvm_data), // cmdsize
241 "__USER", // segname
242 0, // vmaddr
243 0, // vmsize
244 0, // fileoff
245 0, // filesize
246 VM_PROT_READ, // maxprot
247 VM_PROT_READ, // initprot,
248 1, // nsects
249 0 // flags
250 },
251 {
252 "", // sectname
253 "__USER", // segname
254 0, // addr
255 0, // size
256 0, // offset
257 4, // align
258 0, // reloff
259 0, // nreloc
91447636
A
260 0, // flags
261 0, // reserved1
262 0 // reserved2
1c79356b
A
263 }
264};
265
266#ifdef MACH_BSD
267static
268#endif
269struct segment_command *fvm_seg;
270
271static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
272static vm_offset_t getsizeofmacho(struct mach_header *header);
273
274/*
275 * Return the first segment_command in the header.
276 */
277#ifdef MACH_BSD
278__private_extern__
279#endif
91447636
A
280struct segment_command *
281firstseg(void)
1c79356b
A
282{
283 return firstsegfromheader(&_mh_execute_header);
284}
285
286#ifdef MACH_BSD
287__private_extern__
288#endif
91447636
A
289struct segment_command *
290firstsegfromheader(struct mach_header *header)
1c79356b
A
291{
292 struct segment_command *sgp;
91447636 293 unsigned long i;
1c79356b
A
294
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)
299 return sgp;
300 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
301 }
302 return (struct segment_command *)0;
303}
304
305#ifdef MACH_BSD
306__private_extern__
307#endif
91447636
A
308/*
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
312 * kernel
313 */
314struct segment_command *
315nextseg(struct segment_command *sgp)
1c79356b
A
316{
317 struct segment_command *this;
318
319 this = nextsegfromheader(&_mh_execute_header, sgp);
320
321 /*
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.
324 */
325 if (!this && sgp != fvm_seg)
326 this = fvm_seg;
327
328 return this;
329}
330
331#ifdef MACH_BSD
332__private_extern__
333#endif
91447636
A
334/*
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.
338 */
339struct segment_command *
340nextsegfromheader(
1c79356b
A
341 struct mach_header *header,
342 struct segment_command *seg)
343{
344 struct segment_command *sgp;
91447636 345 unsigned long i;
1c79356b
A
346
347 sgp = (struct segment_command *)
348 ((char *)header + sizeof(struct mach_header));
349 for (i = 0; i < header->ncmds; i++) {
350 if (sgp == seg)
351 break;
352 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
353 }
354
355 if (i == header->ncmds)
356 return (struct segment_command *)0;
357
358 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
359 for (; i < header->ncmds; i++) {
360 if (sgp->cmd == LC_SEGMENT)
361 return sgp;
362 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
363 }
364
365 return (struct segment_command *)0;
366}
367
368
369/*
91447636
A
370 * Return the address of the named Mach-O segment from the currently
371 * executing 32 bit kernel, or NULL.
1c79356b
A
372 */
373#ifdef MACH_BSD
374__private_extern__
375#endif
91447636
A
376struct segment_command *
377getsegbyname(const char *seg_name)
1c79356b
A
378{
379 struct segment_command *this;
380
381 this = getsegbynamefromheader(&_mh_execute_header, seg_name);
382
383 /*
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.
386 */
387 if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
388 this = fvm_seg;
389
390 return this;
391}
392
393/*
394 * This routine returns the a pointer the section structure of the named
91447636
A
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.
1c79356b
A
397 */
398#ifdef MACH_BSD
399__private_extern__
400#endif
401struct section *
402getsectbyname(
91447636
A
403 const char *segname,
404 const char *sectname)
1c79356b
A
405{
406 return(getsectbynamefromheader(
407 (struct mach_header *)&_mh_execute_header, segname, sectname));
408}
409
410#ifdef MACH_BSD
411__private_extern__
412#endif
91447636
A
413/*
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
417 * returns NULL.
418 */
419struct section *
420firstsect(struct segment_command *sgp)
1c79356b 421{
1c79356b
A
422 if (!sgp || sgp->nsects == 0)
423 return (struct section *)0;
424
425 return (struct section *)(sgp+1);
426}
427
428#ifdef MACH_BSD
429__private_extern__
430#endif
91447636
A
431/*
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.
436 */
437struct section *
438nextsect(struct segment_command *sgp, struct section *sp)
1c79356b
A
439{
440 struct section *fsp = firstsect(sgp);
441
91447636 442 if (((unsigned long)(sp - fsp) + 1) >= sgp->nsects)
1c79356b
A
443 return (struct section *)0;
444
445 return sp+1;
446}
447
91447636
A
448/*
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,
451 * it returns NULL.
452 */
453static struct fvmfile_command *
454fvmfilefromheader(struct mach_header *header)
1c79356b
A
455{
456 struct fvmfile_command *fvp;
91447636 457 unsigned long i;
1c79356b
A
458
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)
463 return fvp;
464 fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
465 }
466 return (struct fvmfile_command *)0;
467}
468
469/*
470 * Create a fake USER seg if a fvmfile_command is present.
91447636
A
471 *
472 * This routine operates against the currently executing kernel only
1c79356b
A
473 */
474#ifdef MACH_BSD
475__private_extern__
476#endif
91447636
A
477struct segment_command *
478getfakefvmseg(void)
1c79356b
A
479{
480 struct segment_command *sgp = getsegbyname("__USER");
481 struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
482 struct section *sp;
483
484 if (sgp)
485 return sgp;
486
487 if (!fvp)
488 return (struct segment_command *)0;
489
490 fvm_seg = &fvm_data.seg;
491 sgp = fvm_seg;
492 sp = &fvm_data.sect;
493
494 sgp->vmaddr = fvp->header_addr;
495 sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
496
497 strcpy(sp->sectname, fvp->name.ptr);
498 sp->addr = sgp->vmaddr;
499 sp->size = sgp->vmsize;
500
501#if DEBUG
502 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
503 sp->sectname, sp->addr, sp->size);
504#endif /*DEBUG*/
505 return sgp;
506}
507
508/*
509 * Figure out the size the size of the data associated with a
510 * loaded mach_header.
91447636
A
511 *
512 * This routine operates against the currently executing kernel only
1c79356b 513 */
91447636
A
514static vm_offset_t
515getsizeofmacho(struct mach_header *header)
1c79356b
A
516{
517 struct segment_command *sgp;
1c79356b
A
518 vm_offset_t last_addr;
519
520 last_addr = 0;
521 for ( sgp = firstsegfromheader(header)
522 ; sgp
523 ; sgp = nextsegfromheader(header, sgp))
524 {
525 if (sgp->fileoff + sgp->filesize > last_addr)
526 last_addr = sgp->fileoff + sgp->filesize;
527 }
528
529 return last_addr;
530}
531
532#ifdef MACH_KDB
533/*
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.
537 */
538struct symtab_command *
539getsectcmdsymtabfromheader(
540 struct mach_header *mhp)
541{
542 struct segment_command *sgp;
91447636 543 unsigned long i;
1c79356b
A
544
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);
551 }
552 return(NULL);
553}
554
555boolean_t getsymtab(struct mach_header *header,
556 vm_offset_t *symtab,
557 int *nsyms,
558 vm_offset_t *strtab,
559 vm_size_t *strtabsize)
560{
561 struct segment_command *seglink_cmd;
562 struct symtab_command *symtab_cmd;
563
564 seglink_cmd = NULL;
565
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... */
570 }
571
572 seglink_cmd = getsegbynamefromheader(header,"__LINKEDIT");
573 if (seglink_cmd == NULL) {
574 return(FALSE);
575 }
576
577 symtab_cmd = NULL;
578 symtab_cmd = getsectcmdsymtabfromheader(header);
579 if (symtab_cmd == NULL)
580 return(FALSE);
581
582 *nsyms = symtab_cmd->nsyms;
583 if(symtab_cmd->nsyms == 0) return (FALSE); /* No symbols */
584
585 *strtabsize = symtab_cmd->strsize;
586 if(symtab_cmd->strsize == 0) return (FALSE); /* Symbol length is 0 */
587
588 *symtab = seglink_cmd->vmaddr + symtab_cmd->symoff -
589 seglink_cmd->fileoff;
590
591 *strtab = seglink_cmd->vmaddr + symtab_cmd->stroff -
592 seglink_cmd->fileoff;
593
594 return(TRUE);
595}
596#endif
597
598#else
599
600void * getsegdatafromheader( struct mach_header *mhp, char *segname, int *size)
601{
602 return 0;
603}
604
605#endif