]> git.saurik.com Git - apple/xnu.git/blob - libkern/kernel_mach_header.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / libkern / kernel_mach_header.c
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 */
51 vm_offset_t
52 getlastaddr(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++){
62 if ( sgp->cmd == LC_SEGMENT_KERNEL) {
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
71 /*
72 * This routine returns the a pointer to the data for the named section in the
73 * named segment if it exist in the mach header passed to it. Also it returns
74 * the size of the section data indirectly through the pointer size. Otherwise
75 * it returns zero for the pointer and the size.
76 *
77 * This routine can operate against any kernel mach header.
78 */
79 void *
80 getsectdatafromheader(
81 kernel_mach_header_t *mhp,
82 const char *segname,
83 const char *sectname,
84 unsigned long *size)
85 {
86 const kernel_section_t *sp;
87 void *result;
88
89 sp = getsectbynamefromheader(mhp, segname, sectname);
90 if(sp == (kernel_section_t *)0){
91 *size = 0;
92 return((char *)0);
93 }
94 *size = sp->size;
95 result = (void *)sp->addr;
96 return result;
97 }
98
99 /*
100 * This routine returns the a pointer to the data for the named segment
101 * if it exist in the mach header passed to it. Also it returns
102 * the size of the segment data indirectly through the pointer size.
103 * Otherwise it returns zero for the pointer and the size.
104 */
105 void *
106 getsegdatafromheader(
107 kernel_mach_header_t *mhp,
108 const char *segname,
109 unsigned long *size)
110 {
111 const kernel_segment_command_t *sc;
112 void *result;
113
114 sc = getsegbynamefromheader(mhp, segname);
115 if(sc == (kernel_segment_command_t *)0){
116 *size = 0;
117 return((char *)0);
118 }
119 *size = sc->vmsize;
120 result = (void *)sc->vmaddr;
121 return result;
122 }
123
124 /*
125 * This routine returns the section structure for the named section in the
126 * named segment for the mach_header pointer passed to it if it exist.
127 * Otherwise it returns zero.
128 *
129 * This routine can operate against any kernel mach header.
130 */
131 kernel_section_t *
132 getsectbynamefromheader(
133 kernel_mach_header_t *mhp,
134 const char *segname,
135 const char *sectname)
136 {
137 kernel_segment_command_t *sgp;
138 kernel_section_t *sp;
139 unsigned long i, j;
140
141 sgp = (kernel_segment_command_t *)
142 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
143 for(i = 0; i < mhp->ncmds; i++){
144 if(sgp->cmd == LC_SEGMENT_KERNEL)
145 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
146 mhp->filetype == MH_OBJECT){
147 sp = (kernel_section_t *)((uintptr_t)sgp +
148 sizeof(kernel_segment_command_t));
149 for(j = 0; j < sgp->nsects; j++){
150 if(strncmp(sp->sectname, sectname,
151 sizeof(sp->sectname)) == 0 &&
152 strncmp(sp->segname, segname,
153 sizeof(sp->segname)) == 0)
154 return(sp);
155 sp = (kernel_section_t *)((uintptr_t)sp +
156 sizeof(kernel_section_t));
157 }
158 }
159 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
160 }
161 return((kernel_section_t *)NULL);
162 }
163
164 /*
165 * This routine can operate against any kernel mach header.
166 */
167 kernel_segment_command_t *
168 getsegbynamefromheader(
169 kernel_mach_header_t *header,
170 const char *seg_name)
171 {
172 kernel_segment_command_t *sgp;
173 unsigned long i;
174
175 sgp = (kernel_segment_command_t *)
176 ((uintptr_t)header + sizeof(kernel_mach_header_t));
177 for (i = 0; i < header->ncmds; i++){
178 if ( sgp->cmd == LC_SEGMENT_KERNEL
179 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
180 return sgp;
181 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
182 }
183 return (kernel_segment_command_t *)NULL;
184 }
185
186 /*
187 * Return the first segment_command in the header.
188 */
189 kernel_segment_command_t *
190 firstseg(void)
191 {
192 return firstsegfromheader(&_mh_execute_header);
193 }
194
195 kernel_segment_command_t *
196 firstsegfromheader(kernel_mach_header_t *header)
197 {
198 u_int i = 0;
199 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
200 ((uintptr_t)header + sizeof(*header));
201
202 for (i = 0; i < header->ncmds; i++){
203 if (sgp->cmd == LC_SEGMENT_KERNEL)
204 return sgp;
205 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
206 }
207 return (kernel_segment_command_t *)NULL;
208 }
209
210 /*
211 * This routine operates against any kernel mach segment_command structure
212 * pointer and the provided kernel header, to obtain the sequentially next
213 * segment_command structure in that header.
214 */
215 kernel_segment_command_t *
216 nextsegfromheader(
217 kernel_mach_header_t *header,
218 kernel_segment_command_t *seg)
219 {
220 u_int i = 0;
221 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
222 ((uintptr_t)header + sizeof(*header));
223
224 /* Find the index of the passed-in segment */
225 for (i = 0; sgp != seg && i < header->ncmds; i++) {
226 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
227 }
228
229 /* Increment to the next load command */
230 i++;
231 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
232
233 /* Return the next segment command, if any */
234 for (; i < header->ncmds; i++) {
235 if (sgp->cmd == LC_SEGMENT_KERNEL) return sgp;
236
237 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
238 }
239
240 return (kernel_segment_command_t *)NULL;
241 }
242
243
244 /*
245 * Return the address of the named Mach-O segment from the currently
246 * executing kernel kernel, or NULL.
247 */
248 kernel_segment_command_t *
249 getsegbyname(const char *seg_name)
250 {
251 return(getsegbynamefromheader(&_mh_execute_header, seg_name));
252 }
253
254 /*
255 * This routine returns the a pointer the section structure of the named
256 * section in the named segment if it exists in the currently executing
257 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
258 */
259 kernel_section_t *
260 getsectbyname(
261 const char *segname,
262 const char *sectname)
263 {
264 return(getsectbynamefromheader(
265 (kernel_mach_header_t *)&_mh_execute_header, segname, sectname));
266 }
267
268 /*
269 * This routine can operate against any kernel segment_command structure to
270 * return the first kernel section immediately following that structure. If
271 * there are no sections associated with the segment_command structure, it
272 * returns NULL.
273 */
274 kernel_section_t *
275 firstsect(kernel_segment_command_t *sgp)
276 {
277 if (!sgp || sgp->nsects == 0)
278 return (kernel_section_t *)NULL;
279
280 return (kernel_section_t *)(sgp+1);
281 }
282
283 /*
284 * This routine can operate against any kernel segment_command structure and
285 * kernel section to return the next consecutive kernel section immediately
286 * following the kernel section provided. If there are no sections following
287 * the provided section, it returns NULL.
288 */
289 kernel_section_t *
290 nextsect(kernel_segment_command_t *sgp, kernel_section_t *sp)
291 {
292 kernel_section_t *fsp = firstsect(sgp);
293
294 if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects)
295 return (kernel_section_t *)NULL;
296
297 return sp+1;
298 }
299
300 #ifdef MACH_KDB
301 /*
302 * This routine returns the section command for the symbol table in the
303 * named segment for the mach_header pointer passed to it if it exist.
304 * Otherwise it returns zero.
305 */
306 static struct symtab_command *
307 getsectcmdsymtabfromheader(
308 kernel_mach_header_t *mhp)
309 {
310 kernel_segment_command_t *sgp;
311 unsigned long i;
312
313 sgp = (kernel_segment_command_t *)
314 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
315 for(i = 0; i < mhp->ncmds; i++){
316 if(sgp->cmd == LC_SYMTAB)
317 return((struct symtab_command *)sgp);
318 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
319 }
320 return((struct symtab_command *)NULL);
321 }
322
323 boolean_t getsymtab(kernel_mach_header_t *header,
324 vm_offset_t *symtab,
325 int *nsyms,
326 vm_offset_t *strtab,
327 vm_size_t *strtabsize)
328 {
329 kernel_segment_command_t *seglink_cmd;
330 struct symtab_command *symtab_cmd;
331
332 seglink_cmd = NULL;
333
334 if((header->magic != MH_MAGIC)
335 && (header->magic != MH_MAGIC_64)) { /* Check if this is a valid header format */
336 return (FALSE); /* Bye y'all... */
337 }
338
339 seglink_cmd = getsegbynamefromheader(header,"__LINKEDIT");
340 if (seglink_cmd == NULL) {
341 return(FALSE);
342 }
343
344 symtab_cmd = NULL;
345 symtab_cmd = getsectcmdsymtabfromheader(header);
346 if (symtab_cmd == NULL)
347 return(FALSE);
348
349 *nsyms = symtab_cmd->nsyms;
350 if(symtab_cmd->nsyms == 0) return (FALSE); /* No symbols */
351
352 *strtabsize = symtab_cmd->strsize;
353 if(symtab_cmd->strsize == 0) return (FALSE); /* Symbol length is 0 */
354
355 *symtab = seglink_cmd->vmaddr + symtab_cmd->symoff -
356 seglink_cmd->fileoff;
357
358 *strtab = seglink_cmd->vmaddr + symtab_cmd->stroff -
359 seglink_cmd->fileoff;
360
361 return(TRUE);
362 }
363 #endif