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