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 | ␊ |
37 | static long DecodeSegment(long cmdBase, unsigned int*load_addr, unsigned int *load_size);␊ |
38 | static long DecodeUnixThread(long cmdBase, unsigned int *entry);␊ |
39 | static long DecodeSymbolTable(long cmdBase);␊ |
40 | ␊ |
41 | ␊ |
42 | static unsigned long gBinaryAddress;␊ |
43 | bool gHaveKernelCache; //Azi: bs!! - XXX aserebln: uninitialized? and only set to true, never to false␊ |
44 | cpu_type_t archCpuType=CPU_TYPE_I386;␊ |
45 | ␊ |
46 | // Public Functions␊ |
47 | ␊ |
48 | long 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 | }␊ |
74 | ␉else␊ |
75 | ␉{␊ |
76 | ␉␉fapcputype = fap->cputype;␊ |
77 | ␉␉fapoffset = fap->offset;␊ |
78 | ␉␉fapsize = 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 | ␊ |
93 | long 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 | ␉{␊ |
109 | ␉␉case CPU_TYPE_I386:␊ |
110 | ␉␉␉if (mH->magic != MH_MAGIC) {␊ |
111 | ␉␉␉␉error("Mach-O file has bad magic number\n");␊ |
112 | ␉␉␉␉return -1;␊ |
113 | ␉␉␉}␊ |
114 | ␉␉␉cmdstart = (unsigned long)gBinaryAddress + sizeof(struct mach_header);␊ |
115 | ␉␉␉break;␊ |
116 | ␉␉case CPU_TYPE_X86_64:␊ |
117 | ␉␉␉if (mH->magic != MH_MAGIC_64 && mH->magic == MH_MAGIC) ␊ |
118 | ␉␉␉␉return -1;␊ |
119 | ␉␉␉if (mH->magic != MH_MAGIC_64) {␊ |
120 | ␉␉␉␉error("Mach-O file has bad magic number\n");␊ |
121 | ␉␉␉␉return -1;␊ |
122 | ␉␉␉}␊ |
123 | ␉␉␉cmdstart = (unsigned long)gBinaryAddress + sizeof(struct mach_header_64);␊ |
124 | ␉␉␉break;␊ |
125 | ␉␉default:␊ |
126 | ␉␉␉error("Unknown CPU type\n");␊ |
127 | ␉␉␉return -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) {␊ |
152 | ␉case 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++) {␊ |
186 | ␉cmd = ((long *)cmdBase)[0];␊ |
187 | ␉cmdsize = ((long *)cmdBase)[1];␊ |
188 | ␉␉␊ |
189 | ␉if(cmd==LC_SYMTAB) ␊ |
190 | ␉ if (DecodeSymbolTable(cmdBase)!=0)␊ |
191 | ␉␉return -1;␊ |
192 | ␉␉␊ |
193 | ␉cmdBase += cmdsize;␊ |
194 | }␉␊ |
195 | ␉␊ |
196 | return ret;␊ |
197 | }␊ |
198 | ␊ |
199 | // Private Functions␊ |
200 | ␊ |
201 | static 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 | #ifdef DEBUG␊ |
220 | printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",␊ |
221 | ␉ segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,␊ |
222 | (unsigned) segCmd->nsects, (unsigned)segCmd->flags);␊ |
223 | getc();␊ |
224 | #endif␊ |
225 | }␊ |
226 | else␊ |
227 | {␊ |
228 | ␉ struct segment_command *segCmd;␊ |
229 | ␊ |
230 | ␉ segCmd = (struct segment_command *)cmdBase;␊ |
231 | ␊ |
232 | ␉ vmaddr = (segCmd->vmaddr & 0x3fffffff);␊ |
233 | ␉ vmsize = segCmd->vmsize;␊ |
234 | ␉ fileaddr = (gBinaryAddress + segCmd->fileoff);␊ |
235 | ␉ filesize = segCmd->filesize;␊ |
236 | ␉ ␊ |
237 | ␉ segname=segCmd->segname;␊ |
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 | getc();␊ |
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 | //Azi: check for prelinked kernel.␊ |
260 | // segname:␊ |
261 | // Leo 10.5.8: __TEXT, __DATA, __HIB, __DESC, __VECTORS, __KLD, __PRELINK, __LINKEDIT␊ |
262 | // Snow 10.6.6: __TEXT, __DATA, __INITGDT, __INITPT, __DESC, __VECTORS, __HIB, __SLEEP,␊ |
263 | // __KLD, __PRELINK_TEXT, __PRELINK_STATE, __PRELINK_INFO, __LINKEDIT␊ |
264 | if (vmsize && ((strcmp(segname, "__PRELINK") == 0)␊ |
265 | || (strcmp(segname, "__PRELINK_TEXT") == 0))) //Azi: TEXT, STATE or INFO ??␊ |
266 | gHaveKernelCache = true;␊ |
267 | ␊ |
268 | // Copy from file load area.␊ |
269 | if (vmsize>0 && filesize>0)␊ |
270 | ␉ bcopy((char *)fileaddr, (char *)vmaddr, vmsize>filesize?filesize:vmsize);␊ |
271 | ␊ |
272 | // Zero space at the end of the segment.␊ |
273 | if (vmsize > filesize)␊ |
274 | bzero((char *)(vmaddr + filesize), vmsize - filesize);␊ |
275 | ␊ |
276 | *load_addr = vmaddr;␊ |
277 | *load_size = vmsize;␊ |
278 | ␊ |
279 | return 0;␊ |
280 | }␊ |
281 | ␊ |
282 | static long DecodeUnixThread(long cmdBase, unsigned int *entry)␊ |
283 | {␊ |
284 | ␉switch (archCpuType)␊ |
285 | ␉{␊ |
286 | ␉␉case CPU_TYPE_I386:␊ |
287 | ␉␉{␊ |
288 | ␉␉␉i386_thread_state_t *i386ThreadState;␊ |
289 | ␊ |
290 | ␉␉␉i386ThreadState = (i386_thread_state_t *)␊ |
291 | ␉␉␉␉(cmdBase + sizeof(struct thread_command) + 8);␊ |
292 | ␊ |
293 | ␉␉#if defined(__DARWIN_UNIX03) && __DARWIN_UNIX03␊ |
294 | ␉␉␉*entry = i386ThreadState->__eip;␊ |
295 | ␉␉#else␊ |
296 | ␉␉␉*entry = i386ThreadState->eip;␊ |
297 | ␉␉#endif␊ |
298 | ␉␉␉return 0;␊ |
299 | ␉␉}␊ |
300 | ␉␉␉␊ |
301 | ␉␉case CPU_TYPE_X86_64:␊ |
302 | ␉␉{␊ |
303 | ␉␉␉x86_thread_state64_t *x86_64ThreadState;␊ |
304 | ␉␉␉␊ |
305 | ␉␉␉x86_64ThreadState = (x86_thread_state64_t *)␊ |
306 | ␉␉␉(cmdBase + sizeof(struct thread_command) + 8);␊ |
307 | ␉␉␉␊ |
308 | ␉␉#if defined(__DARWIN_UNIX03) && __DARWIN_UNIX03␊ |
309 | ␉␉␉*entry = x86_64ThreadState->__rip;␊ |
310 | ␉␉#else␊ |
311 | ␉␉␉*entry = x86_64ThreadState->rip;␊ |
312 | ␉␉#endif␊ |
313 | ␉␉␉return 0;␊ |
314 | ␉␉}␊ |
315 | ␉␉␉␊ |
316 | ␉␉default:␊ |
317 | ␉␉␉error("Unknown CPU type\n");␊ |
318 | ␉␉␉return -1;␊ |
319 | ␉}␊ |
320 | }␊ |
321 | ␊ |
322 | static long DecodeSymbolTable(long cmdBase)␊ |
323 | {␊ |
324 | struct symtab_command *symTab, *symTableSave;␊ |
325 | long tmpAddr, symsSize, totalSize;␊ |
326 | long gSymbolTableAddr;␊ |
327 | long gSymbolTableSize;␊ |
328 | ␊ |
329 | symTab = (struct symtab_command *)cmdBase;␊ |
330 | ␊ |
331 | #ifdef DEBUG␊ |
332 | printf("symoff: %x, nsyms: %x, stroff: %x, strsize: %x\n",␊ |
333 | ␉ symTab->symoff, symTab->nsyms, symTab->stroff, symTab->strsize);␊ |
334 | ␉getc ();␊ |
335 | #endif␊ |
336 | ␊ |
337 | symsSize = symTab->stroff - symTab->symoff;␊ |
338 | totalSize = symsSize + symTab->strsize;␊ |
339 | ␊ |
340 | gSymbolTableSize = totalSize + sizeof(struct symtab_command);␊ |
341 | gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);␊ |
342 | // Add the SymTab to the memory-map.␊ |
343 | AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize, -1);␊ |
344 | ␊ |
345 | symTableSave = (struct symtab_command *)gSymbolTableAddr;␊ |
346 | tmpAddr = gSymbolTableAddr + sizeof(struct symtab_command);␊ |
347 | ␊ |
348 | symTableSave->symoff = tmpAddr;␊ |
349 | symTableSave->nsyms = symTab->nsyms;␊ |
350 | symTableSave->stroff = tmpAddr + symsSize;␊ |
351 | symTableSave->strsize = symTab->strsize;␊ |
352 | ␉␊ |
353 | bcopy((char *)(gBinaryAddress + symTab->symoff),␊ |
354 | ␉(char *)tmpAddr, totalSize);␊ |
355 | return 0;␊ |
356 | }␊ |
357 | |