Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2340