]>
git.saurik.com Git - apple/xnu.git/blob - libkern/kernel_mach_header.c
   2  * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29  *      File: libkern/kernel_mach_header.c 
  31  *      Functions for accessing mach-o headers. 
  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.  
  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 
  47  * return the last address (first avail) 
  49  * This routine operates against the currently executing kernel only 
  54         kernel_segment_command_t        
*sgp
; 
  55         vm_offset_t             last_addr 
= 0; 
  56         kernel_mach_header_t 
*header 
= &_mh_execute_header
; 
  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
; 
  66                 sgp 
= (kernel_segment_command_t 
*)((uintptr_t)sgp 
+ sgp
->cmdsize
); 
  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. 
  76 getcommandfromheader(kernel_mach_header_t 
*mhp
, uint32_t cmd
) { 
  77         struct load_command 
*lcp
; 
  80         lcp 
= (struct load_command 
*) (mhp 
+ 1); 
  81         for(i 
= 0; i 
< mhp
->ncmds
; i
++){ 
  86                 lcp 
= (struct load_command 
*)((uintptr_t)lcp 
+ lcp
->cmdsize
); 
  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. 
  98 getuuidfromheader(kernel_mach_header_t 
*mhp
, unsigned long *size
) 
 100     struct uuid_command 
*cmd 
= (struct uuid_command 
*) 
 101         getcommandfromheader(mhp
, LC_UUID
); 
 105             *size 
= sizeof(cmd
->uuid
); 
 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. 
 119  * This routine can operate against any kernel mach header. 
 122 getsectdatafromheader( 
 123     kernel_mach_header_t 
*mhp
, 
 125     const char *sectname
, 
 128         const kernel_section_t 
*sp
; 
 131         sp 
= getsectbynamefromheader(mhp
, segname
, sectname
); 
 132         if(sp 
== (kernel_section_t 
*)0){ 
 137         result 
= (void *)sp
->addr
;  
 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. 
 148 getsegdatafromheader( 
 149     kernel_mach_header_t 
*mhp
, 
 153         const kernel_segment_command_t 
*sc
; 
 156         sc 
= getsegbynamefromheader(mhp
, segname
); 
 157         if(sc 
== (kernel_segment_command_t 
*)0){ 
 162         result 
= (void *)sc
->vmaddr
; 
 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. 
 171  * This routine can operate against any kernel mach header. 
 174 getsectbynamefromheader( 
 175     kernel_mach_header_t 
*mhp
, 
 177     const char *sectname
) 
 179         kernel_segment_command_t 
*sgp
; 
 180         kernel_section_t 
*sp
; 
 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) 
 197                         sp 
= (kernel_section_t 
*)((uintptr_t)sp 
+ 
 198                              sizeof(kernel_section_t
)); 
 201             sgp 
= (kernel_segment_command_t 
*)((uintptr_t)sgp 
+ sgp
->cmdsize
); 
 203         return((kernel_section_t 
*)NULL
); 
 207  * This routine can operate against any kernel mach header. 
 209 kernel_segment_command_t 
* 
 210 getsegbynamefromheader( 
 211         kernel_mach_header_t    
*header
, 
 212         const char              *seg_name
) 
 214         kernel_segment_command_t 
*sgp
; 
 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
))) 
 223                 sgp 
= (kernel_segment_command_t 
*)((uintptr_t)sgp 
+ sgp
->cmdsize
); 
 225         return (kernel_segment_command_t 
*)NULL
; 
 229  * Return the first segment_command in the header. 
 231 kernel_segment_command_t 
* 
 234     return firstsegfromheader(&_mh_execute_header
); 
 237 kernel_segment_command_t 
* 
 238 firstsegfromheader(kernel_mach_header_t 
*header
) 
 241     kernel_segment_command_t 
*sgp 
= (kernel_segment_command_t 
*) 
 242         ((uintptr_t)header 
+ sizeof(*header
)); 
 244     for (i 
= 0; i 
< header
->ncmds
; i
++){ 
 245         if (sgp
->cmd 
== LC_SEGMENT_KERNEL
) 
 247         sgp 
= (kernel_segment_command_t 
*)((uintptr_t)sgp 
+ sgp
->cmdsize
); 
 249     return (kernel_segment_command_t 
*)NULL
; 
 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. 
 257 kernel_segment_command_t 
* 
 259         kernel_mach_header_t    
*header
, 
 260         kernel_segment_command_t        
*seg
) 
 263     kernel_segment_command_t 
*sgp 
= (kernel_segment_command_t 
*) 
 264         ((uintptr_t)header 
+ sizeof(*header
)); 
 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
); 
 271     /* Increment to the next load command */ 
 273     sgp 
= (kernel_segment_command_t 
*)((uintptr_t)sgp 
+ sgp
->cmdsize
); 
 275     /* Return the next segment command, if any */ 
 276     for (; i 
< header
->ncmds
; i
++) { 
 277         if (sgp
->cmd 
== LC_SEGMENT_KERNEL
) return sgp
; 
 279         sgp 
= (kernel_segment_command_t 
*)((uintptr_t)sgp 
+ sgp
->cmdsize
); 
 282     return (kernel_segment_command_t 
*)NULL
; 
 287  * Return the address of the named Mach-O segment from the currently 
 288  * executing kernel kernel, or NULL. 
 290 kernel_segment_command_t 
* 
 291 getsegbyname(const char *seg_name
) 
 293         return(getsegbynamefromheader(&_mh_execute_header
, seg_name
)); 
 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. 
 304     const char *sectname
) 
 306         return(getsectbynamefromheader( 
 307                 (kernel_mach_header_t 
*)&_mh_execute_header
, segname
, sectname
)); 
 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 
 317 firstsect(kernel_segment_command_t 
*sgp
) 
 319         if (!sgp 
|| sgp
->nsects 
== 0) 
 320                 return (kernel_section_t 
*)NULL
; 
 322         return (kernel_section_t 
*)(sgp
+1); 
 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. 
 332 nextsect(kernel_segment_command_t 
*sgp
, kernel_section_t 
*sp
) 
 334         kernel_section_t 
*fsp 
= firstsect(sgp
); 
 336         if (((uintptr_t)(sp 
- fsp
) + 1) >= sgp
->nsects
) 
 337                 return (kernel_section_t 
*)NULL
;