The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libkern/kernel_mach_header.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * 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  */
   76 void *
   77 getuuidfromheader(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 
   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  */
  106 void *
  107 getsectdatafromheader(
  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  */
  132 void *
  133 getsegdatafromheader(
  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  */
  158 kernel_section_t *
  159 getsectbynamefromheader(
  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  */
  194 kernel_segment_command_t *
  195 getsegbynamefromheader(
  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  */
  216 kernel_segment_command_t *
  217 firstseg(void)
  218 {
  219     return firstsegfromheader(&_mh_execute_header);
  220 }
  221 
  222 kernel_segment_command_t *
  223 firstsegfromheader(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  */
  242 kernel_segment_command_t *
  243 nextsegfromheader(
  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  */
  275 kernel_segment_command_t *
  276 getsegbyname(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  */
  286 kernel_section_t *
  287 getsectbyname(
  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  */
  301 kernel_section_t *
  302 firstsect(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  */
  316 kernel_section_t *
  317 nextsect(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  */
  333 static struct symtab_command *
  334 getsectcmdsymtabfromheader(
  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 
  350 boolean_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

Cache object: 2d8e36d22d0d0e0cd36b7d1fd9fe2bc9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.