Annotation of XNU/osfmk/mach-o/mach_header.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 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:  * HISTORY
        !            28:  * 27-MAR-97  Umesh Vaishampayan ([email protected])
        !            29:  *     Added getsegdatafromheader();
        !            30:  *
        !            31:  * 29-Jan-92  Mike DeMoney ([email protected])
        !            32:  *     Made into machine independent form from machdep/m68k/mach_header.c.
        !            33:  *     Ifdef'ed out most of this since I couldn't find any references.
        !            34:  */
        !            35: 
        !            36: #include <vm/vm_map.h>
        !            37: #include <vm/vm_kern.h>
        !            38: #include <mach-o/mach_header.h>
        !            39: 
        !            40: #ifdef __MACHO__
        !            41: 
        !            42: extern struct mach_header _mh_execute_header;
        !            43: 
        !            44: struct section *getsectbynamefromheader(
        !            45:        struct mach_header      *header,
        !            46:        char                    *seg_name,
        !            47:        char                    *sect_name);
        !            48: struct segment_command *getsegbynamefromheader(
        !            49:        struct mach_header      *header,
        !            50:        char                    *seg_name);
        !            51: 
        !            52: /*
        !            53:  * return the last address (first avail)
        !            54:  */
        !            55: #ifdef MACH_BSD
        !            56: __private_extern__
        !            57: #endif
        !            58: vm_offset_t getlastaddr(void)
        !            59: {
        !            60:        struct segment_command  *sgp;
        !            61:        vm_offset_t             last_addr = 0;
        !            62:        struct mach_header *header = &_mh_execute_header;
        !            63:        int i;
        !            64: 
        !            65:        sgp = (struct segment_command *)
        !            66:                ((char *)header + sizeof(struct mach_header));
        !            67:        for (i = 0; i < header->ncmds; i++){
        !            68:                if (   sgp->cmd == LC_SEGMENT) {
        !            69:                        if (sgp->vmaddr + sgp->vmsize > last_addr)
        !            70:                                last_addr = sgp->vmaddr + sgp->vmsize;
        !            71:                }
        !            72:                sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !            73:        }
        !            74:        return last_addr;
        !            75: }
        !            76: 
        !            77: #ifdef XXX_MACH_BSD
        !            78: __private_extern__
        !            79: #endif
        !            80: struct mach_header **
        !            81: getmachheaders(void)
        !            82: {
        !            83:        extern struct mach_header _mh_execute_header;
        !            84:        struct mach_header **tl;
        !            85:        
        !            86:        if (kmem_alloc(kernel_map, (vm_offset_t *) &tl, 2*sizeof(struct mach_header *)) != KERN_SUCCESS)
        !            87:                return  NULL;
        !            88: 
        !            89:        tl[0] = &_mh_execute_header;
        !            90:        tl[1] = (struct mach_header *)0;
        !            91:        return tl;
        !            92: }
        !            93: 
        !            94: /*
        !            95:  * This routine returns the a pointer to the data for the named section in the
        !            96:  * named segment if it exist in the mach header passed to it.  Also it returns
        !            97:  * the size of the section data indirectly through the pointer size.  Otherwise
        !            98:  *  it returns zero for the pointer and the size.
        !            99:  */
        !           100: #ifdef MACH_BSD
        !           101: __private_extern__
        !           102: #endif
        !           103: void *
        !           104: getsectdatafromheader(
        !           105:     struct mach_header *mhp,
        !           106:     char *segname,
        !           107:     char *sectname,
        !           108:     int *size)
        !           109: {              
        !           110:        const struct section *sp;
        !           111:        void *result;
        !           112: 
        !           113:        sp = getsectbynamefromheader(mhp, segname, sectname);
        !           114:        if(sp == (struct section *)0){
        !           115:            *size = 0;
        !           116:            return((char *)0);
        !           117:        }
        !           118:        *size = sp->size;
        !           119:        result = (void *)sp->addr;
        !           120:        return result;
        !           121: }
        !           122: 
        !           123: /*
        !           124:  * This routine returns the a pointer to the data for the named segment
        !           125:  * if it exist in the mach header passed to it.  Also it returns
        !           126:  * the size of the segment data indirectly through the pointer size.
        !           127:  * Otherwise it returns zero for the pointer and the size.
        !           128:  */
        !           129: #ifdef MACH_BSD
        !           130: __private_extern__
        !           131: #endif
        !           132: void *
        !           133: getsegdatafromheader(
        !           134:     struct mach_header *mhp,
        !           135:        char *segname,
        !           136:        int *size)
        !           137: {
        !           138:        const struct segment_command *sc;
        !           139:        void *result;
        !           140: 
        !           141:        sc = getsegbynamefromheader(mhp, segname);
        !           142:        if(sc == (struct segment_command *)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: #ifdef MACH_BSD
        !           157: __private_extern__
        !           158: #endif
        !           159: struct section *
        !           160: getsectbynamefromheader(
        !           161:     struct mach_header *mhp,
        !           162:     char *segname,
        !           163:     char *sectname)
        !           164: {
        !           165:        struct segment_command *sgp;
        !           166:        struct section *sp;
        !           167:        long i, j;
        !           168: 
        !           169:        sgp = (struct segment_command *)
        !           170:              ((char *)mhp + sizeof(struct mach_header));
        !           171:        for(i = 0; i < mhp->ncmds; i++){
        !           172:            if(sgp->cmd == LC_SEGMENT)
        !           173:                if(strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0 ||
        !           174:                   mhp->filetype == MH_OBJECT){
        !           175:                    sp = (struct section *)((char *)sgp +
        !           176:                         sizeof(struct segment_command));
        !           177:                    for(j = 0; j < sgp->nsects; j++){
        !           178:                        if(strncmp(sp->sectname, sectname,
        !           179:                           sizeof(sp->sectname)) == 0 &&
        !           180:                           strncmp(sp->segname, segname,
        !           181:                           sizeof(sp->segname)) == 0)
        !           182:                            return(sp);
        !           183:                        sp = (struct section *)((char *)sp +
        !           184:                             sizeof(struct section));
        !           185:                    }
        !           186:                }
        !           187:            sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           188:        }
        !           189:        return((struct section *)0);
        !           190: }
        !           191: 
        !           192: #ifdef MACH_BSD
        !           193: __private_extern__
        !           194: #endif
        !           195: struct segment_command *getsegbynamefromheader(
        !           196:        struct mach_header      *header,
        !           197:        char                    *seg_name)
        !           198: {
        !           199:        struct segment_command *sgp;
        !           200:        int i;
        !           201: 
        !           202:        sgp = (struct segment_command *)
        !           203:                ((char *)header + sizeof(struct mach_header));
        !           204:        for (i = 0; i < header->ncmds; i++){
        !           205:                if (   sgp->cmd == LC_SEGMENT
        !           206:                    && !strncmp(sgp->segname, seg_name, sizeof(sgp->segname)))
        !           207:                        return sgp;
        !           208:                sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           209:        }
        !           210:        return (struct segment_command *)0;
        !           211: }
        !           212: 
        !           213: 
        !           214: /*
        !           215:  * For now at least, all the rest of this seems unused.
        !           216:  * NOTE: The constant in here for segment alignment is machine-dependent,
        !           217:  * so if you include this, define a machine dependent constant for it's
        !           218:  * value.
        !           219:  */
        !           220: static struct {
        !           221:        struct segment_command  seg;
        !           222:        struct section          sect;
        !           223: } fvm_data = {
        !           224:        {
        !           225:                LC_SEGMENT,             // cmd
        !           226:                sizeof(fvm_data),       // cmdsize
        !           227:                "__USER",               // segname
        !           228:                0,                      // vmaddr
        !           229:                0,                      // vmsize
        !           230:                0,                      // fileoff
        !           231:                0,                      // filesize
        !           232:                VM_PROT_READ,           // maxprot
        !           233:                VM_PROT_READ,           // initprot,
        !           234:                1,                      // nsects
        !           235:                0                       // flags
        !           236:        },
        !           237:        {
        !           238:                "",                     // sectname
        !           239:                "__USER",               // segname
        !           240:                0,                      // addr
        !           241:                0,                      // size
        !           242:                0,                      // offset
        !           243:                4,                      // align
        !           244:                0,                      // reloff
        !           245:                0,                      // nreloc
        !           246:                0                       // flags
        !           247:        }
        !           248: };
        !           249: 
        !           250: #ifdef MACH_BSD
        !           251: static
        !           252: #endif
        !           253: struct segment_command *fvm_seg;
        !           254: 
        !           255: static struct fvmfile_command *fvmfilefromheader(struct mach_header *header);
        !           256: static vm_offset_t getsizeofmacho(struct mach_header *header);
        !           257: 
        !           258: /*
        !           259:  * Return the first segment_command in the header.
        !           260:  */
        !           261: #ifdef MACH_BSD
        !           262: __private_extern__
        !           263: #endif
        !           264: struct segment_command *firstseg(void)
        !           265: {
        !           266:        return firstsegfromheader(&_mh_execute_header);
        !           267: }
        !           268: 
        !           269: #ifdef MACH_BSD
        !           270: __private_extern__
        !           271: #endif
        !           272: struct segment_command *firstsegfromheader(struct mach_header *header)
        !           273: {
        !           274:        struct segment_command *sgp;
        !           275:        int i;
        !           276: 
        !           277:        sgp = (struct segment_command *)
        !           278:                ((char *)header + sizeof(struct mach_header));
        !           279:        for (i = 0; i < header->ncmds; i++){
        !           280:                if (sgp->cmd == LC_SEGMENT)
        !           281:                        return sgp;
        !           282:                sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           283:        }
        !           284:        return (struct segment_command *)0;
        !           285: }
        !           286: 
        !           287: #ifdef MACH_BSD
        !           288: __private_extern__
        !           289: #endif
        !           290: struct segment_command *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: #ifdef MACH_BSD
        !           307: __private_extern__
        !           308: #endif
        !           309: struct segment_command *nextsegfromheader(
        !           310:        struct mach_header      *header,
        !           311:        struct segment_command  *seg)
        !           312: {
        !           313:        struct segment_command *sgp;
        !           314:        int i;
        !           315: 
        !           316:        sgp = (struct segment_command *)
        !           317:                ((char *)header + sizeof(struct mach_header));
        !           318:        for (i = 0; i < header->ncmds; i++) {
        !           319:                if (sgp == seg)
        !           320:                        break;
        !           321:                sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           322:        }
        !           323: 
        !           324:        if (i == header->ncmds)
        !           325:                return (struct segment_command *)0;
        !           326: 
        !           327:        sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           328:        for (; i < header->ncmds; i++) {
        !           329:                if (sgp->cmd == LC_SEGMENT)
        !           330:                        return sgp;
        !           331:                sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           332:        }
        !           333: 
        !           334:        return (struct segment_command *)0;
        !           335: }
        !           336: 
        !           337: 
        !           338: /*
        !           339:  * Return the address of the named Mach-O segment, or NULL.
        !           340:  */
        !           341: #ifdef MACH_BSD
        !           342: __private_extern__
        !           343: #endif
        !           344: struct segment_command *getsegbyname(char *seg_name)
        !           345: {
        !           346:        struct segment_command *this;
        !           347: 
        !           348:        this = getsegbynamefromheader(&_mh_execute_header, seg_name);
        !           349: 
        !           350:        /*
        !           351:         * For the kernel's header add on the faked segment for the
        !           352:         * USER boot code identified by a FVMFILE_COMMAND in the mach header.
        !           353:         */
        !           354:        if (!this && strcmp(seg_name, fvm_seg->segname) == 0)
        !           355:                this = fvm_seg;
        !           356: 
        !           357:        return this;
        !           358: }
        !           359: 
        !           360: /*
        !           361:  * This routine returns the a pointer the section structure of the named
        !           362:  * section in the named segment if it exist in the mach executable it is
        !           363:  * linked into.  Otherwise it returns zero.
        !           364:  */
        !           365: #ifdef MACH_BSD
        !           366: __private_extern__
        !           367: #endif
        !           368: struct section *
        !           369: getsectbyname(
        !           370:     char *segname,
        !           371:     char *sectname)
        !           372: {
        !           373:        return(getsectbynamefromheader(
        !           374:                (struct mach_header *)&_mh_execute_header, segname, sectname));
        !           375: }
        !           376: 
        !           377: #ifdef MACH_BSD
        !           378: __private_extern__
        !           379: #endif
        !           380: struct section *firstsect(struct segment_command *sgp)
        !           381: {
        !           382:        struct section *sp;
        !           383: 
        !           384:        if (!sgp || sgp->nsects == 0)
        !           385:                return (struct section *)0;
        !           386: 
        !           387:        return (struct section *)(sgp+1);
        !           388: }
        !           389: 
        !           390: #ifdef MACH_BSD
        !           391: __private_extern__
        !           392: #endif
        !           393: struct section *nextsect(struct segment_command *sgp, struct section *sp)
        !           394: {
        !           395:        struct section *fsp = firstsect(sgp);
        !           396: 
        !           397:        if (sp - fsp >= sgp->nsects-1)
        !           398:                return (struct section *)0;
        !           399: 
        !           400:        return sp+1;
        !           401: }
        !           402: 
        !           403: static struct fvmfile_command *fvmfilefromheader(struct mach_header *header)
        !           404: {
        !           405:        struct fvmfile_command *fvp;
        !           406:        int i;
        !           407: 
        !           408:        fvp = (struct fvmfile_command *)
        !           409:                ((char *)header + sizeof(struct mach_header));
        !           410:        for (i = 0; i < header->ncmds; i++){
        !           411:                if (fvp->cmd == LC_FVMFILE)
        !           412:                        return fvp;
        !           413:                fvp = (struct fvmfile_command *)((char *)fvp + fvp->cmdsize);
        !           414:        }
        !           415:        return (struct fvmfile_command *)0;
        !           416: }
        !           417: 
        !           418: /*
        !           419:  * Create a fake USER seg if a fvmfile_command is present.
        !           420:  */
        !           421: #ifdef MACH_BSD
        !           422: __private_extern__
        !           423: #endif
        !           424: struct segment_command *getfakefvmseg(void)
        !           425: {
        !           426:        struct segment_command *sgp = getsegbyname("__USER");
        !           427:        struct fvmfile_command *fvp = fvmfilefromheader(&_mh_execute_header);
        !           428:        struct section *sp;
        !           429: 
        !           430:        if (sgp)
        !           431:                return sgp;
        !           432: 
        !           433:        if (!fvp)
        !           434:                return (struct segment_command *)0;
        !           435: 
        !           436:        fvm_seg = &fvm_data.seg;
        !           437:        sgp = fvm_seg;
        !           438:        sp = &fvm_data.sect;
        !           439: 
        !           440:        sgp->vmaddr = fvp->header_addr;
        !           441:        sgp->vmsize = getsizeofmacho((struct mach_header *)(sgp->vmaddr));
        !           442: 
        !           443:        strcpy(sp->sectname, fvp->name.ptr);
        !           444:        sp->addr = sgp->vmaddr;
        !           445:        sp->size = sgp->vmsize;
        !           446: 
        !           447: #if    DEBUG
        !           448:        printf("fake fvm seg __USER/\"%s\" at 0x%x, size 0x%x\n",
        !           449:                sp->sectname, sp->addr, sp->size);
        !           450: #endif /*DEBUG*/
        !           451:        return sgp;
        !           452: }
        !           453: 
        !           454: /*
        !           455:  * Figure out the size the size of the data associated with a
        !           456:  * loaded mach_header.
        !           457:  */
        !           458: static vm_offset_t getsizeofmacho(struct mach_header *header)
        !           459: {
        !           460:        struct segment_command  *sgp;
        !           461:        struct section          *sp;
        !           462:        vm_offset_t             last_addr;
        !           463: 
        !           464:        last_addr = 0;
        !           465:        for (  sgp = firstsegfromheader(header)
        !           466:            ; sgp
        !           467:            ; sgp = nextsegfromheader(header, sgp))
        !           468:        {
        !           469:                if (sgp->fileoff + sgp->filesize > last_addr)
        !           470:                        last_addr = sgp->fileoff + sgp->filesize;
        !           471:        }
        !           472: 
        !           473:        return last_addr;
        !           474: }
        !           475: 
        !           476: #ifdef MACH_KDB
        !           477: /*
        !           478:  * This routine returns the section command for the symbol table in the
        !           479:  * named segment for the mach_header pointer passed to it if it exist.
        !           480:  * Otherwise it returns zero.
        !           481:  */
        !           482: struct symtab_command *
        !           483: getsectcmdsymtabfromheader(
        !           484:        struct mach_header *mhp)
        !           485: {
        !           486:        struct segment_command *sgp;
        !           487:        struct section *sp;
        !           488:        long i;
        !           489: 
        !           490:        sgp = (struct segment_command *)
        !           491:                ((char *)mhp + sizeof(struct mach_header));
        !           492:        for(i = 0; i < mhp->ncmds; i++){
        !           493:                if(sgp->cmd == LC_SYMTAB)
        !           494:                return((struct symtab_command *)sgp);
        !           495:                sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize);
        !           496:        }
        !           497:        return(NULL);
        !           498: }
        !           499: 
        !           500: boolean_t getsymtab(struct mach_header *header,
        !           501:                        vm_offset_t *symtab,
        !           502:                        int *nsyms,
        !           503:                        vm_offset_t *strtab,
        !           504:                        vm_size_t *strtabsize)
        !           505: {
        !           506:        struct segment_command *seglink_cmd;
        !           507:        struct symtab_command *symtab_cmd;
        !           508: 
        !           509:        seglink_cmd = NULL;
        !           510:        
        !           511:        if(header->magic != MH_MAGIC) {                                         /* Check if this is a valid header format */
        !           512:                printf("Attempt to use invalid header (magic = %08X) to find symbol table\n", 
        !           513:                        header->magic);                                                         /* Tell them what's wrong */
        !           514:                return (FALSE);                                                                 /* Bye y'all... */
        !           515:        }
        !           516:        
        !           517:        seglink_cmd = getsegbynamefromheader(header,"__LINKEDIT");
        !           518:        if (seglink_cmd == NULL) {
        !           519:                return(FALSE);
        !           520:        }
        !           521: 
        !           522:        symtab_cmd = NULL;
        !           523:        symtab_cmd = getsectcmdsymtabfromheader(header);
        !           524:        if (symtab_cmd == NULL)
        !           525:                return(FALSE);
        !           526: 
        !           527:        *nsyms = symtab_cmd->nsyms;
        !           528:        if(symtab_cmd->nsyms == 0) return (FALSE);      /* No symbols */
        !           529: 
        !           530:        *strtabsize = symtab_cmd->strsize;
        !           531:        if(symtab_cmd->strsize == 0) return (FALSE);    /* Symbol length is 0 */
        !           532:        
        !           533:        *symtab = seglink_cmd->vmaddr + symtab_cmd->symoff -
        !           534:                seglink_cmd->fileoff;
        !           535: 
        !           536:        *strtab = seglink_cmd->vmaddr + symtab_cmd->stroff -
        !           537:                        seglink_cmd->fileoff;
        !           538: 
        !           539:        return(TRUE);
        !           540: }
        !           541: #endif
        !           542: 
        !           543: #else
        !           544: 
        !           545: void * getsegdatafromheader( struct mach_header *mhp, char *segname, int *size)
        !           546: {
        !           547:        return  0;
        !           548: }
        !           549: 
        !           550: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.