Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 976