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