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

Archive Download this file

Revision: 2858