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