Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/load.c

1/*
2 * Copyright (c) 2003 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 2.0 (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 * load.c - Functions for decoding a Mach-o Kernel.
24 *
25 * Copyright (c) 1998-2003 Apple Computer, Inc.
26 *
27 */
28
29#include <mach-o/fat.h>
30#include <mach-o/loader.h>
31#include <mach/machine/thread_status.h>
32
33#include <sl.h>
34
35static long DecodeSegment(long cmdBase, unsigned int*load_addr, unsigned int *load_size);
36static long DecodeUnixThread(long cmdBase, unsigned int *entry);
37static long DecodeSymbolTable(long cmdBase);
38
39
40static unsigned long gBinaryAddress;
41bool gHaveKernelCache;/* XXX aserebln: uninitialized? and only set to true, never to false */
42cpu_type_t archCpuType=CPU_TYPE_I386;
43
44// Public Functions
45
46long ThinFatFile(void **binary, unsigned long *length)
47{
48 unsigned long nfat, swapped, size = 0;
49 struct fat_header *fhp = (struct fat_header *)*binary;
50 struct fat_arch *fap =
51 (struct fat_arch *)((unsigned long)*binary + sizeof(struct fat_header));
52 cpu_type_t fapcputype;
53 uint32_t fapoffset;
54 uint32_t fapsize;
55
56 if (fhp->magic == FAT_MAGIC) {
57 nfat = fhp->nfat_arch;
58 swapped = 0;
59 } else if (fhp->magic == FAT_CIGAM) {
60 nfat = OSSwapInt32(fhp->nfat_arch);
61 swapped = 1;
62 } else {
63 return -1;
64 }
65
66 for (; nfat > 0; nfat--, fap++) {
67 if (swapped) {
68 fapcputype = OSSwapInt32(fap->cputype);
69 fapoffset = OSSwapInt32(fap->offset);
70 fapsize = OSSwapInt32(fap->size);
71 }
72else
73{
74fapcputype = fap->cputype;
75fapoffset = fap->offset;
76fapsize = fap->size;
77}
78
79 if (fapcputype == archCpuType) {
80 *binary = (void *) ((unsigned long)*binary + fapoffset);
81 size = fapsize;
82 break;
83 }
84 }
85
86 if (length != 0) *length = size;
87
88 return 0;
89}
90
91long DecodeMachO(void *binary, entry_t *rentry, char **raddr, int *rsize)
92{
93 struct mach_header *mH;
94 unsigned long ncmds, cmdBase, cmd, cmdsize, cmdstart;
95 // long headerBase, headerAddr, headerSize;
96 unsigned int vmaddr = ~0;
97 unsigned int vmend = 0;
98 unsigned long cnt;
99 long ret = -1;
100 unsigned int entry = 0;
101
102 gBinaryAddress = (unsigned long)binary;
103
104 mH = (struct mach_header *)(gBinaryAddress);
105 switch (archCpuType)
106{
107case CPU_TYPE_I386:
108if (mH->magic != MH_MAGIC) {
109error("Mach-O file has bad magic number\n");
110return -1;
111}
112cmdstart = (unsigned long)gBinaryAddress + sizeof(struct mach_header);
113break;
114case CPU_TYPE_X86_64:
115if (mH->magic != MH_MAGIC_64 && mH->magic == MH_MAGIC)
116return -1;
117if (mH->magic != MH_MAGIC_64) {
118error("Mach-O file has bad magic number\n");
119return -1;
120}
121cmdstart = (unsigned long)gBinaryAddress + sizeof(struct mach_header_64);
122break;
123default:
124error("Unknown CPU type\n");
125return -1;
126}
127
128 cmdBase = cmdstart;
129
130#if DEBUG
131 printf("magic: %x\n", (unsigned)mH->magic);
132 printf("cputype: %x\n", (unsigned)mH->cputype);
133 printf("cpusubtype: %x\n", (unsigned)mH->cpusubtype);
134 printf("filetype: %x\n", (unsigned)mH->filetype);
135 printf("ncmds: %x\n", (unsigned)mH->ncmds);
136 printf("sizeofcmds: %x\n", (unsigned)mH->sizeofcmds);
137 printf("flags: %x\n", (unsigned)mH->flags);
138 getchar();
139#endif
140
141 ncmds = mH->ncmds;
142
143 for (cnt = 0; cnt < ncmds; cnt++) {
144 cmd = ((long *)cmdBase)[0];
145 cmdsize = ((long *)cmdBase)[1];
146 unsigned int load_addr;
147 unsigned int load_size;
148
149 switch (cmd) {
150case LC_SEGMENT_64:
151 case LC_SEGMENT:
152 ret = DecodeSegment(cmdBase, &load_addr, &load_size);
153 if (ret == 0 && load_size != 0 && load_addr >= KERNEL_ADDR) {
154 vmaddr = MIN(vmaddr, load_addr);
155 vmend = MAX(vmend, load_addr + load_size);
156 }
157 break;
158
159 case LC_UNIXTHREAD:
160 ret = DecodeUnixThread(cmdBase, &entry);
161 break;
162
163 case LC_SYMTAB:
164 break;
165
166 default:
167#if NOTDEF
168 printf("Ignoring cmd type %d.\n", (unsigned)cmd);
169#endif
170 break;
171 }
172
173 if (ret != 0) return -1;
174
175 cmdBase += cmdsize;
176 }
177
178 *rentry = (entry_t)( (unsigned long) entry & 0x3fffffff );
179 *rsize = vmend - vmaddr;
180 *raddr = (char *)vmaddr;
181
182 cmdBase = cmdstart;
183 for (cnt = 0; cnt < ncmds; cnt++) {
184cmd = ((long *)cmdBase)[0];
185cmdsize = ((long *)cmdBase)[1];
186
187if(cmd==LC_SYMTAB)
188 if (DecodeSymbolTable(cmdBase)!=0)
189return -1;
190
191cmdBase += cmdsize;
192 }
193
194 return ret;
195}
196
197// Private Functions
198
199static long DecodeSegment(long cmdBase, unsigned int *load_addr, unsigned int *load_size)
200{
201 unsigned long vmaddr, fileaddr;
202 long vmsize, filesize;
203 char *segname;
204
205 if (((long *)cmdBase)[0]==LC_SEGMENT_64)
206 {
207 struct segment_command_64 *segCmd;
208
209 segCmd = (struct segment_command_64 *)cmdBase;
210
211 vmaddr = (segCmd->vmaddr & 0x3fffffff);
212 vmsize = segCmd->vmsize;
213 fileaddr = (gBinaryAddress + segCmd->fileoff);
214 filesize = segCmd->filesize;
215
216 segname=segCmd->segname;
217
218#ifdef DEBUG
219 printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
220 segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
221 (unsigned) segCmd->nsects, (unsigned)segCmd->flags);
222 getchar();
223#endif
224 }
225 else
226 {
227 struct segment_command *segCmd;
228
229 segCmd = (struct segment_command *)cmdBase;
230
231 vmaddr = (segCmd->vmaddr & 0x3fffffff);
232 vmsize = segCmd->vmsize;
233 fileaddr = (gBinaryAddress + segCmd->fileoff);
234 filesize = segCmd->filesize;
235
236 segname=segCmd->segname;
237
238#ifdef DEBUG
239 printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
240 segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
241 (unsigned) segCmd->nsects, (unsigned)segCmd->flags);
242 getchar();
243#endif
244 }
245
246 if (vmsize == 0 || filesize == 0) {
247 *load_addr = ~0;
248 *load_size = 0;
249 return 0;
250 }
251
252 if (! ((vmaddr >= KERNEL_ADDR &&
253 (vmaddr + vmsize) <= (KERNEL_ADDR + KERNEL_LEN)) ||
254 (vmaddr >= HIB_ADDR &&
255 (vmaddr + vmsize) <= (HIB_ADDR + HIB_LEN)))) {
256 stop("Kernel overflows available space");
257 }
258
259 if (vmsize && ((strcmp(segname, "__PRELINK_INFO") == 0) || (strcmp(segname, "__PRELINK") == 0)))
260 gHaveKernelCache = true;
261
262 // Copy from file load area.
263 if (vmsize>0 && filesize>0)
264 bcopy((char *)fileaddr, (char *)vmaddr, vmsize>filesize?filesize:vmsize);
265
266 // Zero space at the end of the segment.
267 if (vmsize > filesize)
268 bzero((char *)(vmaddr + filesize), vmsize - filesize);
269
270 *load_addr = vmaddr;
271 *load_size = vmsize;
272
273 return 0;
274}
275
276static long DecodeUnixThread(long cmdBase, unsigned int *entry)
277{
278switch (archCpuType)
279{
280case CPU_TYPE_I386:
281{
282i386_thread_state_t *i386ThreadState;
283
284i386ThreadState = (i386_thread_state_t *)
285(cmdBase + sizeof(struct thread_command) + 8);
286
287*entry = i386ThreadState->eip;
288return 0;
289}
290
291case CPU_TYPE_X86_64:
292{
293x86_thread_state64_t *x86_64ThreadState;
294
295x86_64ThreadState = (x86_thread_state64_t *)
296(cmdBase + sizeof(struct thread_command) + 8);
297
298*entry = x86_64ThreadState->rip;
299return 0;
300}
301
302default:
303error("Unknown CPU type\n");
304return -1;
305}
306}
307
308static long DecodeSymbolTable(long cmdBase)
309{
310 struct symtab_command *symTab, *symTableSave;
311 long tmpAddr, symsSize, totalSize;
312 long gSymbolTableAddr;
313 long gSymbolTableSize;
314
315 symTab = (struct symtab_command *)cmdBase;
316
317#if DEBUG
318 printf("symoff: %x, nsyms: %x, stroff: %x, strsize: %x\n",
319 symTab->symoff, symTab->nsyms, symTab->stroff, symTab->strsize);
320 getchar();
321#endif
322
323 symsSize = symTab->stroff - symTab->symoff;
324 totalSize = symsSize + symTab->strsize;
325
326 gSymbolTableSize = totalSize + sizeof(struct symtab_command);
327 gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);
328 // Add the SymTab to the memory-map.
329 AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize, -1);
330
331 symTableSave = (struct symtab_command *)gSymbolTableAddr;
332 tmpAddr = gSymbolTableAddr + sizeof(struct symtab_command);
333
334 symTableSave->symoff = tmpAddr;
335 symTableSave->nsyms = symTab->nsyms;
336 symTableSave->stroff = tmpAddr + symsSize;
337 symTableSave->strsize = symTab->strsize;
338
339 bcopy((char *)(gBinaryAddress + symTab->symoff),
340(char *)tmpAddr, totalSize);
341 return 0;
342}
343

Archive Download this file

Revision: 1053