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 }
67 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
68 }
69 return last_addr;
70 }
71
72 /*
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.
75 */
76 void *
77 getcommandfromheader(kernel_mach_header_t *mhp, uint32_t cmd)
78 {
79 struct load_command *lcp;
80 unsigned long i;
81
82 lcp = (struct load_command *) (mhp + 1);
83 for (i = 0; i < mhp->ncmds; i++) {
84 if (lcp->cmd == cmd) {
85 return (void *)lcp;
86 }
87
88 lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize);
89 }
90
91 return NULL;
92 }
93
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 */
99 void *
100 getuuidfromheader(kernel_mach_header_t *mhp, unsigned long *size)
101 {
102 struct uuid_command *cmd = (struct uuid_command *)
103 getcommandfromheader(mhp, LC_UUID);
104
105 if (cmd != NULL) {
106 if (size) {
107 *size = sizeof(cmd->uuid);
108 }
109 return cmd->uuid;
110 }
111
112 return NULL;
113 }
114
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 */
123 void *
124 getsectdatafromheader(
125 kernel_mach_header_t *mhp,
126 const char *segname,
127 const char *sectname,
128 unsigned long *size)
129 {
130 const kernel_section_t *sp;
131 void *result;
132
133 sp = getsectbynamefromheader(mhp, segname, sectname);
134 if (sp == (kernel_section_t *)0) {
135 *size = 0;
136 return (char *)0;
137 }
138 *size = sp->size;
139 result = (void *)sp->addr;
140 return result;
141 }
142
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 */
150 uint32_t
151 getsectoffsetfromheader(
152 kernel_mach_header_t *mhp,
153 const char *segname,
154 const char *sectname)
155 {
156 const kernel_section_t *sp;
157
158 sp = getsectbynamefromheader(mhp, segname, sectname);
159 if (sp == (kernel_section_t *)0) {
160 return 0;
161 }
162
163 return sp->offset;
164 }
165
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 */
172 void *
173 getsegdatafromheader(
174 kernel_mach_header_t *mhp,
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);
182 if (sc == (kernel_segment_command_t *)0) {
183 *size = 0;
184 return (char *)0;
185 }
186 *size = sc->vmsize;
187 result = (void *)sc->vmaddr;
188 return result;
189 }
190
191 /*
192 * This routine iterates through the sections in a particular segment
193 * and returns pointer to the requested section, if it is present.
194 * Otherwise it returns zero.
195 */
196 kernel_section_t *
197 getsectbynamefromseg(
198 kernel_segment_command_t *sgp,
199 const char *segname,
200 const char *sectname)
201 {
202 unsigned long j;
203 kernel_section_t *sp = (kernel_section_t *)((uintptr_t)sgp +
204 sizeof(kernel_segment_command_t));
205 for (j = 0; j < sgp->nsects; j++) {
206 if (strncmp(sp->sectname, sectname,
207 sizeof(sp->sectname)) == 0 &&
208 strncmp(sp->segname, segname,
209 sizeof(sp->segname)) == 0) {
210 return sp;
211 }
212 sp = (kernel_section_t *)((uintptr_t)sp +
213 sizeof(kernel_section_t));
214 }
215 return (kernel_section_t *)NULL;
216 }
217
218
219 /*
220 * This routine returns the section structure for the named section in the
221 * named segment for the mach_header pointer passed to it if it exist.
222 * Otherwise it returns zero.
223 *
224 * This routine can operate against any kernel mach header.
225 */
226 kernel_section_t *
227 getsectbynamefromheader(
228 kernel_mach_header_t *mhp,
229 const char *segname,
230 const char *sectname)
231 {
232 kernel_segment_command_t *sgp;
233 kernel_section_t *sp;
234 unsigned long i;
235
236 sgp = (kernel_segment_command_t *)
237 ((uintptr_t)mhp + sizeof(kernel_mach_header_t));
238 for (i = 0; i < mhp->ncmds; i++) {
239 if (sgp->cmd == LC_SEGMENT_KERNEL) {
240 if (strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
241 mhp->filetype == MH_OBJECT) {
242 sp = getsectbynamefromseg(sgp, segname, sectname);
243 if (sp) {
244 return sp;
245 }
246 }
247 }
248 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
249 }
250 return (kernel_section_t *)NULL;
251 }
252
253 /*
254 * This routine can operate against any kernel mach header.
255 */
256 kernel_segment_command_t *
257 getsegbynamefromheader(
258 kernel_mach_header_t *header,
259 const char *seg_name)
260 {
261 kernel_segment_command_t *sgp;
262 unsigned long i;
263
264 sgp = (kernel_segment_command_t *)
265 ((uintptr_t)header + sizeof(kernel_mach_header_t));
266 for (i = 0; i < header->ncmds; i++) {
267 if (sgp->cmd == LC_SEGMENT_KERNEL
268 && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname))) {
269 return sgp;
270 }
271 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
272 }
273 return (kernel_segment_command_t *)NULL;
274 }
275
276 /*
277 * Return the first segment_command in the header.
278 */
279 kernel_segment_command_t *
280 firstseg(void)
281 {
282 return firstsegfromheader(&_mh_execute_header);
283 }
284
285 kernel_segment_command_t *
286 firstsegfromheader(kernel_mach_header_t *header)
287 {
288 u_int i = 0;
289 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
290 ((uintptr_t)header + sizeof(*header));
291
292 for (i = 0; i < header->ncmds; i++) {
293 if (sgp->cmd == LC_SEGMENT_KERNEL) {
294 return sgp;
295 }
296 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
297 }
298 return (kernel_segment_command_t *)NULL;
299 }
300
301 /*
302 * This routine operates against any kernel mach segment_command structure
303 * pointer and the provided kernel header, to obtain the sequentially next
304 * segment_command structure in that header.
305 */
306 kernel_segment_command_t *
307 nextsegfromheader(
308 kernel_mach_header_t *header,
309 kernel_segment_command_t *seg)
310 {
311 u_int i = 0;
312 kernel_segment_command_t *sgp = (kernel_segment_command_t *)
313 ((uintptr_t)header + sizeof(*header));
314
315 /* Find the index of the passed-in segment */
316 for (i = 0; sgp != seg && i < header->ncmds; i++) {
317 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
318 }
319
320 /* Increment to the next load command */
321 i++;
322 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
323
324 /* Return the next segment command, if any */
325 for (; i < header->ncmds; i++) {
326 if (sgp->cmd == LC_SEGMENT_KERNEL) {
327 return sgp;
328 }
329
330 sgp = (kernel_segment_command_t *)((uintptr_t)sgp + sgp->cmdsize);
331 }
332
333 return (kernel_segment_command_t *)NULL;
334 }
335
336
337 /*
338 * Return the address of the named Mach-O segment from the currently
339 * executing kernel kernel, or NULL.
340 */
341 kernel_segment_command_t *
342 getsegbyname(const char *seg_name)
343 {
344 return getsegbynamefromheader(&_mh_execute_header, seg_name);
345 }
346
347 /*
348 * This routine returns the a pointer the section structure of the named
349 * section in the named segment if it exists in the currently executing
350 * kernel, which it is presumed to be linked into. Otherwise it returns NULL.
351 */
352 kernel_section_t *
353 getsectbyname(
354 const char *segname,
355 const char *sectname)
356 {
357 return getsectbynamefromheader(
358 (kernel_mach_header_t *)&_mh_execute_header, segname, sectname);
359 }
360
361 /*
362 * This routine can operate against any kernel segment_command structure to
363 * return the first kernel section immediately following that structure. If
364 * there are no sections associated with the segment_command structure, it
365 * returns NULL.
366 */
367 kernel_section_t *
368 firstsect(kernel_segment_command_t *sgp)
369 {
370 if (!sgp || sgp->nsects == 0) {
371 return (kernel_section_t *)NULL;
372 }
373
374 return (kernel_section_t *)(sgp + 1);
375 }
376
377 /*
378 * This routine can operate against any kernel segment_command structure and
379 * kernel section to return the next consecutive kernel section immediately
380 * following the kernel section provided. If there are no sections following
381 * the provided section, it returns NULL.
382 */
383 kernel_section_t *
384 nextsect(kernel_segment_command_t *sgp, kernel_section_t *sp)
385 {
386 kernel_section_t *fsp = firstsect(sgp);
387
388 if (((uintptr_t)(sp - fsp) + 1) >= sgp->nsects) {
389 return (kernel_section_t *)NULL;
390 }
391
392 return sp + 1;
393 }
Cache object: babeab37affeee6a19536e766eab7fca
|