]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/mach_header.c
xnu-344.23.tar.gz
[apple/xnu.git] / bsd / kern / mach_header.c
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
39 extern struct mach_header _mh_execute_header;
40
41 struct section *getsectbynamefromheader(
42 struct mach_header *header,
43 char *seg_name,
44 char *sect_name);
45 struct segment_command *getsegbynamefromheader(
46 struct mach_header *header,
47 char *seg_name);
48
49 /*
50 * return the last address (first avail)
51 */
52 vm_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 /* [ */
72 struct mach_header **
73 getmachheaders(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 */
90 void *
91 getsectdatafromheader(
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 */
116 void *
117 getsegdatafromheader(
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 */
140 struct section *
141 getsectbynamefromheader(
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
173 struct 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 */
198 static 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
228 struct segment_command *fvm_seg;
229
230 static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
231 static vm_offset_t getsizeofmacho(struct mach_header *header);
232
233 /*
234 * Return the first segment_command in the header.
235 */
236 struct segment_command *firstseg(void)
237 {
238 return firstsegfromheader(&_mh_execute_header);
239 }
240
241 struct 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
256 struct 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
272 struct 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 */
304 struct 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 */
325 struct section *
326 getsectbyname(
327 char *segname,
328 char *sectname)
329 {
330 return(getsectbynamefromheader(
331 (struct mach_header *)&_mh_execute_header, segname, sectname));
332 }
333
334 struct 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
344 struct 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
354 static 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 */
372 struct 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 */
405 static 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) */