]> git.saurik.com Git - apple/xnu.git/blame - libkern/kernel_mach_header.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libkern / kernel_mach_header.c
CommitLineData
b0d623f7
A
1/*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
b0d623f7
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
b0d623f7
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
b0d623f7
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * File: libkern/kernel_mach_header.c
30 *
31 * Functions for accessing mach-o headers.
32 *
33 * NOTE: This file supports only kernel mach headers at the present
34 * time; it's primary use is by kld, and all externally
35 * referenced routines at the present time operate against
36 * the kernel mach header _mh_execute_header, which is the
0a7de745 37 * header for the currently executing kernel.
b0d623f7
A
38 *
39 */
40
41#include <vm/vm_map.h>
42#include <vm/vm_kern.h>
43#include <libkern/kernel_mach_header.h>
0a7de745 44#include <string.h> // from libsa
b0d623f7
A
45
46/*
47 * return the last address (first avail)
48 *
49 * This routine operates against the currently executing kernel only
50 */
51vm_offset_t
52getlastaddr(void)
53{
0a7de745
A
54 kernel_segment_command_t *sgp;
55 vm_offset_t last_addr = 0;
b0d623f7
A
56 kernel_mach_header_t *header = &_mh_execute_header;
57 unsigned long i;
58
59 sgp = (kernel_segment_command_t *)
0a7de745
A
60 ((uintptr_t)header + sizeof(kernel_mach_header_t));
61 for (i = 0; i < header->ncmds; i++) {
316670eb 62 if (sgp->cmd == LC_SEGMENT_KERNEL) {
0a7de745 63 if (sgp->vmaddr + sgp->vmsize > last_addr) {
b0d623f7 64 last_addr = sgp->vmaddr + sgp->vmsize;
0a7de745 65 }
b0d623f7
A
66 }
67 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
68 }
69 return last_addr;
70}
71
6d2010ae 72/*
316670eb
A
73 * Find the specified load command in the Mach-O headers, and return
74 * the command. If there is no such load command, NULL is returned.
6d2010ae
A
75 */
76void *
0a7de745
A
77getcommandfromheader(kernel_mach_header_t *mhp, uint32_t cmd)
78{
316670eb 79 struct load_command *lcp;
6d2010ae
A
80 unsigned long i;
81
316670eb 82 lcp = (struct load_command *) (mhp + 1);
0a7de745
A
83 for (i = 0; i < mhp->ncmds; i++) {
84 if (lcp->cmd == cmd) {
316670eb 85 return (void *)lcp;
6d2010ae
A
86 }
87
316670eb 88 lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize);
6d2010ae
A
89 }
90
91 return NULL;
92}
93
316670eb
A
94/*
95 * Find the UUID load command in the Mach-O headers, and return
96 * the address of the UUID blob and size in "*size". If the
97 * Mach-O image is missing a UUID, NULL is returned.
98 */
99void *
100getuuidfromheader(kernel_mach_header_t *mhp, unsigned long *size)
101{
0a7de745
A
102 struct uuid_command *cmd = (struct uuid_command *)
103 getcommandfromheader(mhp, LC_UUID);
316670eb 104
0a7de745
A
105 if (cmd != NULL) {
106 if (size) {
107 *size = sizeof(cmd->uuid);
108 }
109 return cmd->uuid;
110 }
316670eb 111
0a7de745 112 return NULL;
316670eb
A
113}
114
b0d623f7
A
115/*
116 * This routine returns the a pointer to the data for the named section in the
117 * named segment if it exist in the mach header passed to it. Also it returns
118 * the size of the section data indirectly through the pointer size. Otherwise
119 * it returns zero for the pointer and the size.
120 *
121 * This routine can operate against any kernel mach header.
122 */
123void *
124getsectdatafromheader(
0a7de745
A
125 kernel_mach_header_t *mhp,
126 const char *segname,
127 const char *sectname,
128 unsigned long *size)
129{
b0d623f7
A
130 const kernel_section_t *sp;
131 void *result;
132
133 sp = getsectbynamefromheader(mhp, segname, sectname);
0a7de745
A
134 if (sp == (kernel_section_t *)0) {
135 *size = 0;
136 return (char *)0;
b0d623f7
A
137 }
138 *size = sp->size;
0a7de745 139 result = (void *)sp->addr;
b0d623f7
A
140 return result;
141}
142
39037602
A
143/*
144 * This routine returns the offset for the named section in the
145 * named segment if it exist in the mach header passed to it. Otherwise
146 * it returns zero.
147 *
148 * This routine can operate against any kernel mach header.
149 */
150uint32_t
151getsectoffsetfromheader(
0a7de745
A
152 kernel_mach_header_t *mhp,
153 const char *segname,
154 const char *sectname)
39037602
A
155{
156 const kernel_section_t *sp;
157
158 sp = getsectbynamefromheader(mhp, segname, sectname);
0a7de745
A
159 if (sp == (kernel_section_t *)0) {
160 return 0;
39037602
A
161 }
162
163 return sp->offset;
164}
165
b0d623f7
A
166/*
167 * This routine returns the a pointer to the data for the named segment
168 * if it exist in the mach header passed to it. Also it returns
169 * the size of the segment data indirectly through the pointer size.
170 * Otherwise it returns zero for the pointer and the size.
171 */
172void *
173getsegdatafromheader(
0a7de745 174 kernel_mach_header_t *mhp,
b0d623f7
A
175 const char *segname,
176 unsigned long *size)
177{
178 const kernel_segment_command_t *sc;
179 void *result;
180
181 sc = getsegbynamefromheader(mhp, segname);
0a7de745
A
182 if (sc == (kernel_segment_command_t *)0) {
183 *size = 0;
184 return (char *)0;
b0d623f7
A
185 }
186 *size = sc->vmsize;
187 result = (void *)sc->vmaddr;
188 return result;
189}
190
191/*
192 * This routine returns the section structure for the named section in the
193 * named segment for the mach_header pointer passed to it if it exist.
194 * Otherwise it returns zero.
195 *
196 * This routine can operate against any kernel mach header.
197 */
198kernel_section_t *
199getsectbynamefromheader(
0a7de745
A
200 kernel_mach_header_t *mhp,
201 const char *segname,
202 const char *sectname)
b0d623f7
A
203{
204 kernel_segment_command_t *sgp;
205 kernel_section_t *sp;
206 unsigned long i, j;
207
208 sgp = (kernel_segment_command_t *)
0a7de745
A
209 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
210 for (i = 0; i < mhp->ncmds; i++) {
211 if (sgp->cmd == LC_SEGMENT_KERNEL) {
212 if (strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
213 mhp->filetype == MH_OBJECT) {
214 sp = (kernel_section_t *)((uintptr_t)sgp +
215 sizeof(kernel_segment_command_t));
216 for (j = 0; j < sgp->nsects; j++) {
217 if (strncmp(sp->sectname, sectname,
218 sizeof(sp->sectname)) == 0 &&
219 strncmp(sp->segname, segname,
220 sizeof(sp->segname)) == 0) {
221 return sp;
222 }
223 sp = (kernel_section_t *)((uintptr_t)sp +
224 sizeof(kernel_section_t));
225 }
226 }
b0d623f7 227 }
0a7de745 228 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
b0d623f7 229 }
0a7de745 230 return (kernel_section_t *)NULL;
b0d623f7
A
231}
232
233/*
234 * This routine can operate against any kernel mach header.
235 */
236kernel_segment_command_t *
237getsegbynamefromheader(
0a7de745
A
238 kernel_mach_header_t *header,
239 const char *seg_name)
b0d623f7
A
240{
241 kernel_segment_command_t *sgp;
242 unsigned long i;
243
244 sgp = (kernel_segment_command_t *)
0a7de745
A
245 ((uintptr_t)header + sizeof(kernel_mach_header_t));
246 for (i = 0; i < header->ncmds; i++) {
247 if (sgp->cmd == LC_SEGMENT_KERNEL
248 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname))) {
b0d623f7 249 return sgp;
0a7de745 250 }
b0d623f7
A
251 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
252 }
253 return (kernel_segment_command_t *)NULL;
254}
255
256/*
257 * Return the first segment_command in the header.
258 */
259kernel_segment_command_t *
260firstseg(void)
261{
0a7de745 262 return firstsegfromheader(&_mh_execute_header);
b0d623f7
A
263}
264
265kernel_segment_command_t *
266firstsegfromheader(kernel_mach_header_t *header)
267{
0a7de745
A
268 u_int i = 0;
269 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
270 ((uintptr_t)header + sizeof(*header));
271
272 for (i = 0; i < header->ncmds; i++) {
273 if (sgp->cmd == LC_SEGMENT_KERNEL) {
274 return sgp;
275 }
276 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
277 }
278 return (kernel_segment_command_t *)NULL;
b0d623f7
A
279}
280
281/*
282 * This routine operates against any kernel mach segment_command structure
283 * pointer and the provided kernel header, to obtain the sequentially next
284 * segment_command structure in that header.
285 */
286kernel_segment_command_t *
287nextsegfromheader(
0a7de745
A
288 kernel_mach_header_t *header,
289 kernel_segment_command_t *seg)
b0d623f7 290{
0a7de745
A
291 u_int i = 0;
292 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
293 ((uintptr_t)header + sizeof(*header));
b0d623f7 294
0a7de745
A
295 /* Find the index of the passed-in segment */
296 for (i = 0; sgp != seg && i < header->ncmds; i++) {
297 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
298 }
b0d623f7 299
0a7de745
A
300 /* Increment to the next load command */
301 i++;
302 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
b0d623f7 303
0a7de745
A
304 /* Return the next segment command, if any */
305 for (; i < header->ncmds; i++) {
306 if (sgp->cmd == LC_SEGMENT_KERNEL) {
307 return sgp;
308 }
b0d623f7 309
0a7de745
A
310 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
311 }
b0d623f7 312
0a7de745 313 return (kernel_segment_command_t *)NULL;
b0d623f7
A
314}
315
316
317/*
318 * Return the address of the named Mach-O segment from the currently
319 * executing kernel kernel, or NULL.
320 */
321kernel_segment_command_t *
322getsegbyname(const char *seg_name)
323{
0a7de745 324 return getsegbynamefromheader(&_mh_execute_header, seg_name);
b0d623f7
A
325}
326
327/*
328 * This routine returns the a pointer the section structure of the named
329 * section in the named segment if it exists in the currently executing
330 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
331 */
332kernel_section_t *
333getsectbyname(
0a7de745
A
334 const char *segname,
335 const char *sectname)
b0d623f7 336{
0a7de745
A
337 return getsectbynamefromheader(
338 (kernel_mach_header_t *)&_mh_execute_header, segname, sectname);
b0d623f7
A
339}
340
341/*
342 * This routine can operate against any kernel segment_command structure to
343 * return the first kernel section immediately following that structure. If
344 * there are no sections associated with the segment_command structure, it
345 * returns NULL.
346 */
347kernel_section_t *
348firstsect(kernel_segment_command_t *sgp)
349{
0a7de745 350 if (!sgp || sgp->nsects == 0) {
b0d623f7 351 return (kernel_section_t *)NULL;
0a7de745 352 }
b0d623f7 353
0a7de745 354 return (kernel_section_t *)(sgp + 1);
b0d623f7
A
355}
356
357/*
358 * This routine can operate against any kernel segment_command structure and
359 * kernel section to return the next consecutive kernel section immediately
360 * following the kernel section provided. If there are no sections following
361 * the provided section, it returns NULL.
362 */
363kernel_section_t *
364nextsect(kernel_segment_command_t *sgp, kernel_section_t *sp)
365{
366 kernel_section_t *fsp = firstsect(sgp);
367
0a7de745 368 if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects) {
b0d623f7 369 return (kernel_section_t *)NULL;
0a7de745 370 }
b0d623f7 371
0a7de745 372 return sp + 1;
b0d623f7 373}