|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.