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