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