]> git.saurik.com Git - apple/xnu.git/blob - osfmk/mach-o/mach_header.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / mach-o / mach_header.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * File: kern/mach_header.c
27 *
28 * Functions for accessing mach-o headers.
29 *
30 * HISTORY
31 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
32 * Added getsegdatafromheader();
33 *
34 * 29-Jan-92 Mike DeMoney (mike@next.com)
35 * Made into machine independent form from machdep/m68k/mach_header.c.
36 * Ifdef'ed out most of this since I couldn't find any references.
37 */
38
39 #include <vm/vm_map.h>
40 #include <vm/vm_kern.h>
41 #include <mach-o/mach_header.h>
42
43 #ifdef __MACHO__
44
45 extern struct mach_header _mh_execute_header;
46
47 struct section *getsectbynamefromheader(
48 struct mach_header *header,
49 char *seg_name,
50 char *sect_name);
51 struct segment_command *getsegbynamefromheader(
52 struct mach_header *header,
53 char *seg_name);
54
55 /*
56 * return the last address (first avail)
57 */
58 #ifdef MACH_BSD
59 __private_extern__
60 #endif
61 vm_offset_t getlastaddr(void)
62 {
63 struct segment_command *sgp;
64 vm_offset_t last_addr = 0;
65 struct mach_header *header = &_mh_execute_header;
66 int i;
67
68 sgp = (struct segment_command *)
69 ((char *)header + sizeof(struct mach_header));
70 for (i = 0; i < header->ncmds; i++){
71 if ( sgp->cmd == LC_SEGMENT) {
72 if (sgp->vmaddr + sgp->vmsize > last_addr)
73 last_addr = sgp->vmaddr + sgp->vmsize;
74 }
75 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
76 }
77 return last_addr;
78 }
79
80 #ifdef XXX_MACH_BSD
81 __private_extern__
82 #endif
83 struct mach_header **
84 getmachheaders(void)
85 {
86 extern struct mach_header _mh_execute_header;
87 struct mach_header **tl;
88
89 if (kmem_alloc(kernel_map, (vm_offset_t *) &tl, 2*sizeof(struct mach_header *)) != KERN_SUCCESS)
90 return NULL;
91
92 tl[0] = &_mh_execute_header;
93 tl[1] = (struct mach_header *)0;
94 return tl;
95 }
96
97 /*
98 * This routine returns the a pointer to the data for the named section in the
99 * named segment if it exist in the mach header passed to it. Also it returns
100 * the size of the section data indirectly through the pointer size. Otherwise
101 * it returns zero for the pointer and the size.
102 */
103 #ifdef MACH_BSD
104 __private_extern__
105 #endif
106 void *
107 getsectdatafromheader(
108 struct mach_header *mhp,
109 char *segname,
110 char *sectname,
111 int *size)
112 {
113 const struct section *sp;
114 void *result;
115
116 sp = getsectbynamefromheader(mhp, segname, sectname);
117 if(sp == (struct section *)0){
118 *size = 0;
119 return((char *)0);
120 }
121 *size = sp->size;
122 result = (void *)sp->addr;
123 return result;
124 }
125
126 /*
127 * This routine returns the a pointer to the data for the named segment
128 * if it exist in the mach header passed to it. Also it returns
129 * the size of the segment data indirectly through the pointer size.
130 * Otherwise it returns zero for the pointer and the size.
131 */
132 #ifdef MACH_BSD
133 __private_extern__
134 #endif
135 void *
136 getsegdatafromheader(
137 struct mach_header *mhp,
138 char *segname,
139 int *size)
140 {
141 const struct segment_command *sc;
142 void *result;
143
144 sc = getsegbynamefromheader(mhp, segname);
145 if(sc == (struct segment_command *)0){
146 *size = 0;
147 return((char *)0);
148 }
149 *size = sc->vmsize;
150 result = (void *)sc->vmaddr;
151 return result;
152 }
153
154 /*
155 * This routine returns the section structure for the named section in the
156 * named segment for the mach_header pointer passed to it if it exist.
157 * Otherwise it returns zero.
158 */
159 #ifdef MACH_BSD
160 __private_extern__
161 #endif
162 struct section *
163 getsectbynamefromheader(
164 struct mach_header *mhp,
165 char *segname,
166 char *sectname)
167 {
168 struct segment_command *sgp;
169 struct section *sp;
170 long i, j;
171
172 sgp = (struct segment_command *)
173 ((char *)mhp + sizeof(struct mach_header));
174 for(i = 0; i < mhp->ncmds; i++){
175 if(sgp->cmd == LC_SEGMENT)
176 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
177 mhp->filetype == MH_OBJECT){
178 sp = (struct section *)((char *)sgp +
179 sizeof(struct segment_command));
180 for(j = 0; j < sgp->nsects; j++){
181 if(strncmp(sp->sectname, sectname,
182 sizeof(sp->sectname)) == 0 &&
183 strncmp(sp->segname, segname,
184 sizeof(sp->segname)) == 0)
185 return(sp);
186 sp = (struct section *)((char *)sp +
187 sizeof(struct section));
188 }
189 }
190 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
191 }
192 return((struct section *)0);
193 }
194
195 #ifdef MACH_BSD
196 __private_extern__
197 #endif
198 struct segment_command *getsegbynamefromheader(
199 struct mach_header *header,
200 char *seg_name)
201 {
202 struct segment_command *sgp;
203 int i;
204
205 sgp = (struct segment_command *)
206 ((char *)header + sizeof(struct mach_header));
207 for (i = 0; i < header->ncmds; i++){
208 if ( sgp->cmd == LC_SEGMENT
209 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
210 return sgp;
211 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
212 }
213 return (struct segment_command *)0;
214 }
215
216
217 /*
218 * For now at least, all the rest of this seems unused.
219 * NOTE: The constant in here for segment alignment is machine-dependent,
220 * so if you include this, define a machine dependent constant for it's
221 * value.
222 */
223 static struct {
224 struct segment_command seg;
225 struct section sect;
226 } fvm_data = {
227 {
228 LC_SEGMENT, // cmd
229 sizeof(fvm_data), // cmdsize
230 "__USER", // segname
231 0, // vmaddr
232 0, // vmsize
233 0, // fileoff
234 0, // filesize
235 VM_PROT_READ, // maxprot
236 VM_PROT_READ, // initprot,
237 1, // nsects
238 0 // flags
239 },
240 {
241 "", // sectname
242 "__USER", // segname
243 0, // addr
244 0, // size
245 0, // offset
246 4, // align
247 0, // reloff
248 0, // nreloc
249 0 // flags
250 }
251 };
252
253 #ifdef MACH_BSD
254 static
255 #endif
256 struct segment_command *fvm_seg;
257
258 static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
259 static vm_offset_t getsizeofmacho(struct mach_header *header);
260
261 /*
262 * Return the first segment_command in the header.
263 */
264 #ifdef MACH_BSD
265 __private_extern__
266 #endif
267 struct segment_command *firstseg(void)
268 {
269 return firstsegfromheader(&_mh_execute_header);
270 }
271
272 #ifdef MACH_BSD
273 __private_extern__
274 #endif
275 struct segment_command *firstsegfromheader(struct mach_header *header)
276 {
277 struct segment_command *sgp;
278 int i;
279
280 sgp = (struct segment_command *)
281 ((char *)header + sizeof(struct mach_header));
282 for (i = 0; i < header->ncmds; i++){
283 if (sgp->cmd == LC_SEGMENT)
284 return sgp;
285 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
286 }
287 return (struct segment_command *)0;
288 }
289
290 #ifdef MACH_BSD
291 __private_extern__
292 #endif
293 struct segment_command *nextseg(struct segment_command *sgp)
294 {
295 struct segment_command *this;
296
297 this = nextsegfromheader(&_mh_execute_header, sgp);
298
299 /*
300 * For the kernel's header add on the faked segment for the
301 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
302 */
303 if (!this && sgp != fvm_seg)
304 this = fvm_seg;
305
306 return this;
307 }
308
309 #ifdef MACH_BSD
310 __private_extern__
311 #endif
312 struct segment_command *nextsegfromheader(
313 struct mach_header *header,
314 struct segment_command *seg)
315 {
316 struct segment_command *sgp;
317 int i;
318
319 sgp = (struct segment_command *)
320 ((char *)header + sizeof(struct mach_header));
321 for (i = 0; i < header->ncmds; i++) {
322 if (sgp == seg)
323 break;
324 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
325 }
326
327 if (i == header->ncmds)
328 return (struct segment_command *)0;
329
330 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
331 for (; i < header->ncmds; i++) {
332 if (sgp->cmd == LC_SEGMENT)
333 return sgp;
334 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
335 }
336
337 return (struct segment_command *)0;
338 }
339
340
341 /*
342 * Return the address of the named Mach-O segment, or NULL.
343 */
344 #ifdef MACH_BSD
345 __private_extern__
346 #endif
347 struct segment_command *getsegbyname(char *seg_name)
348 {
349 struct segment_command *this;
350
351 this = getsegbynamefromheader(&_mh_execute_header, seg_name);
352
353 /*
354 * For the kernel's header add on the faked segment for the
355 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
356 */
357 if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
358 this = fvm_seg;
359
360 return this;
361 }
362
363 /*
364 * This routine returns the a pointer the section structure of the named
365 * section in the named segment if it exist in the mach executable it is
366 * linked into. Otherwise it returns zero.
367 */
368 #ifdef MACH_BSD
369 __private_extern__
370 #endif
371 struct section *
372 getsectbyname(
373 char *segname,
374 char *sectname)
375 {
376 return(getsectbynamefromheader(
377 (struct mach_header *)&_mh_execute_header, segname, sectname));
378 }
379
380 #ifdef MACH_BSD
381 __private_extern__
382 #endif
383 struct section *firstsect(struct segment_command *sgp)
384 {
385 struct section *sp;
386
387 if (!sgp || sgp->nsects == 0)
388 return (struct section *)0;
389
390 return (struct section *)(sgp+1);
391 }
392
393 #ifdef MACH_BSD
394 __private_extern__
395 #endif
396 struct section *nextsect(struct segment_command *sgp, struct section *sp)
397 {
398 struct section *fsp = firstsect(sgp);
399
400 if (sp - fsp >= sgp->nsects-1)
401 return (struct section *)0;
402
403 return sp+1;
404 }
405
406 static struct fvmfile_command *fvmfilefromheader(struct mach_header *header)
407 {
408 struct fvmfile_command *fvp;
409 int i;
410
411 fvp = (struct fvmfile_command *)
412 ((char *)header + sizeof(struct mach_header));
413 for (i = 0; i < header->ncmds; i++){
414 if (fvp->cmd == LC_FVMFILE)
415 return fvp;
416 fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
417 }
418 return (struct fvmfile_command *)0;
419 }
420
421 /*
422 * Create a fake USER seg if a fvmfile_command is present.
423 */
424 #ifdef MACH_BSD
425 __private_extern__
426 #endif
427 struct segment_command *getfakefvmseg(void)
428 {
429 struct segment_command *sgp = getsegbyname("__USER");
430 struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
431 struct section *sp;
432
433 if (sgp)
434 return sgp;
435
436 if (!fvp)
437 return (struct segment_command *)0;
438
439 fvm_seg = &fvm_data.seg;
440 sgp = fvm_seg;
441 sp = &fvm_data.sect;
442
443 sgp->vmaddr = fvp->header_addr;
444 sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
445
446 strcpy(sp->sectname, fvp->name.ptr);
447 sp->addr = sgp->vmaddr;
448 sp->size = sgp->vmsize;
449
450 #if DEBUG
451 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
452 sp->sectname, sp->addr, sp->size);
453 #endif /*DEBUG*/
454 return sgp;
455 }
456
457 /*
458 * Figure out the size the size of the data associated with a
459 * loaded mach_header.
460 */
461 static vm_offset_t getsizeofmacho(struct mach_header *header)
462 {
463 struct segment_command *sgp;
464 struct section *sp;
465 vm_offset_t last_addr;
466
467 last_addr = 0;
468 for ( sgp = firstsegfromheader(header)
469 ; sgp
470 ; sgp = nextsegfromheader(header, sgp))
471 {
472 if (sgp->fileoff + sgp->filesize > last_addr)
473 last_addr = sgp->fileoff + sgp->filesize;
474 }
475
476 return last_addr;
477 }
478
479 #ifdef MACH_KDB
480 /*
481 * This routine returns the section command for the symbol table in the
482 * named segment for the mach_header pointer passed to it if it exist.
483 * Otherwise it returns zero.
484 */
485 struct symtab_command *
486 getsectcmdsymtabfromheader(
487 struct mach_header *mhp)
488 {
489 struct segment_command *sgp;
490 struct section *sp;
491 long i;
492
493 sgp = (struct segment_command *)
494 ((char *)mhp + sizeof(struct mach_header));
495 for(i = 0; i < mhp->ncmds; i++){
496 if(sgp->cmd == LC_SYMTAB)
497 return((struct symtab_command *)sgp);
498 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
499 }
500 return(NULL);
501 }
502
503 boolean_t getsymtab(struct mach_header *header,
504 vm_offset_t *symtab,
505 int *nsyms,
506 vm_offset_t *strtab,
507 vm_size_t *strtabsize)
508 {
509 struct segment_command *seglink_cmd;
510 struct symtab_command *symtab_cmd;
511
512 seglink_cmd = NULL;
513
514 if(header->magic != MH_MAGIC) { /* Check if this is a valid header format */
515 printf("Attempt to use invalid header (magic = %08X) to find symbol table\n",
516 header->magic); /* Tell them what's wrong */
517 return (FALSE); /* Bye y'all... */
518 }
519
520 seglink_cmd = getsegbynamefromheader(header,"__LINKEDIT");
521 if (seglink_cmd == NULL) {
522 return(FALSE);
523 }
524
525 symtab_cmd = NULL;
526 symtab_cmd = getsectcmdsymtabfromheader(header);
527 if (symtab_cmd == NULL)
528 return(FALSE);
529
530 *nsyms = symtab_cmd->nsyms;
531 if(symtab_cmd->nsyms == 0) return (FALSE); /* No symbols */
532
533 *strtabsize = symtab_cmd->strsize;
534 if(symtab_cmd->strsize == 0) return (FALSE); /* Symbol length is 0 */
535
536 *symtab = seglink_cmd->vmaddr + symtab_cmd->symoff -
537 seglink_cmd->fileoff;
538
539 *strtab = seglink_cmd->vmaddr + symtab_cmd->stroff -
540 seglink_cmd->fileoff;
541
542 return(TRUE);
543 }
544 #endif
545
546 #else
547
548 void * getsegdatafromheader( struct mach_header *mhp, char *segname, int *size)
549 {
550 return 0;
551 }
552
553 #endif