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