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