]> git.saurik.com Git - apple/xnu.git/blame - libkern/kernel_mach_header.c
xnu-2422.1.72.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@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
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
37 * header for the currently executing kernel.
38 *
39 */
40
41#include <vm/vm_map.h>
42#include <vm/vm_kern.h>
43#include <libkern/kernel_mach_header.h>
44#include <string.h> // from libsa
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{
54 kernel_segment_command_t *sgp;
55 vm_offset_t last_addr = 0;
56 kernel_mach_header_t *header = &_mh_execute_header;
57 unsigned long i;
58
59 sgp = (kernel_segment_command_t *)
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) {
b0d623f7
A
63 if (sgp->vmaddr + sgp->vmsize > last_addr)
64 last_addr = sgp->vmaddr + sgp->vmsize;
65 }
66 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
67 }
68 return last_addr;
69}
70
6d2010ae 71/*
316670eb
A
72 * Find the specified load command in the Mach-O headers, and return
73 * the command. If there is no such load command, NULL is returned.
6d2010ae
A
74 */
75void *
316670eb
A
76getcommandfromheader(kernel_mach_header_t *mhp, uint32_t cmd) {
77 struct load_command *lcp;
6d2010ae
A
78 unsigned long i;
79
316670eb 80 lcp = (struct load_command *) (mhp + 1);
6d2010ae 81 for(i = 0; i < mhp->ncmds; i++){
316670eb
A
82 if(lcp->cmd == cmd) {
83 return (void *)lcp;
6d2010ae
A
84 }
85
316670eb 86 lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize);
6d2010ae
A
87 }
88
89 return NULL;
90}
91
316670eb
A
92/*
93 * Find the UUID load command in the Mach-O headers, and return
94 * the address of the UUID blob and size in "*size". If the
95 * Mach-O image is missing a UUID, NULL is returned.
96 */
97void *
98getuuidfromheader(kernel_mach_header_t *mhp, unsigned long *size)
99{
100 struct uuid_command *cmd = (struct uuid_command *)
101 getcommandfromheader(mhp, LC_UUID);
102
103 if (cmd != NULL) {
104 if (size) {
105 *size = sizeof(cmd->uuid);
106 }
107 return cmd->uuid;
108 }
109
110 return NULL;
111}
112
b0d623f7
A
113/*
114 * This routine returns the a pointer to the data for the named section in the
115 * named segment if it exist in the mach header passed to it. Also it returns
116 * the size of the section data indirectly through the pointer size. Otherwise
117 * it returns zero for the pointer and the size.
118 *
119 * This routine can operate against any kernel mach header.
120 */
121void *
122getsectdatafromheader(
123 kernel_mach_header_t *mhp,
124 const char *segname,
125 const char *sectname,
126 unsigned long *size)
127{
128 const kernel_section_t *sp;
129 void *result;
130
131 sp = getsectbynamefromheader(mhp, segname, sectname);
132 if(sp == (kernel_section_t *)0){
133 *size = 0;
134 return((char *)0);
135 }
136 *size = sp->size;
137 result = (void *)sp->addr;
138 return result;
139}
140
141/*
142 * This routine returns the a pointer to the data for the named segment
143 * if it exist in the mach header passed to it. Also it returns
144 * the size of the segment data indirectly through the pointer size.
145 * Otherwise it returns zero for the pointer and the size.
146 */
147void *
148getsegdatafromheader(
149 kernel_mach_header_t *mhp,
150 const char *segname,
151 unsigned long *size)
152{
153 const kernel_segment_command_t *sc;
154 void *result;
155
156 sc = getsegbynamefromheader(mhp, segname);
157 if(sc == (kernel_segment_command_t *)0){
158 *size = 0;
159 return((char *)0);
160 }
161 *size = sc->vmsize;
162 result = (void *)sc->vmaddr;
163 return result;
164}
165
166/*
167 * This routine returns the section structure for the named section in the
168 * named segment for the mach_header pointer passed to it if it exist.
169 * Otherwise it returns zero.
170 *
171 * This routine can operate against any kernel mach header.
172 */
173kernel_section_t *
174getsectbynamefromheader(
175 kernel_mach_header_t *mhp,
176 const char *segname,
177 const char *sectname)
178{
179 kernel_segment_command_t *sgp;
180 kernel_section_t *sp;
181 unsigned long i, j;
182
183 sgp = (kernel_segment_command_t *)
184 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
185 for(i = 0; i < mhp->ncmds; i++){
186 if(sgp->cmd == LC_SEGMENT_KERNEL)
187 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
188 mhp->filetype == MH_OBJECT){
189 sp = (kernel_section_t *)((uintptr_t)sgp +
190 sizeof(kernel_segment_command_t));
191 for(j = 0; j < sgp->nsects; j++){
192 if(strncmp(sp->sectname, sectname,
193 sizeof(sp->sectname)) == 0 &&
194 strncmp(sp->segname, segname,
195 sizeof(sp->segname)) == 0)
196 return(sp);
197 sp = (kernel_section_t *)((uintptr_t)sp +
198 sizeof(kernel_section_t));
199 }
200 }
201 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
202 }
203 return((kernel_section_t *)NULL);
204}
205
206/*
207 * This routine can operate against any kernel mach header.
208 */
209kernel_segment_command_t *
210getsegbynamefromheader(
211 kernel_mach_header_t *header,
212 const char *seg_name)
213{
214 kernel_segment_command_t *sgp;
215 unsigned long i;
216
217 sgp = (kernel_segment_command_t *)
218 ((uintptr_t)header + sizeof(kernel_mach_header_t));
219 for (i = 0; i < header->ncmds; i++){
220 if ( sgp->cmd == LC_SEGMENT_KERNEL
221 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
222 return sgp;
223 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
224 }
225 return (kernel_segment_command_t *)NULL;
226}
227
228/*
229 * Return the first segment_command in the header.
230 */
231kernel_segment_command_t *
232firstseg(void)
233{
234 return firstsegfromheader(&_mh_execute_header);
235}
236
237kernel_segment_command_t *
238firstsegfromheader(kernel_mach_header_t *header)
239{
240 u_int i = 0;
241 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
242 ((uintptr_t)header + sizeof(*header));
243
244 for (i = 0; i < header->ncmds; i++){
245 if (sgp->cmd == LC_SEGMENT_KERNEL)
246 return sgp;
247 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
248 }
249 return (kernel_segment_command_t *)NULL;
250}
251
252/*
253 * This routine operates against any kernel mach segment_command structure
254 * pointer and the provided kernel header, to obtain the sequentially next
255 * segment_command structure in that header.
256 */
257kernel_segment_command_t *
258nextsegfromheader(
259 kernel_mach_header_t *header,
260 kernel_segment_command_t *seg)
261{
262 u_int i = 0;
263 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
264 ((uintptr_t)header + sizeof(*header));
265
266 /* Find the index of the passed-in segment */
267 for (i = 0; sgp != seg && i < header->ncmds; i++) {
268 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
269 }
270
271 /* Increment to the next load command */
272 i++;
273 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
274
275 /* Return the next segment command, if any */
276 for (; i < header->ncmds; i++) {
277 if (sgp->cmd == LC_SEGMENT_KERNEL) return sgp;
278
279 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
280 }
281
282 return (kernel_segment_command_t *)NULL;
283}
284
285
286/*
287 * Return the address of the named Mach-O segment from the currently
288 * executing kernel kernel, or NULL.
289 */
290kernel_segment_command_t *
291getsegbyname(const char *seg_name)
292{
293 return(getsegbynamefromheader(&_mh_execute_header, seg_name));
294}
295
296/*
297 * This routine returns the a pointer the section structure of the named
298 * section in the named segment if it exists in the currently executing
299 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
300 */
301kernel_section_t *
302getsectbyname(
303 const char *segname,
304 const char *sectname)
305{
306 return(getsectbynamefromheader(
307 (kernel_mach_header_t *)&_mh_execute_header, segname, sectname));
308}
309
310/*
311 * This routine can operate against any kernel segment_command structure to
312 * return the first kernel section immediately following that structure. If
313 * there are no sections associated with the segment_command structure, it
314 * returns NULL.
315 */
316kernel_section_t *
317firstsect(kernel_segment_command_t *sgp)
318{
319 if (!sgp || sgp->nsects == 0)
320 return (kernel_section_t *)NULL;
321
322 return (kernel_section_t *)(sgp+1);
323}
324
325/*
326 * This routine can operate against any kernel segment_command structure and
327 * kernel section to return the next consecutive kernel section immediately
328 * following the kernel section provided. If there are no sections following
329 * the provided section, it returns NULL.
330 */
331kernel_section_t *
332nextsect(kernel_segment_command_t *sgp, kernel_section_t *sp)
333{
334 kernel_section_t *fsp = firstsect(sgp);
335
336 if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects)
337 return (kernel_section_t *)NULL;
338
339 return sp+1;
340}