]>
Commit | Line | Data |
---|---|---|
14c7c974 | 1 | /* |
f083c6c3 | 2 | * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. |
14c7c974 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
f083c6c3 A |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14c7c974 A |
14 | * |
15 | * The Original Code and all software distributed under the License are | |
f083c6c3 | 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
f083c6c3 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
14c7c974 A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
f083c6c3 A |
26 | * load.c - Functions for decoding a Mach-o Kernel. |
27 | * | |
28 | * Copyright (c) 1998-2003 Apple Computer, Inc. | |
29 | * | |
14c7c974 A |
30 | */ |
31 | ||
14c7c974 | 32 | #include <mach-o/fat.h> |
f083c6c3 A |
33 | #include <mach-o/loader.h> |
34 | #include <mach/machine/thread_status.h> | |
14c7c974 | 35 | |
f083c6c3 | 36 | #include <sl.h> |
75b89a82 | 37 | |
f083c6c3 A |
38 | static long DecodeSegment(long cmdBase, unsigned int*load_addr, unsigned int *load_size); |
39 | static long DecodeUnixThread(long cmdBase, unsigned int *entry); | |
14c7c974 | 40 | |
14c7c974 | 41 | |
f083c6c3 A |
42 | static unsigned long gBinaryAddress; |
43 | BOOL gHaveKernelCache; | |
75b89a82 | 44 | |
f083c6c3 | 45 | // Public Functions |
14c7c974 | 46 | |
f083c6c3 | 47 | long ThinFatFile(void **binary, unsigned long *length) |
14c7c974 | 48 | { |
f083c6c3 A |
49 | unsigned long nfat, swapped, size = 0; |
50 | struct fat_header *fhp = (struct fat_header *)*binary; | |
51 | struct fat_arch *fap = | |
52 | (struct fat_arch *)((unsigned long)*binary + sizeof(struct fat_header)); | |
53 | ||
54 | if (fhp->magic == FAT_MAGIC) { | |
55 | nfat = fhp->nfat_arch; | |
56 | swapped = 0; | |
57 | } else if (fhp->magic == FAT_CIGAM) { | |
58 | nfat = NXSwapInt(fhp->nfat_arch); | |
59 | swapped = 1; | |
60 | } else { | |
61 | return -1; | |
62 | } | |
63 | ||
64 | for (; nfat > 0; nfat--, fap++) { | |
65 | if (swapped) { | |
66 | fap->cputype = NXSwapInt(fap->cputype); | |
67 | fap->offset = NXSwapInt(fap->offset); | |
68 | fap->size = NXSwapInt(fap->size); | |
14c7c974 | 69 | } |
75b89a82 | 70 | |
f083c6c3 A |
71 | if (fap->cputype == CPU_TYPE_I386) { |
72 | *binary = (void *) ((unsigned long)*binary + fap->offset); | |
73 | size = fap->size; | |
74 | break; | |
14c7c974 | 75 | } |
f083c6c3 A |
76 | } |
77 | ||
78 | if (length != 0) *length = size; | |
79 | ||
80 | return 0; | |
14c7c974 A |
81 | } |
82 | ||
f083c6c3 | 83 | long DecodeMachO(void *binary, entry_t *rentry, char **raddr, int *rsize) |
14c7c974 | 84 | { |
f083c6c3 A |
85 | struct mach_header *mH; |
86 | unsigned long ncmds, cmdBase, cmd, cmdsize; | |
87 | // long headerBase, headerAddr, headerSize; | |
88 | unsigned int vmaddr = ~0; | |
89 | unsigned int vmend = 0; | |
90 | unsigned long cnt; | |
91 | long ret = -1; | |
92 | unsigned int entry; | |
93 | ||
94 | gBinaryAddress = (unsigned long)binary; | |
95 | ||
96 | // headerBase = gBinaryAddress; | |
97 | cmdBase = (unsigned long)gBinaryAddress + sizeof(struct mach_header); | |
98 | ||
99 | mH = (struct mach_header *)(gBinaryAddress); | |
100 | if (mH->magic != MH_MAGIC) { | |
101 | error("Mach-O file has bad magic number\n"); | |
102 | return -1; | |
103 | } | |
104 | ||
105 | #if NOTDEF | |
106 | printf("magic: %x\n", (unsigned)mH->magic); | |
107 | printf("cputype: %x\n", (unsigned)mH->cputype); | |
108 | printf("cpusubtype: %x\n", (unsigned)mH->cpusubtype); | |
109 | printf("filetype: %x\n", (unsigned)mH->filetype); | |
110 | printf("ncmds: %x\n", (unsigned)mH->ncmds); | |
111 | printf("sizeofcmds: %x\n", (unsigned)mH->sizeofcmds); | |
112 | printf("flags: %x\n", (unsigned)mH->flags); | |
113 | getc(); | |
14c7c974 | 114 | #endif |
f083c6c3 A |
115 | |
116 | ncmds = mH->ncmds; | |
117 | ||
118 | for (cnt = 0; cnt < ncmds; cnt++) { | |
119 | cmd = ((long *)cmdBase)[0]; | |
120 | cmdsize = ((long *)cmdBase)[1]; | |
121 | unsigned int load_addr; | |
122 | unsigned int load_size; | |
123 | ||
124 | switch (cmd) { | |
125 | ||
126 | case LC_SEGMENT: | |
127 | ret = DecodeSegment(cmdBase, &load_addr, &load_size); | |
128 | if (ret == 0 && load_size != 0) { | |
129 | vmaddr = min(vmaddr, load_addr); | |
130 | vmend = max(vmend, load_addr + load_size); | |
131 | } | |
132 | break; | |
133 | ||
134 | case LC_UNIXTHREAD: | |
135 | ret = DecodeUnixThread(cmdBase, &entry); | |
136 | break; | |
137 | ||
138 | default: | |
139 | #if NOTDEF | |
140 | printf("Ignoring cmd type %d.\n", (unsigned)cmd); | |
14c7c974 | 141 | #endif |
f083c6c3 | 142 | break; |
75b89a82 | 143 | } |
f083c6c3 A |
144 | |
145 | if (ret != 0) return -1; | |
146 | ||
147 | cmdBase += cmdsize; | |
148 | } | |
149 | ||
150 | *rentry = (entry_t)( (unsigned long) entry & 0x3fffffff ); | |
151 | *rsize = vmend - vmaddr; | |
152 | *raddr = (char *)vmaddr; | |
153 | ||
154 | return ret; | |
14c7c974 A |
155 | } |
156 | ||
f083c6c3 | 157 | // Private Functions |
14c7c974 | 158 | |
f083c6c3 | 159 | static long DecodeSegment(long cmdBase, unsigned int *load_addr, unsigned int *load_size) |
14c7c974 | 160 | { |
f083c6c3 A |
161 | struct segment_command *segCmd; |
162 | unsigned long vmaddr, fileaddr; | |
163 | long vmsize, filesize; | |
75b89a82 | 164 | |
f083c6c3 A |
165 | segCmd = (struct segment_command *)cmdBase; |
166 | ||
167 | vmaddr = (segCmd->vmaddr & 0x3fffffff); | |
168 | vmsize = segCmd->vmsize; | |
169 | ||
170 | fileaddr = (gBinaryAddress + segCmd->fileoff); | |
171 | filesize = segCmd->filesize; | |
172 | ||
173 | if (filesize == 0) { | |
174 | *load_addr = ~0; | |
175 | *load_size = 0; | |
176 | return 0; | |
177 | } | |
178 | ||
179 | #if NOTDEF | |
180 | printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n", | |
181 | segCmd->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize, | |
182 | (unsigned) segCmd->nsects, (unsigned)segCmd->flags); | |
183 | getc(); | |
14c7c974 | 184 | #endif |
f083c6c3 A |
185 | |
186 | if (vmaddr < KERNEL_ADDR || | |
187 | (vmaddr + vmsize) > (KERNEL_ADDR + KERNEL_LEN)) { | |
188 | stop("Kernel overflows available space"); | |
189 | } | |
190 | ||
191 | if (vmsize && (strcmp(segCmd->segname, "__PRELINK") == 0)) { | |
192 | gHaveKernelCache = 1; | |
193 | } | |
194 | ||
195 | // Copy from file load area. | |
196 | bcopy((char *)fileaddr, (char *)vmaddr, filesize); | |
197 | ||
198 | // Zero space at the end of the segment. | |
199 | bzero((char *)(vmaddr + filesize), vmsize - filesize); | |
14c7c974 | 200 | |
f083c6c3 A |
201 | *load_addr = vmaddr; |
202 | *load_size = vmsize; | |
47b0a8bd | 203 | |
f083c6c3 A |
204 | return 0; |
205 | } | |
14c7c974 | 206 | |
14c7c974 | 207 | |
f083c6c3 A |
208 | static long DecodeUnixThread(long cmdBase, unsigned int *entry) |
209 | { | |
210 | i386_thread_state_t *i386ThreadState; | |
211 | ||
212 | i386ThreadState = (i386_thread_state_t *) | |
213 | (cmdBase + sizeof(struct thread_command) + 8); | |
214 | ||
215 | *entry = i386ThreadState->eip; | |
216 | ||
217 | return 0; | |
14c7c974 | 218 | } |
f083c6c3 | 219 |