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/bsd/kern/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-2004 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * The contents of this file constitute Original Code as defined in and
    7  * are subject to the Apple Public Source License Version 1.1 (the
    8  * "License").  You may not use this file except in compliance with the
    9  * License.  Please obtain a copy of the License at
   10  * http://www.apple.com/publicsource and read it before using this file.
   11  * 
   12  * This Original Code and all software distributed under the License are
   13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
   17  * License for the specific language governing rights and limitations
   18  * under the License.
   19  * 
   20  * @APPLE_LICENSE_HEADER_END@
   21  */
   22 /*
   23  *      File: kern/mach_header.c
   24  *
   25  *      Functions for accessing mach-o headers.
   26  *
   27  * NOTE:        This file supports only 32 bit mach headers at the present
   28  *              time; it's primary use is by kld, and all externally
   29  *              referenced routines at the present time operate against
   30  *              the 32 bit mach header _mh_execute_header, which is the
   31  *              header for the currently executing kernel.  Adding support
   32  *              for 64 bit kernels is possible, but is not necessary at the
   33  *              present time.
   34  *
   35  * HISTORY
   36  * 27-MAR-97  Umesh Vaishampayan (umeshv@NeXT.com)
   37  *      Added getsegdatafromheader();
   38  *
   39  * 29-Jan-92  Mike DeMoney (mike@next.com)
   40  *      Made into machine independent form from machdep/m68k/mach_header.c.
   41  *      Ifdef'ed out most of this since I couldn't find any references.
   42  */
   43 
   44 #if !defined(KERNEL_PRELOAD)
   45 #include <kern/mach_header.h>
   46 #include <string.h>             // from libsa
   47 
   48 extern struct mach_header _mh_execute_header;
   49 
   50 /*
   51  * return the last address (first avail)
   52  *
   53  * This routine operates against the currently executing kernel only
   54  */
   55 vm_offset_t
   56 getlastaddr(void)
   57 {
   58         struct segment_command  *sgp;
   59         vm_offset_t             last_addr = 0;
   60         struct mach_header *header = &_mh_execute_header;
   61         unsigned long i;
   62 
   63         sgp = (struct segment_command *)
   64                 ((char *)header + sizeof(struct mach_header));
   65         for (i = 0; i < header->ncmds; i++){
   66                 if (   sgp->cmd == LC_SEGMENT) {
   67                         if (sgp->vmaddr + sgp->vmsize > last_addr)
   68                                 last_addr = sgp->vmaddr + sgp->vmsize;
   69                 }
   70                 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
   71         }
   72         return last_addr;
   73 }
   74 
   75 #if FIXME  /* [ */
   76 /*
   77  * This routine operates against the currently executing kernel only
   78  */
   79 struct mach_header **
   80 getmachheaders(void)
   81 {
   82         struct mach_header **tl;
   83         tl = (struct mach_header **)malloc(2*sizeof(struct mach_header *));
   84         tl[0] = &_mh_execute_header;
   85         tl[1] = (struct mach_header *)0;
   86         return tl;
   87 }
   88 #endif  /* FIXME ] */
   89 
   90 /*
   91  * This routine returns the a pointer to the data for the named section in the
   92  * named segment if it exist in the mach header passed to it.  Also it returns
   93  * the size of the section data indirectly through the pointer size.  Otherwise
   94  *  it returns zero for the pointer and the size.
   95  *
   96  * This routine can operate against any 32 bit mach header.
   97  */
   98 void *
   99 getsectdatafromheader(
  100     struct mach_header *mhp,
  101     const char *segname,
  102     const char *sectname,
  103     int *size)
  104 {               
  105         const struct section *sp;
  106         void *result;
  107 
  108         sp = getsectbynamefromheader(mhp, segname, sectname);
  109         if(sp == (struct section *)0){
  110             *size = 0;
  111             return((char *)0);
  112         }
  113         *size = sp->size;
  114         result = (void *)sp->addr;
  115         return result;
  116 }
  117 
  118 /*
  119  * This routine returns the a pointer to the data for the named segment
  120  * if it exist in the mach header passed to it.  Also it returns
  121  * the size of the segment data indirectly through the pointer size.
  122  * Otherwise it returns zero for the pointer and the size.
  123  *
  124  * This routine can operate against any 32 bit mach header.
  125  */
  126 void *
  127 getsegdatafromheader(
  128         struct mach_header *mhp,
  129         const char *segname,
  130         int *size)
  131 {
  132         const struct segment_command *sc;
  133         void *result;
  134 
  135         sc = getsegbynamefromheader(mhp, segname);
  136         if(sc == (struct segment_command *)0){
  137             *size = 0;
  138             return((char *)0);
  139         }
  140         *size = sc->vmsize;
  141         result = (void *)sc->vmaddr;
  142         return result;
  143 }
  144 
  145 /*
  146  * This routine returns the section structure for the named section in the
  147  * named segment for the mach_header pointer passed to it if it exist.
  148  * Otherwise it returns zero.
  149  *
  150  * This routine can operate against any 32 bit mach header.
  151  */
  152 struct section *
  153 getsectbynamefromheader(
  154     struct mach_header *mhp,
  155     const char *segname,
  156     const char *sectname)
  157 {
  158         struct segment_command *sgp;
  159         struct section *sp;
  160         unsigned long i, j;
  161 
  162         sgp = (struct segment_command *)
  163               ((char *)mhp + sizeof(struct mach_header));
  164         for(i = 0; i < mhp->ncmds; i++){
  165             if(sgp->cmd == LC_SEGMENT)
  166                 if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
  167                    mhp->filetype == MH_OBJECT){
  168                     sp = (struct section *)((char *)sgp +
  169                          sizeof(struct segment_command));
  170                     for(j = 0; j < sgp->nsects; j++){
  171                         if(strncmp(sp->sectname, sectname,
  172                            sizeof(sp->sectname)) == 0 &&
  173                            strncmp(sp->segname, segname,
  174                            sizeof(sp->segname)) == 0)
  175                             return(sp);
  176                         sp = (struct section *)((char *)sp +
  177                              sizeof(struct section));
  178                     }
  179                 }
  180             sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
  181         }
  182         return((struct section *)0);
  183 }
  184 
  185 /*
  186  * This routine can operate against any 32 bit mach header.
  187  */
  188 struct segment_command *
  189 getsegbynamefromheader(
  190         struct mach_header      *header,
  191         const char              *seg_name)
  192 {
  193         struct segment_command *sgp;
  194         unsigned long i;
  195 
  196         sgp = (struct segment_command *)
  197                 ((char *)header + sizeof(struct mach_header));
  198         for (i = 0; i < header->ncmds; i++){
  199                 if (   sgp->cmd == LC_SEGMENT
  200                     && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
  201                         return sgp;
  202                 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
  203         }
  204         return (struct segment_command *)0;
  205 }
  206 
  207 
  208 /*
  209  * For now at least, all the rest of this seems unused.
  210  * NOTE: The constant in here for segment alignment is machine-dependent,
  211  * so if you include this, define a machine dependent constant for it's
  212  * value.
  213  */
  214 static struct {
  215         struct segment_command  seg;
  216         struct section          sect;
  217 } fvm_data = {
  218         {
  219                 LC_SEGMENT,             // cmd
  220                 sizeof(fvm_data),       // cmdsize
  221                 "__USER",               // segname
  222                 0,                      // vmaddr
  223                 0,                      // vmsize
  224                 0,                      // fileoff
  225                 0,                      // filesize
  226                 VM_PROT_READ,           // maxprot
  227                 VM_PROT_READ,           // initprot,
  228                 1,                      // nsects
  229                 0                       // flags
  230         },
  231         {
  232                 "",                     // sectname
  233                 "__USER",               // segname
  234                 0,                      // addr
  235                 0,                      // size
  236                 0,                      // offset
  237                 4,                      // align
  238                 0,                      // reloff
  239                 0,                      // nreloc
  240                 0,                      // flags
  241                 0,                      // reserved1
  242                 0                       // reserved2
  243         }
  244 };
  245 
  246 struct segment_command *fvm_seg;
  247 
  248 static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
  249 static vm_offset_t getsizeofmacho(struct mach_header *header);
  250 
  251 /*
  252  * Return the first segment_command in the header.
  253  *
  254  * This routine operates against the currently executing kernel only
  255  */
  256 struct segment_command *
  257 firstseg(void)
  258 {
  259         return firstsegfromheader(&_mh_execute_header);
  260 }
  261 
  262 /*
  263  * This routine can operate against any 32 bit mach header, and returns a
  264  * pointer to a 32 bit segment_command structure from the file prefixed by
  265  * the header it is passed as its argument.
  266  */
  267 struct segment_command *
  268 firstsegfromheader(struct mach_header *header)
  269 {
  270         struct segment_command *sgp;
  271         unsigned long i;
  272 
  273         sgp = (struct segment_command *)
  274                 ((char *)header + sizeof(struct mach_header));
  275         for (i = 0; i < header->ncmds; i++){
  276                 if (sgp->cmd == LC_SEGMENT)
  277                         return sgp;
  278                 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
  279         }
  280         return (struct segment_command *)0;
  281 }
  282 
  283 /*
  284  * This routine operates against a 32 bit mach segment_command structure
  285  * pointer from the currently executing kernel only, to obtain the
  286  * sequentially next segment_command structure in the currently executing
  287  * kernel
  288  */
  289 struct segment_command *
  290 nextseg(struct segment_command *sgp)
  291 {
  292         struct segment_command *this;
  293 
  294         this = nextsegfromheader(&_mh_execute_header, sgp);
  295 
  296         /*
  297          * For the kernel's header add on the faked segment for the
  298          * USER boot code identified by a FVMFILE_COMMAND in the mach header.
  299          */
  300         if (!this && sgp != fvm_seg)
  301                 this = fvm_seg;
  302 
  303         return this;
  304 }
  305 
  306 /*
  307  * This routine operates against any 32 bit mach segment_command structure
  308  * pointer and the provided 32 bit header, to obtain the sequentially next
  309  * segment_command structure in that header.
  310  */
  311 struct segment_command *
  312 nextsegfromheader(
  313         struct mach_header      *header,
  314         struct segment_command  *seg)
  315 {
  316         struct segment_command *sgp;
  317         unsigned long i;
  318 
  319         sgp = (struct segment_command *)
  320                 ((char *)header + sizeof(struct mach_header));
  321         for (i = 0; i < header->ncmds; i++) {
  322                 if (sgp == seg)
  323                         break;
  324                 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
  325         }
  326 
  327         if (i == header->ncmds)
  328                 return (struct segment_command *)0;
  329 
  330         sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
  331         for (; i < header->ncmds; i++) {
  332                 if (sgp->cmd == LC_SEGMENT)
  333                         return sgp;
  334                 sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
  335         }
  336 
  337         return (struct segment_command *)0;
  338 }
  339 
  340 
  341 /*
  342  * Return the address of the named Mach-O segment from the currently
  343  * executing 32 bit kernel, or NULL.
  344  */
  345 struct segment_command *
  346 getsegbyname(const char *seg_name)
  347 {
  348         struct segment_command *this;
  349 
  350         this = getsegbynamefromheader(&_mh_execute_header, seg_name);
  351 
  352         /*
  353          * For the kernel's header add on the faked segment for the
  354          * USER boot code identified by a FVMFILE_COMMAND in the mach header.
  355          */
  356         if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
  357                 this = fvm_seg;
  358 
  359         return this;
  360 }
  361 
  362 /*
  363  * This routine returns the a pointer the section structure of the named
  364  * section in the named segment if it exists in the currently executing
  365  * kernel, which it is presumed to be linked into.  Otherwise it returns NULL.
  366  */
  367 struct section *
  368 getsectbyname(
  369     const char *segname,
  370     const char *sectname)
  371 {
  372         return(getsectbynamefromheader(
  373                 (struct mach_header *)&_mh_execute_header, segname, sectname));
  374 }
  375 
  376 /*
  377  * This routine can operate against any 32 bit segment_command structure to
  378  * return the first 32 bit section immediately following that structure.  If
  379  * there are no sections associated with the segment_command structure, it
  380  * returns NULL.
  381  */
  382 struct section *
  383 firstsect(struct segment_command *sgp)
  384 {
  385         if (!sgp || sgp->nsects == 0)
  386                 return (struct section *)0;
  387 
  388         return (struct section *)(sgp+1);
  389 }
  390 
  391 /*
  392  * This routine can operate against any 32 bit segment_command structure and
  393  * 32 bit section to return the next consecutive  32 bit section immediately
  394  * following the 32 bit section provided.  If there are no sections following
  395  * the provided section, it returns NULL.
  396  */
  397 struct section *
  398 nextsect(struct segment_command *sgp, struct section *sp)
  399 {
  400         struct section *fsp = firstsect(sgp);
  401 
  402         if (((unsigned long)(sp - fsp) + 1) >= sgp->nsects)
  403                 return (struct section *)0;
  404 
  405         return sp+1;
  406 }
  407 
  408 /*
  409  * This routine can operate against any 32 bit mach header to return the
  410  * first occurring 32 bit fvmfile_command section.  If one is not present,
  411  * it returns NULL.
  412  */
  413 static struct fvmfile_command *
  414 fvmfilefromheader(struct mach_header *header)
  415 {
  416         struct fvmfile_command *fvp;
  417         unsigned long i;
  418 
  419         fvp = (struct fvmfile_command *)
  420                 ((char *)header + sizeof(struct mach_header));
  421         for (i = 0; i < header->ncmds; i++){
  422                 if (fvp->cmd == LC_FVMFILE)
  423                         return fvp;
  424                 fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
  425         }
  426         return (struct fvmfile_command *)0;
  427 }
  428 
  429 /*
  430  * Create a fake USER seg if a fvmfile_command is present.
  431  *
  432  * This routine operates against the currently executing kernel only
  433  */
  434 struct segment_command *
  435 getfakefvmseg(void)
  436 {
  437         struct segment_command *sgp = getsegbyname("__USER");
  438         struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
  439         struct section *sp;
  440 
  441         if (sgp)
  442                 return sgp;
  443 
  444         if (!fvp)
  445                 return (struct segment_command *)0;
  446 
  447         fvm_seg = &fvm_data.seg;
  448         sgp = fvm_seg;
  449         sp = &fvm_data.sect;
  450 
  451         sgp->vmaddr = fvp->header_addr;
  452         sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
  453 
  454         strcpy(sp->sectname, fvp->name.ptr);
  455         sp->addr = sgp->vmaddr;
  456         sp->size = sgp->vmsize;
  457 
  458 #if     DEBUG
  459         printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
  460                 sp->sectname, sp->addr, sp->size);
  461 #endif  /* DEBUG */
  462 
  463         return sgp;
  464 }
  465 
  466 /*
  467  * Figure out the size the size of the data associated with a
  468  * loaded mach_header.
  469  *
  470  * This routine can operate against any 32 bit mach header.
  471  */
  472 static vm_offset_t
  473 getsizeofmacho(struct mach_header *header)
  474 {
  475         struct segment_command  *sgp;
  476         vm_offset_t             last_addr;
  477 
  478         last_addr = 0;
  479         for (  sgp = firstsegfromheader(header)
  480             ; sgp
  481             ; sgp = nextsegfromheader(header, sgp))
  482         {
  483                 if (sgp->fileoff + sgp->filesize > last_addr)
  484                         last_addr = sgp->fileoff + sgp->filesize;
  485         }
  486 
  487         return last_addr;
  488 }
  489 #endif  /* !defined(KERNEL_PRELOAD) */

Cache object: a377a0b0f40ac0360c310b80dce3efce


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