]> git.saurik.com Git - apple/xnu.git/blame - osfmk/mach-o/mach_header.c
xnu-792.13.8.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 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
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
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
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.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b
A
29 */
30/*
31 * File: kern/mach_header.c
32 *
33 * Functions for accessing mach-o headers.
34 *
91447636
A
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
41 * present time.
42 *
1c79356b
A
43 * HISTORY
44 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
45 * Added getsegdatafromheader();
46 *
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.
50 */
51
52#include <vm/vm_map.h>
53#include <vm/vm_kern.h>
54#include <mach-o/mach_header.h>
91447636 55#include <string.h> // from libsa
1c79356b
A
56
57#ifdef __MACHO__
58
59extern struct mach_header _mh_execute_header;
60
1c79356b
A
61/*
62 * return the last address (first avail)
91447636
A
63 *
64 * This routine operates against the currently executing kernel only
1c79356b
A
65 */
66#ifdef MACH_BSD
67__private_extern__
68#endif
91447636
A
69vm_offset_t
70getlastaddr(void)
1c79356b
A
71{
72 struct segment_command *sgp;
73 vm_offset_t last_addr = 0;
74 struct mach_header *header = &_mh_execute_header;
91447636 75 unsigned long i;
1c79356b
A
76
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;
83 }
84 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
85 }
86 return last_addr;
87}
88
89#ifdef XXX_MACH_BSD
90__private_extern__
91#endif
91447636
A
92/*
93 * This routine operates against the currently executing kernel only
94 */
1c79356b
A
95struct mach_header **
96getmachheaders(void)
97{
1c79356b
A
98 struct mach_header **tl;
99
100 if (kmem_alloc(kernel_map, (vm_offset_t *) &tl, 2*sizeof(struct mach_header *)) != KERN_SUCCESS)
101 return NULL;
102
103 tl[0] = &_mh_execute_header;
104 tl[1] = (struct mach_header *)0;
105 return tl;
106}
107
108/*
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.
91447636
A
113 *
114 * This routine can operate against any 32 bit mach header.
1c79356b
A
115 */
116#ifdef MACH_BSD
117__private_extern__
118#endif
119void *
120getsectdatafromheader(
121 struct mach_header *mhp,
91447636
A
122 const char *segname,
123 const char *sectname,
1c79356b
A
124 int *size)
125{
126 const struct section *sp;
127 void *result;
128
129 sp = getsectbynamefromheader(mhp, segname, sectname);
130 if(sp == (struct section *)0){
131 *size = 0;
132 return((char *)0);
133 }
134 *size = sp->size;
135 result = (void *)sp->addr;
136 return result;
137}
138
139/*
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.
144 */
145#ifdef MACH_BSD
146__private_extern__
147#endif
148void *
149getsegdatafromheader(
150 struct mach_header *mhp,
91447636 151 const char *segname,
1c79356b
A
152 int *size)
153{
154 const struct segment_command *sc;
155 void *result;
156
157 sc = getsegbynamefromheader(mhp, segname);
158 if(sc == (struct segment_command *)0){
159 *size = 0;
160 return((char *)0);
161 }
162 *size = sc->vmsize;
163 result = (void *)sc->vmaddr;
164 return result;
165}
166
167/*
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.
91447636
A
171 *
172 * This routine can operate against any 32 bit mach header.
1c79356b
A
173 */
174#ifdef MACH_BSD
175__private_extern__
176#endif
177struct section *
178getsectbynamefromheader(
179 struct mach_header *mhp,
91447636
A
180 const char *segname,
181 const char *sectname)
1c79356b
A
182{
183 struct segment_command *sgp;
184 struct section *sp;
91447636 185 unsigned long i, j;
1c79356b
A
186
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)
200 return(sp);
201 sp = (struct section *)((char *)sp +
202 sizeof(struct section));
203 }
204 }
205 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
206 }
207 return((struct section *)0);
208}
209
210#ifdef MACH_BSD
211__private_extern__
212#endif
91447636
A
213/*
214 * This routine can operate against any 32 bit mach header.
215 */
216struct segment_command *
217getsegbynamefromheader(
1c79356b 218 struct mach_header *header,
91447636 219 const char *seg_name)
1c79356b
A
220{
221 struct segment_command *sgp;
91447636 222 unsigned long i;
1c79356b
A
223
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)))
229 return sgp;
230 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
231 }
232 return (struct segment_command *)0;
233}
234
235
236/*
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
240 * value.
241 */
242static struct {
243 struct segment_command seg;
244 struct section sect;
245} fvm_data = {
246 {
247 LC_SEGMENT, // cmd
248 sizeof(fvm_data), // cmdsize
249 "__USER", // segname
250 0, // vmaddr
251 0, // vmsize
252 0, // fileoff
253 0, // filesize
254 VM_PROT_READ, // maxprot
255 VM_PROT_READ, // initprot,
256 1, // nsects
257 0 // flags
258 },
259 {
260 "", // sectname
261 "__USER", // segname
262 0, // addr
263 0, // size
264 0, // offset
265 4, // align
266 0, // reloff
267 0, // nreloc
91447636
A
268 0, // flags
269 0, // reserved1
270 0 // reserved2
1c79356b
A
271 }
272};
273
274#ifdef MACH_BSD
275static
276#endif
277struct segment_command *fvm_seg;
278
279static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
280static vm_offset_t getsizeofmacho(struct mach_header *header);
281
282/*
283 * Return the first segment_command in the header.
284 */
285#ifdef MACH_BSD
286__private_extern__
287#endif
91447636
A
288struct segment_command *
289firstseg(void)
1c79356b
A
290{
291 return firstsegfromheader(&_mh_execute_header);
292}
293
294#ifdef MACH_BSD
295__private_extern__
296#endif
91447636
A
297struct segment_command *
298firstsegfromheader(struct mach_header *header)
1c79356b
A
299{
300 struct segment_command *sgp;
91447636 301 unsigned long i;
1c79356b
A
302
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)
307 return sgp;
308 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
309 }
310 return (struct segment_command *)0;
311}
312
313#ifdef MACH_BSD
314__private_extern__
315#endif
91447636
A
316/*
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
320 * kernel
321 */
322struct segment_command *
323nextseg(struct segment_command *sgp)
1c79356b
A
324{
325 struct segment_command *this;
326
327 this = nextsegfromheader(&_mh_execute_header, sgp);
328
329 /*
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.
332 */
333 if (!this && sgp != fvm_seg)
334 this = fvm_seg;
335
336 return this;
337}
338
339#ifdef MACH_BSD
340__private_extern__
341#endif
91447636
A
342/*
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.
346 */
347struct segment_command *
348nextsegfromheader(
1c79356b
A
349 struct mach_header *header,
350 struct segment_command *seg)
351{
352 struct segment_command *sgp;
91447636 353 unsigned long i;
1c79356b
A
354
355 sgp = (struct segment_command *)
356 ((char *)header + sizeof(struct mach_header));
357 for (i = 0; i < header->ncmds; i++) {
358 if (sgp == seg)
359 break;
360 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
361 }
362
363 if (i == header->ncmds)
364 return (struct segment_command *)0;
365
366 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
367 for (; i < header->ncmds; i++) {
368 if (sgp->cmd == LC_SEGMENT)
369 return sgp;
370 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
371 }
372
373 return (struct segment_command *)0;
374}
375
376
377/*
91447636
A
378 * Return the address of the named Mach-O segment from the currently
379 * executing 32 bit kernel, or NULL.
1c79356b
A
380 */
381#ifdef MACH_BSD
382__private_extern__
383#endif
91447636
A
384struct segment_command *
385getsegbyname(const char *seg_name)
1c79356b
A
386{
387 struct segment_command *this;
388
389 this = getsegbynamefromheader(&_mh_execute_header, seg_name);
390
391 /*
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.
394 */
395 if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
396 this = fvm_seg;
397
398 return this;
399}
400
401/*
402 * This routine returns the a pointer the section structure of the named
91447636
A
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.
1c79356b
A
405 */
406#ifdef MACH_BSD
407__private_extern__
408#endif
409struct section *
410getsectbyname(
91447636
A
411 const char *segname,
412 const char *sectname)
1c79356b
A
413{
414 return(getsectbynamefromheader(
415 (struct mach_header *)&_mh_execute_header, segname, sectname));
416}
417
418#ifdef MACH_BSD
419__private_extern__
420#endif
91447636
A
421/*
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
425 * returns NULL.
426 */
427struct section *
428firstsect(struct segment_command *sgp)
1c79356b 429{
1c79356b
A
430 if (!sgp || sgp->nsects == 0)
431 return (struct section *)0;
432
433 return (struct section *)(sgp+1);
434}
435
436#ifdef MACH_BSD
437__private_extern__
438#endif
91447636
A
439/*
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.
444 */
445struct section *
446nextsect(struct segment_command *sgp, struct section *sp)
1c79356b
A
447{
448 struct section *fsp = firstsect(sgp);
449
91447636 450 if (((unsigned long)(sp - fsp) + 1) >= sgp->nsects)
1c79356b
A
451 return (struct section *)0;
452
453 return sp+1;
454}
455
91447636
A
456/*
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,
459 * it returns NULL.
460 */
461static struct fvmfile_command *
462fvmfilefromheader(struct mach_header *header)
1c79356b
A
463{
464 struct fvmfile_command *fvp;
91447636 465 unsigned long i;
1c79356b
A
466
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)
471 return fvp;
472 fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
473 }
474 return (struct fvmfile_command *)0;
475}
476
477/*
478 * Create a fake USER seg if a fvmfile_command is present.
91447636
A
479 *
480 * This routine operates against the currently executing kernel only
1c79356b
A
481 */
482#ifdef MACH_BSD
483__private_extern__
484#endif
91447636
A
485struct segment_command *
486getfakefvmseg(void)
1c79356b
A
487{
488 struct segment_command *sgp = getsegbyname("__USER");
489 struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
490 struct section *sp;
491
492 if (sgp)
493 return sgp;
494
495 if (!fvp)
496 return (struct segment_command *)0;
497
498 fvm_seg = &fvm_data.seg;
499 sgp = fvm_seg;
500 sp = &fvm_data.sect;
501
502 sgp->vmaddr = fvp->header_addr;
503 sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
504
505 strcpy(sp->sectname, fvp->name.ptr);
506 sp->addr = sgp->vmaddr;
507 sp->size = sgp->vmsize;
508
509#if DEBUG
510 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
511 sp->sectname, sp->addr, sp->size);
512#endif /*DEBUG*/
513 return sgp;
514}
515
516/*
517 * Figure out the size the size of the data associated with a
518 * loaded mach_header.
91447636
A
519 *
520 * This routine operates against the currently executing kernel only
1c79356b 521 */
91447636
A
522static vm_offset_t
523getsizeofmacho(struct mach_header *header)
1c79356b
A
524{
525 struct segment_command *sgp;
1c79356b
A
526 vm_offset_t last_addr;
527
528 last_addr = 0;
529 for ( sgp = firstsegfromheader(header)
530 ; sgp
531 ; sgp = nextsegfromheader(header, sgp))
532 {
533 if (sgp->fileoff + sgp->filesize > last_addr)
534 last_addr = sgp->fileoff + sgp->filesize;
535 }
536
537 return last_addr;
538}
539
540#ifdef MACH_KDB
541/*
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.
545 */
546struct symtab_command *
547getsectcmdsymtabfromheader(
548 struct mach_header *mhp)
549{
550 struct segment_command *sgp;
91447636 551 unsigned long i;
1c79356b
A
552
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);
559 }
560 return(NULL);
561}
562
563boolean_t getsymtab(struct mach_header *header,
564 vm_offset_t *symtab,
565 int *nsyms,
566 vm_offset_t *strtab,
567 vm_size_t *strtabsize)
568{
569 struct segment_command *seglink_cmd;
570 struct symtab_command *symtab_cmd;
571
572 seglink_cmd = NULL;
573
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... */
578 }
579
580 seglink_cmd = getsegbynamefromheader(header,"__LINKEDIT");
581 if (seglink_cmd == NULL) {
582 return(FALSE);
583 }
584
585 symtab_cmd = NULL;
586 symtab_cmd = getsectcmdsymtabfromheader(header);
587 if (symtab_cmd == NULL)
588 return(FALSE);
589
590 *nsyms = symtab_cmd->nsyms;
591 if(symtab_cmd->nsyms == 0) return (FALSE); /* No symbols */
592
593 *strtabsize = symtab_cmd->strsize;
594 if(symtab_cmd->strsize == 0) return (FALSE); /* Symbol length is 0 */
595
596 *symtab = seglink_cmd->vmaddr + symtab_cmd->symoff -
597 seglink_cmd->fileoff;
598
599 *strtab = seglink_cmd->vmaddr + symtab_cmd->stroff -
600 seglink_cmd->fileoff;
601
602 return(TRUE);
603}
604#endif
605
606#else
607
608void * getsegdatafromheader( struct mach_header *mhp, char *segname, int *size)
609{
610 return 0;
611}
612
613#endif