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  * 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

Cache object: 7b6cace311a488ade60322b55cabf9af


[ 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.