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