]> git.saurik.com Git - apple/xnu.git/blame - osfmk/mach-o/mach_header.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / mach-o / mach_header.c
CommitLineData
1c79356b
A
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
42extern struct mach_header _mh_execute_header;
43
44struct section *getsectbynamefromheader(
45 struct mach_header *header,
46 char *seg_name,
47 char *sect_name);
48struct 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
58vm_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
80struct mach_header **
81getmachheaders(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
103void *
104getsectdatafromheader(
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
132void *
133getsegdatafromheader(
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
159struct section *
160getsectbynamefromheader(
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
195struct 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 */
220static 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
251static
252#endif
253struct segment_command *fvm_seg;
254
255static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
256static 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
264struct segment_command *firstseg(void)
265{
266 return firstsegfromheader(&_mh_execute_header);
267}
268
269#ifdef MACH_BSD
270__private_extern__
271#endif
272struct 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
290struct 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
309struct 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
344struct 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
368struct section *
369getsectbyname(
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
380struct 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
393struct 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
403static 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
424struct 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 */
458static 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 */
482struct symtab_command *
483getsectcmdsymtabfromheader(
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
500boolean_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
545void * getsegdatafromheader( struct mach_header *mhp, char *segname, int *size)
546{
547 return 0;
548}
549
550#endif