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


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