]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/mach_header.c
xnu-124.1.tar.gz
[apple/xnu.git] / bsd / kern / 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#if !defined(KERNEL_PRELOAD)
37#include <kern/mach_header.h>
38
39extern struct mach_header _mh_execute_header;
40
41struct section *getsectbynamefromheader(
42 struct mach_header *header,
43 char *seg_name,
44 char *sect_name);
45struct segment_command *getsegbynamefromheader(
46 struct mach_header *header,
47 char *seg_name);
48
49/*
50 * return the last address (first avail)
51 */
52vm_offset_t getlastaddr(void)
53{
54 struct segment_command *sgp;
55 vm_offset_t last_addr = 0;
56 struct mach_header *header = &_mh_execute_header;
57 int i;
58
59 sgp = (struct segment_command *)
60 ((char *)header + sizeof(struct mach_header));
61 for (i = 0; i < header->ncmds; i++){
62 if ( sgp->cmd == LC_SEGMENT) {
63 if (sgp->vmaddr + sgp->vmsize > last_addr)
64 last_addr = sgp->vmaddr + sgp->vmsize;
65 }
66 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
67 }
68 return last_addr;
69}
70
71#if FIXME /* [ */
72struct mach_header **
73getmachheaders(void)
74{
75 extern struct mach_header _mh_execute_header;
76 struct mach_header **tl;
77 tl = (struct mach_header **)malloc(2*sizeof(struct mach_header *));
78 tl[0] = &_mh_execute_header;
79 tl[1] = (struct mach_header *)0;
80 return tl;
81}
82#endif /* FIXME ] */
83
84/*
85 * This routine returns the a pointer to the data for the named section in the
86 * named segment if it exist in the mach header passed to it. Also it returns
87 * the size of the section data indirectly through the pointer size. Otherwise
88 * it returns zero for the pointer and the size.
89 */
90void *
91getsectdatafromheader(
92 struct mach_header *mhp,
93 char *segname,
94 char *sectname,
95 int *size)
96{
97 const struct section *sp;
98 void *result;
99
100 sp = getsectbynamefromheader(mhp, segname, sectname);
101 if(sp == (struct section *)0){
102 *size = 0;
103 return((char *)0);
104 }
105 *size = sp->size;
106 result = (void *)sp->addr;
107 return result;
108}
109
110/*
111 * This routine returns the a pointer to the data for the named segment
112 * if it exist in the mach header passed to it. Also it returns
113 * the size of the segment data indirectly through the pointer size.
114 * Otherwise it returns zero for the pointer and the size.
115 */
116void *
117getsegdatafromheader(
118 struct mach_header *mhp,
119 char *segname,
120 int *size)
121{
122 const struct segment_command *sc;
123 void *result;
124
125 sc = getsegbynamefromheader(mhp, segname);
126 if(sc == (struct segment_command *)0){
127 *size = 0;
128 return((char *)0);
129 }
130 *size = sc->vmsize;
131 result = (void *)sc->vmaddr;
132 return result;
133}
134
135/*
136 * This routine returns the section structure for the named section in the
137 * named segment for the mach_header pointer passed to it if it exist.
138 * Otherwise it returns zero.
139 */
140struct section *
141getsectbynamefromheader(
142 struct mach_header *mhp,
143 char *segname,
144 char *sectname)
145{
146 struct segment_command *sgp;
147 struct section *sp;
148 long i, j;
149
150 sgp = (struct segment_command *)
151 ((char *)mhp + sizeof(struct mach_header));
152 for(i = 0; i < mhp->ncmds; i++){
153 if(sgp->cmd == LC_SEGMENT)
154 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
155 mhp->filetype == MH_OBJECT){
156 sp = (struct section *)((char *)sgp +
157 sizeof(struct segment_command));
158 for(j = 0; j < sgp->nsects; j++){
159 if(strncmp(sp->sectname, sectname,
160 sizeof(sp->sectname)) == 0 &&
161 strncmp(sp->segname, segname,
162 sizeof(sp->segname)) == 0)
163 return(sp);
164 sp = (struct section *)((char *)sp +
165 sizeof(struct section));
166 }
167 }
168 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
169 }
170 return((struct section *)0);
171}
172
173struct segment_command *getsegbynamefromheader(
174 struct mach_header *header,
175 char *seg_name)
176{
177 struct segment_command *sgp;
178 int i;
179
180 sgp = (struct segment_command *)
181 ((char *)header + sizeof(struct mach_header));
182 for (i = 0; i < header->ncmds; i++){
183 if ( sgp->cmd == LC_SEGMENT
184 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
185 return sgp;
186 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
187 }
188 return (struct segment_command *)0;
189}
190
191
192/*
193 * For now at least, all the rest of this seems unused.
194 * NOTE: The constant in here for segment alignment is machine-dependent,
195 * so if you include this, define a machine dependent constant for it's
196 * value.
197 */
198static struct {
199 struct segment_command seg;
200 struct section sect;
201} fvm_data = {
202 {
203 LC_SEGMENT, // cmd
204 sizeof(fvm_data), // cmdsize
205 "__USER", // segname
206 0, // vmaddr
207 0, // vmsize
208 0, // fileoff
209 0, // filesize
210 VM_PROT_READ, // maxprot
211 VM_PROT_READ, // initprot,
212 1, // nsects
213 0 // flags
214 },
215 {
216 "", // sectname
217 "__USER", // segname
218 0, // addr
219 0, // size
220 0, // offset
221 4, // align
222 0, // reloff
223 0, // nreloc
224 0 // flags
225 }
226};
227
228struct segment_command *fvm_seg;
229
230static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
231static vm_offset_t getsizeofmacho(struct mach_header *header);
232
233/*
234 * Return the first segment_command in the header.
235 */
236struct segment_command *firstseg(void)
237{
238 return firstsegfromheader(&_mh_execute_header);
239}
240
241struct segment_command *firstsegfromheader(struct mach_header *header)
242{
243 struct segment_command *sgp;
244 int i;
245
246 sgp = (struct segment_command *)
247 ((char *)header + sizeof(struct mach_header));
248 for (i = 0; i < header->ncmds; i++){
249 if (sgp->cmd == LC_SEGMENT)
250 return sgp;
251 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
252 }
253 return (struct segment_command *)0;
254}
255
256struct segment_command *nextseg(struct segment_command *sgp)
257{
258 struct segment_command *this;
259
260 this = nextsegfromheader(&_mh_execute_header, sgp);
261
262 /*
263 * For the kernel's header add on the faked segment for the
264 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
265 */
266 if (!this && sgp != fvm_seg)
267 this = fvm_seg;
268
269 return this;
270}
271
272struct segment_command *nextsegfromheader(
273 struct mach_header *header,
274 struct segment_command *seg)
275{
276 struct segment_command *sgp;
277 int i;
278
279 sgp = (struct segment_command *)
280 ((char *)header + sizeof(struct mach_header));
281 for (i = 0; i < header->ncmds; i++) {
282 if (sgp == seg)
283 break;
284 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
285 }
286
287 if (i == header->ncmds)
288 return (struct segment_command *)0;
289
290 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
291 for (; i < header->ncmds; i++) {
292 if (sgp->cmd == LC_SEGMENT)
293 return sgp;
294 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
295 }
296
297 return (struct segment_command *)0;
298}
299
300
301/*
302 * Return the address of the named Mach-O segment, or NULL.
303 */
304struct segment_command *getsegbyname(char *seg_name)
305{
306 struct segment_command *this;
307
308 this = getsegbynamefromheader(&_mh_execute_header, seg_name);
309
310 /*
311 * For the kernel's header add on the faked segment for the
312 * USER boot code identified by a FVMFILE_COMMAND in the mach header.
313 */
314 if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
315 this = fvm_seg;
316
317 return this;
318}
319
320/*
321 * This routine returns the a pointer the section structure of the named
322 * section in the named segment if it exist in the mach executable it is
323 * linked into. Otherwise it returns zero.
324 */
325struct section *
326getsectbyname(
327 char *segname,
328 char *sectname)
329{
330 return(getsectbynamefromheader(
331 (struct mach_header *)&_mh_execute_header, segname, sectname));
332}
333
334struct section *firstsect(struct segment_command *sgp)
335{
336 struct section *sp;
337
338 if (!sgp || sgp->nsects == 0)
339 return (struct section *)0;
340
341 return (struct section *)(sgp+1);
342}
343
344struct section *nextsect(struct segment_command *sgp, struct section *sp)
345{
346 struct section *fsp = firstsect(sgp);
347
348 if (sp - fsp >= sgp->nsects-1)
349 return (struct section *)0;
350
351 return sp+1;
352}
353
354static struct fvmfile_command *fvmfilefromheader(struct mach_header *header)
355{
356 struct fvmfile_command *fvp;
357 int i;
358
359 fvp = (struct fvmfile_command *)
360 ((char *)header + sizeof(struct mach_header));
361 for (i = 0; i < header->ncmds; i++){
362 if (fvp->cmd == LC_FVMFILE)
363 return fvp;
364 fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
365 }
366 return (struct fvmfile_command *)0;
367}
368
369/*
370 * Create a fake USER seg if a fvmfile_command is present.
371 */
372struct segment_command *getfakefvmseg(void)
373{
374 struct segment_command *sgp = getsegbyname("__USER");
375 struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
376 struct section *sp;
377
378 if (sgp)
379 return sgp;
380
381 if (!fvp)
382 return (struct segment_command *)0;
383
384 fvm_seg = &fvm_data.seg;
385 sgp = fvm_seg;
386 sp = &fvm_data.sect;
387
388 sgp->vmaddr = fvp->header_addr;
389 sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
390
391 strcpy(sp->sectname, fvp->name.ptr);
392 sp->addr = sgp->vmaddr;
393 sp->size = sgp->vmsize;
394
395#if DEBUG
396 printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
397 sp->sectname, sp->addr, sp->size);
398#endif DEBUG
399}
400
401/*
402 * Figure out the size the size of the data associated with a
403 * loaded mach_header.
404 */
405static vm_offset_t getsizeofmacho(struct mach_header *header)
406{
407 struct segment_command *sgp;
408 struct section *sp;
409 vm_offset_t last_addr;
410
411 last_addr = 0;
412 for ( sgp = firstsegfromheader(header)
413 ; sgp
414 ; sgp = nextsegfromheader(header, sgp))
415 {
416 if (sgp->fileoff + sgp->filesize > last_addr)
417 last_addr = sgp->fileoff + sgp->filesize;
418 }
419
420 return last_addr;
421}
422#endif /* !defined(KERNEL_PRELOAD) */