]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/mach_header.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / bsd / kern / mach_header.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
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.
8f6c56a5 11 *
6601e61a
A
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
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
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.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22/*
23 * File: kern/mach_header.c
24 *
25 * Functions for accessing mach-o headers.
26 *
91447636
A
27 * NOTE: This file supports only 32 bit mach headers at the present
28 * time; it's primary use is by kld, and all externally
29 * referenced routines at the present time operate against
30 * the 32 bit mach header _mh_execute_header, which is the
31 * header for the currently executing kernel. Adding support
32 * for 64 bit kernels is possible, but is not necessary at the
33 * present time.
34 *
1c79356b
A
35 * HISTORY
36 * 27-MAR-97 Umesh Vaishampayan (umeshv@NeXT.com)
37 * Added getsegdatafromheader();
38 *
39 * 29-Jan-92 Mike DeMoney (mike@next.com)
40 * Made into machine independent form from machdep/m68k/mach_header.c.
41 * Ifdef'ed out most of this since I couldn't find any references.
42 */
43
44#if !defined(KERNEL_PRELOAD)
45#include <kern/mach_header.h>
91447636 46#include <string.h> // from libsa
1c79356b
A
47
48extern struct mach_header _mh_execute_header;
49
1c79356b
A
50/*
51 * return the last address (first avail)
91447636
A
52 *
53 * This routine operates against the currently executing kernel only
1c79356b 54 */
91447636
A
55vm_offset_t
56getlastaddr(void)
1c79356b
A
57{
58 struct segment_command *sgp;
59 vm_offset_t last_addr = 0;
60 struct mach_header *header = &_mh_execute_header;
91447636 61 unsigned long i;
1c79356b
A
62
63 sgp = (struct segment_command *)
64 ((char *)header + sizeof(struct mach_header));
65 for (i = 0; i < header->ncmds; i++){
66 if ( sgp->cmd == LC_SEGMENT) {
67 if (sgp->vmaddr + sgp->vmsize > last_addr)
68 last_addr = sgp->vmaddr + sgp->vmsize;
69 }
70 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
71 }
72 return last_addr;
73}
74
75#if FIXME /* [ */
91447636
A
76/*
77 * This routine operates against the currently executing kernel only
78 */
1c79356b
A
79struct mach_header **
80getmachheaders(void)
81{
1c79356b
A
82 struct mach_header **tl;
83 tl = (struct mach_header **)malloc(2*sizeof(struct mach_header *));
84 tl[0] = &_mh_execute_header;
85 tl[1] = (struct mach_header *)0;
86 return tl;
87}
88#endif /* FIXME ] */
89
90/*
91 * This routine returns the a pointer to the data for the named section in the
92 * named segment if it exist in the mach header passed to it. Also it returns
93 * the size of the section data indirectly through the pointer size. Otherwise
94 * it returns zero for the pointer and the size.
91447636
A
95 *
96 * This routine can operate against any 32 bit mach header.
1c79356b
A
97 */
98void *
99getsectdatafromheader(
100 struct mach_header *mhp,
91447636
A
101 const char *segname,
102 const char *sectname,
1c79356b
A
103 int *size)
104{
105 const struct section *sp;
106 void *result;
107
108 sp = getsectbynamefromheader(mhp, segname, sectname);
109 if(sp == (struct section *)0){
110 *size = 0;
111 return((char *)0);
112 }
113 *size = sp->size;
114 result = (void *)sp->addr;
115 return result;
116}
117
118/*
119 * This routine returns the a pointer to the data for the named segment
120 * if it exist in the mach header passed to it. Also it returns
121 * the size of the segment data indirectly through the pointer size.
122 * Otherwise it returns zero for the pointer and the size.
91447636
A
123 *
124 * This routine can operate against any 32 bit mach header.
1c79356b
A
125 */
126void *
127getsegdatafromheader(
91447636
A
128 struct mach_header *mhp,
129 const char *segname,
1c79356b
A
130 int *size)
131{
132 const struct segment_command *sc;
133 void *result;
134
135 sc = getsegbynamefromheader(mhp, segname);
136 if(sc == (struct segment_command *)0){
137 *size = 0;
138 return((char *)0);
139 }
140 *size = sc->vmsize;
141 result = (void *)sc->vmaddr;
142 return result;
143}
144
145/*
146 * This routine returns the section structure for the named section in the
147 * named segment for the mach_header pointer passed to it if it exist.
148 * Otherwise it returns zero.
91447636
A
149 *
150 * This routine can operate against any 32 bit mach header.
1c79356b
A
151 */
152struct section *
153getsectbynamefromheader(
154 struct mach_header *mhp,
91447636
A
155 const char *segname,
156 const char *sectname)
1c79356b
A
157{
158 struct segment_command *sgp;
159 struct section *sp;
91447636 160 unsigned long i, j;
1c79356b
A
161
162 sgp = (struct segment_command *)
163 ((char *)mhp + sizeof(struct mach_header));
164 for(i = 0; i < mhp->ncmds; i++){
165 if(sgp->cmd == LC_SEGMENT)
166 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
167 mhp->filetype == MH_OBJECT){
168 sp = (struct section *)((char *)sgp +
169 sizeof(struct segment_command));
170 for(j = 0; j < sgp->nsects; j++){
171 if(strncmp(sp->sectname, sectname,
172 sizeof(sp->sectname)) == 0 &&
173 strncmp(sp->segname, segname,
174 sizeof(sp->segname)) == 0)
175 return(sp);
176 sp = (struct section *)((char *)sp +
177 sizeof(struct section));
178 }
179 }
180 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
181 }
182 return((struct section *)0);
183}
184
91447636
A
185/*
186 * This routine can operate against any 32 bit mach header.
187 */
188struct segment_command *
189getsegbynamefromheader(
1c79356b 190 struct mach_header *header,
91447636 191 const char *seg_name)
1c79356b
A
192{
193 struct segment_command *sgp;
91447636 194 unsigned long i;
1c79356b
A
195
196 sgp = (struct segment_command *)
197 ((char *)header + sizeof(struct mach_header));
198 for (i = 0; i < header->ncmds; i++){
199 if ( sgp->cmd == LC_SEGMENT
200 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
201 return sgp;
202 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
203 }
204 return (struct segment_command *)0;
205}
206
207
208/*
209 * For now at least, all the rest of this seems unused.
210 * NOTE: The constant in here for segment alignment is machine-dependent,
211 * so if you include this, define a machine dependent constant for it's
212 * value.
213 */
214static struct {
215 struct segment_command seg;
216 struct section sect;
217} fvm_data = {
218 {
219 LC_SEGMENT, // cmd
220 sizeof(fvm_data), // cmdsize
221 "__USER", // segname
222 0, // vmaddr
223 0, // vmsize
224 0, // fileoff
225 0, // filesize
226 VM_PROT_READ, // maxprot
227 VM_PROT_READ, // initprot,
228 1, // nsects
229 0 // flags
230 },
231 {
232 "", // sectname
233 "__USER", // segname
234 0, // addr
235 0, // size
236 0, // offset
237 4, // align
238 0, // reloff
239 0, // nreloc
91447636
A
240 0, // flags
241 0, // reserved1
242 0 // reserved2
1c79356b
A
243 }
244};
245
246struct segment_command *fvm_seg;
247
248static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
249static vm_offset_t getsizeofmacho(struct mach_header *header);
250
251/*
252 * Return the first segment_command in the header.
91447636
A
253 *
254 * This routine operates against the currently executing kernel only
1c79356b 255 */
91447636
A
256struct segment_command *
257firstseg(void)
1c79356b
A
258{
259 return firstsegfromheader(&_mh_execute_header);
260}
261
91447636
A
262/*
263 * This routine can operate against any 32 bit mach header, and returns a
264 * pointer to a 32 bit segment_command structure from the file prefixed by
265 * the header it is passed as its argument.
266 */
267struct segment_command *
268firstsegfromheader(struct mach_header *header)
1c79356b
A
269{
270 struct segment_command *sgp;
91447636 271 unsigned long i;
1c79356b
A
272
273 sgp = (struct segment_command *)
274 ((char *)header + sizeof(struct mach_header));
275 for (i = 0; i < header->ncmds; i++){
276 if (sgp->cmd == LC_SEGMENT)
277 return sgp;
278 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
279 }
280 return (struct segment_command *)0;
281}
282
91447636
A
283/*
284 * This routine operates against a 32 bit mach segment_command structure
285 * pointer from the currently executing kernel only, to obtain the
286 * sequentially next segment_command structure in the currently executing
287 * kernel
288 */
289struct segment_command *
290nextseg(struct segment_command *sgp)
1c79356b
A
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
91447636
A
306/*
307 * This routine operates against any 32 bit mach segment_command structure
308 * pointer and the provided 32 bit header, to obtain the sequentially next
309 * segment_command structure in that header.
310 */
311struct segment_command *
312nextsegfromheader(
1c79356b
A
313 struct mach_header *header,
314 struct segment_command *seg)
315{
316 struct segment_command *sgp;
91447636 317 unsigned long i;
1c79356b
A
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/*
91447636
A
342 * Return the address of the named Mach-O segment from the currently
343 * executing 32 bit kernel, or NULL.
1c79356b 344 */
91447636
A
345struct segment_command *
346getsegbyname(const char *seg_name)
1c79356b
A
347{
348 struct segment_command *this;
349
350 this = getsegbynamefromheader(&_mh_execute_header, seg_name);
351
352 /*
353 * For the kernel's header add on the faked segment for the
354 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
355 */
356 if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
357 this = fvm_seg;
358
359 return this;
360}
361
362/*
363 * This routine returns the a pointer the section structure of the named
91447636
A
364 * section in the named segment if it exists in the currently executing
365 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
1c79356b
A
366 */
367struct section *
368getsectbyname(
91447636
A
369 const char *segname,
370 const char *sectname)
1c79356b
A
371{
372 return(getsectbynamefromheader(
373 (struct mach_header *)&_mh_execute_header, segname, sectname));
374}
375
91447636
A
376/*
377 * This routine can operate against any 32 bit segment_command structure to
378 * return the first 32 bit section immediately following that structure. If
379 * there are no sections associated with the segment_command structure, it
380 * returns NULL.
381 */
382struct section *
383firstsect(struct segment_command *sgp)
1c79356b 384{
1c79356b
A
385 if (!sgp || sgp->nsects == 0)
386 return (struct section *)0;
387
388 return (struct section *)(sgp+1);
389}
390
91447636
A
391/*
392 * This routine can operate against any 32 bit segment_command structure and
393 * 32 bit section to return the next consecutive 32 bit section immediately
394 * following the 32 bit section provided. If there are no sections following
395 * the provided section, it returns NULL.
396 */
397struct section *
398nextsect(struct segment_command *sgp, struct section *sp)
1c79356b
A
399{
400 struct section *fsp = firstsect(sgp);
401
91447636 402 if (((unsigned long)(sp - fsp) + 1) >= sgp->nsects)
1c79356b
A
403 return (struct section *)0;
404
405 return sp+1;
406}
407
91447636
A
408/*
409 * This routine can operate against any 32 bit mach header to return the
410 * first occurring 32 bit fvmfile_command section. If one is not present,
411 * it returns NULL.
412 */
413static struct fvmfile_command *
414fvmfilefromheader(struct mach_header *header)
1c79356b
A
415{
416 struct fvmfile_command *fvp;
91447636 417 unsigned long i;
1c79356b
A
418
419 fvp = (struct fvmfile_command *)
420 ((char *)header + sizeof(struct mach_header));
421 for (i = 0; i < header->ncmds; i++){
422 if (fvp->cmd == LC_FVMFILE)
423 return fvp;
424 fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
425 }
426 return (struct fvmfile_command *)0;
427}
428
429/*
430 * Create a fake USER seg if a fvmfile_command is present.
91447636
A
431 *
432 * This routine operates against the currently executing kernel only
1c79356b 433 */
91447636
A
434struct segment_command *
435getfakefvmseg(void)
1c79356b
A
436{
437 struct segment_command *sgp = getsegbyname("__USER");
438 struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
439 struct section *sp;
440
441 if (sgp)
442 return sgp;
443
444 if (!fvp)
445 return (struct segment_command *)0;
446
447 fvm_seg = &fvm_data.seg;
448 sgp = fvm_seg;
449 sp = &fvm_data.sect;
450
451 sgp->vmaddr = fvp->header_addr;
452 sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
453
454 strcpy(sp->sectname, fvp->name.ptr);
455 sp->addr = sgp->vmaddr;
456 sp->size = sgp->vmsize;
457
458#if DEBUG
459 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
460 sp->sectname, sp->addr, sp->size);
55e303ae 461#endif /* DEBUG */
91447636
A
462
463 return sgp;
1c79356b
A
464}
465
466/*
467 * Figure out the size the size of the data associated with a
468 * loaded mach_header.
91447636
A
469 *
470 * This routine can operate against any 32 bit mach header.
1c79356b 471 */
91447636
A
472static vm_offset_t
473getsizeofmacho(struct mach_header *header)
1c79356b
A
474{
475 struct segment_command *sgp;
1c79356b
A
476 vm_offset_t last_addr;
477
478 last_addr = 0;
479 for ( sgp = firstsegfromheader(header)
480 ; sgp
481 ; sgp = nextsegfromheader(header, sgp))
482 {
483 if (sgp->fileoff + sgp->filesize > last_addr)
484 last_addr = sgp->fileoff + sgp->filesize;
485 }
486
487 return last_addr;
488}
489#endif /* !defined(KERNEL_PRELOAD) */