Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2004