|
|
1.1 ! root 1: /* ! 2: * Mach-O object file loading ! 3: * ! 4: * Copyright (c) 2006 Pierre d'Herbemont ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, write to the Free Software ! 18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 19: */ ! 20: #include <stdio.h> ! 21: #include <sys/types.h> ! 22: #include <fcntl.h> ! 23: #include <sys/stat.h> ! 24: #include <errno.h> ! 25: #include <unistd.h> ! 26: #include <sys/mman.h> ! 27: #include <stdlib.h> ! 28: #include <string.h> ! 29: ! 30: #include "qemu.h" ! 31: #include "disas.h" ! 32: ! 33: #include <mach-o/loader.h> ! 34: #include <mach-o/fat.h> ! 35: #include <mach-o/nlist.h> ! 36: #include <mach-o/reloc.h> ! 37: #include <mach-o/ppc/reloc.h> ! 38: ! 39: //#define DEBUG_MACHLOAD ! 40: ! 41: #ifdef DEBUG_MACHLOAD ! 42: # define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) ! 43: #else ! 44: # define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) ! 45: #endif ! 46: ! 47: # define check_mach_header(x) (x.magic == MH_CIGAM) ! 48: ! 49: extern const char *interp_prefix; ! 50: ! 51: /* we don't have a good implementation for this */ ! 52: #define DONT_USE_DYLD_SHARED_MAP ! 53: ! 54: /* Pass extra arg to DYLD for debug */ ! 55: //#define ACTIVATE_DYLD_TRACE ! 56: ! 57: //#define OVERRIDE_DYLINKER ! 58: ! 59: #ifdef OVERRIDE_DYLINKER ! 60: # ifdef TARGET_I386 ! 61: # define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld" ! 62: # else ! 63: # define DYLINKER_NAME "/usr/lib/dyld" ! 64: # endif ! 65: #endif ! 66: ! 67: /* XXX: in an include */ ! 68: struct nlist_extended ! 69: { ! 70: union { ! 71: char *n_name; ! 72: long n_strx; ! 73: } n_un; ! 74: unsigned char n_type; ! 75: unsigned char n_sect; ! 76: short st_desc; ! 77: unsigned long st_value; ! 78: unsigned long st_size; ! 79: }; ! 80: ! 81: /* Print symbols in gdb */ ! 82: void *macho_text_sect = 0; ! 83: int macho_offset = 0; ! 84: ! 85: int load_object(const char *filename, struct target_pt_regs * regs, void ** mh); ! 86: void qerror(const char *format, ...); ! 87: #ifdef TARGET_I386 ! 88: typedef struct mach_i386_thread_state { ! 89: unsigned int eax; ! 90: unsigned int ebx; ! 91: unsigned int ecx; ! 92: unsigned int edx; ! 93: unsigned int edi; ! 94: unsigned int esi; ! 95: unsigned int ebp; ! 96: unsigned int esp; ! 97: unsigned int ss; ! 98: unsigned int eflags; ! 99: unsigned int eip; ! 100: unsigned int cs; ! 101: unsigned int ds; ! 102: unsigned int es; ! 103: unsigned int fs; ! 104: unsigned int gs; ! 105: } mach_i386_thread_state_t; ! 106: ! 107: void bswap_i386_thread_state(struct mach_i386_thread_state *ts) ! 108: { ! 109: bswap32s((uint32_t*)&ts->eax); ! 110: bswap32s((uint32_t*)&ts->ebx); ! 111: bswap32s((uint32_t*)&ts->ecx); ! 112: bswap32s((uint32_t*)&ts->edx); ! 113: bswap32s((uint32_t*)&ts->edi); ! 114: bswap32s((uint32_t*)&ts->esi); ! 115: bswap32s((uint32_t*)&ts->ebp); ! 116: bswap32s((uint32_t*)&ts->esp); ! 117: bswap32s((uint32_t*)&ts->ss); ! 118: bswap32s((uint32_t*)&ts->eflags); ! 119: bswap32s((uint32_t*)&ts->eip); ! 120: bswap32s((uint32_t*)&ts->cs); ! 121: bswap32s((uint32_t*)&ts->ds); ! 122: bswap32s((uint32_t*)&ts->es); ! 123: bswap32s((uint32_t*)&ts->fs); ! 124: bswap32s((uint32_t*)&ts->gs); ! 125: } ! 126: #define target_thread_state mach_i386_thread_state ! 127: #define TARGET_CPU_TYPE CPU_TYPE_I386 ! 128: #define TARGET_CPU_NAME "i386" ! 129: #endif ! 130: ! 131: #ifdef TARGET_PPC ! 132: struct mach_ppc_thread_state { ! 133: unsigned int srr0; /* Instruction address register (PC) */ ! 134: unsigned int srr1; /* Machine state register (supervisor) */ ! 135: unsigned int r0; ! 136: unsigned int r1; ! 137: unsigned int r2; ! 138: unsigned int r3; ! 139: unsigned int r4; ! 140: unsigned int r5; ! 141: unsigned int r6; ! 142: unsigned int r7; ! 143: unsigned int r8; ! 144: unsigned int r9; ! 145: unsigned int r10; ! 146: unsigned int r11; ! 147: unsigned int r12; ! 148: unsigned int r13; ! 149: unsigned int r14; ! 150: unsigned int r15; ! 151: unsigned int r16; ! 152: unsigned int r17; ! 153: unsigned int r18; ! 154: unsigned int r19; ! 155: unsigned int r20; ! 156: unsigned int r21; ! 157: unsigned int r22; ! 158: unsigned int r23; ! 159: unsigned int r24; ! 160: unsigned int r25; ! 161: unsigned int r26; ! 162: unsigned int r27; ! 163: unsigned int r28; ! 164: unsigned int r29; ! 165: unsigned int r30; ! 166: unsigned int r31; ! 167: ! 168: unsigned int cr; /* Condition register */ ! 169: unsigned int xer; /* User's integer exception register */ ! 170: unsigned int lr; /* Link register */ ! 171: unsigned int ctr; /* Count register */ ! 172: unsigned int mq; /* MQ register (601 only) */ ! 173: ! 174: unsigned int vrsave; /* Vector Save Register */ ! 175: }; ! 176: ! 177: void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts) ! 178: { ! 179: bswap32s((uint32_t*)&ts->srr0); ! 180: bswap32s((uint32_t*)&ts->srr1); ! 181: bswap32s((uint32_t*)&ts->r0); ! 182: bswap32s((uint32_t*)&ts->r1); ! 183: bswap32s((uint32_t*)&ts->r2); ! 184: bswap32s((uint32_t*)&ts->r3); ! 185: bswap32s((uint32_t*)&ts->r4); ! 186: bswap32s((uint32_t*)&ts->r5); ! 187: bswap32s((uint32_t*)&ts->r6); ! 188: bswap32s((uint32_t*)&ts->r7); ! 189: bswap32s((uint32_t*)&ts->r8); ! 190: bswap32s((uint32_t*)&ts->r9); ! 191: bswap32s((uint32_t*)&ts->r10); ! 192: bswap32s((uint32_t*)&ts->r11); ! 193: bswap32s((uint32_t*)&ts->r12); ! 194: bswap32s((uint32_t*)&ts->r13); ! 195: bswap32s((uint32_t*)&ts->r14); ! 196: bswap32s((uint32_t*)&ts->r15); ! 197: bswap32s((uint32_t*)&ts->r16); ! 198: bswap32s((uint32_t*)&ts->r17); ! 199: bswap32s((uint32_t*)&ts->r18); ! 200: bswap32s((uint32_t*)&ts->r19); ! 201: bswap32s((uint32_t*)&ts->r20); ! 202: bswap32s((uint32_t*)&ts->r21); ! 203: bswap32s((uint32_t*)&ts->r22); ! 204: bswap32s((uint32_t*)&ts->r23); ! 205: bswap32s((uint32_t*)&ts->r24); ! 206: bswap32s((uint32_t*)&ts->r25); ! 207: bswap32s((uint32_t*)&ts->r26); ! 208: bswap32s((uint32_t*)&ts->r27); ! 209: bswap32s((uint32_t*)&ts->r28); ! 210: bswap32s((uint32_t*)&ts->r29); ! 211: bswap32s((uint32_t*)&ts->r30); ! 212: bswap32s((uint32_t*)&ts->r31); ! 213: ! 214: bswap32s((uint32_t*)&ts->cr); ! 215: bswap32s((uint32_t*)&ts->xer); ! 216: bswap32s((uint32_t*)&ts->lr); ! 217: bswap32s((uint32_t*)&ts->ctr); ! 218: bswap32s((uint32_t*)&ts->mq); ! 219: ! 220: bswap32s((uint32_t*)&ts->vrsave); ! 221: } ! 222: ! 223: #define target_thread_state mach_ppc_thread_state ! 224: #define TARGET_CPU_TYPE CPU_TYPE_POWERPC ! 225: #define TARGET_CPU_NAME "PowerPC" ! 226: #endif ! 227: ! 228: struct target_thread_command { ! 229: unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */ ! 230: unsigned long cmdsize; /* total size of this command */ ! 231: unsigned long flavor; /* flavor of thread state */ ! 232: unsigned long count; /* count of longs in thread state */ ! 233: struct target_thread_state state; /* thread state for this flavor */ ! 234: }; ! 235: ! 236: void bswap_tc(struct target_thread_command *tc) ! 237: { ! 238: bswap32s((uint32_t*)(&tc->flavor)); ! 239: bswap32s((uint32_t*)&tc->count); ! 240: #if defined(TARGET_I386) ! 241: bswap_i386_thread_state(&tc->state); ! 242: #elif defined(TARGET_PPC) ! 243: bswap_ppc_thread_state(&tc->state); ! 244: #else ! 245: # error unknown TARGET_CPU_TYPE ! 246: #endif ! 247: } ! 248: ! 249: void bswap_mh(struct mach_header *mh) ! 250: { ! 251: bswap32s((uint32_t*)(&mh->magic)); ! 252: bswap32s((uint32_t*)&mh->cputype); ! 253: bswap32s((uint32_t*)&mh->cpusubtype); ! 254: bswap32s((uint32_t*)&mh->filetype); ! 255: bswap32s((uint32_t*)&mh->ncmds); ! 256: bswap32s((uint32_t*)&mh->sizeofcmds); ! 257: bswap32s((uint32_t*)&mh->flags); ! 258: } ! 259: ! 260: void bswap_lc(struct load_command *lc) ! 261: { ! 262: bswap32s((uint32_t*)&lc->cmd); ! 263: bswap32s((uint32_t*)&lc->cmdsize); ! 264: } ! 265: ! 266: ! 267: void bswap_fh(struct fat_header *fh) ! 268: { ! 269: bswap32s((uint32_t*)&fh->magic); ! 270: bswap32s((uint32_t*)&fh->nfat_arch); ! 271: } ! 272: ! 273: void bswap_fa(struct fat_arch *fa) ! 274: { ! 275: bswap32s((uint32_t*)&fa->cputype); ! 276: bswap32s((uint32_t*)&fa->cpusubtype); ! 277: bswap32s((uint32_t*)&fa->offset); ! 278: bswap32s((uint32_t*)&fa->size); ! 279: bswap32s((uint32_t*)&fa->align); ! 280: } ! 281: ! 282: void bswap_segcmd(struct segment_command *sc) ! 283: { ! 284: bswap32s((uint32_t*)&sc->vmaddr); ! 285: bswap32s((uint32_t*)&sc->vmsize); ! 286: bswap32s((uint32_t*)&sc->fileoff); ! 287: bswap32s((uint32_t*)&sc->filesize); ! 288: bswap32s((uint32_t*)&sc->maxprot); ! 289: bswap32s((uint32_t*)&sc->initprot); ! 290: bswap32s((uint32_t*)&sc->nsects); ! 291: bswap32s((uint32_t*)&sc->flags); ! 292: } ! 293: ! 294: void bswap_symtabcmd(struct symtab_command *stc) ! 295: { ! 296: bswap32s((uint32_t*)&stc->cmd); ! 297: bswap32s((uint32_t*)&stc->cmdsize); ! 298: bswap32s((uint32_t*)&stc->symoff); ! 299: bswap32s((uint32_t*)&stc->nsyms); ! 300: bswap32s((uint32_t*)&stc->stroff); ! 301: bswap32s((uint32_t*)&stc->strsize); ! 302: } ! 303: ! 304: void bswap_sym(struct nlist *n) ! 305: { ! 306: bswap32s((uint32_t*)&n->n_un.n_strx); ! 307: bswap16s((uint16_t*)&n->n_desc); ! 308: bswap32s((uint32_t*)&n->n_value); ! 309: } ! 310: ! 311: int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap) ! 312: { ! 313: int entry; ! 314: if(need_bswap) ! 315: bswap_tc(tc); ! 316: #if defined(TARGET_I386) ! 317: entry = tc->state.eip; ! 318: DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n", ! 319: tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp, ! 320: tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es, ! 321: tc->state.fs, tc->state.gs ); ! 322: #define reg_copy(reg) regs->reg = tc->state.reg ! 323: if(regs) ! 324: { ! 325: reg_copy(eax); ! 326: reg_copy(ebx); ! 327: reg_copy(ecx); ! 328: reg_copy(edx); ! 329: ! 330: reg_copy(edi); ! 331: reg_copy(esi); ! 332: ! 333: reg_copy(ebp); ! 334: reg_copy(esp); ! 335: ! 336: reg_copy(eflags); ! 337: reg_copy(eip); ! 338: /* ! 339: reg_copy(ss); ! 340: reg_copy(cs); ! 341: reg_copy(ds); ! 342: reg_copy(es); ! 343: reg_copy(fs); ! 344: reg_copy(gs);*/ ! 345: } ! 346: #undef reg_copy ! 347: #elif defined(TARGET_PPC) ! 348: entry = tc->state.srr0; ! 349: #endif ! 350: DPRINTF("load_thread: entry 0x%x\n", entry); ! 351: return entry; ! 352: } ! 353: ! 354: int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap) ! 355: { ! 356: int size; ! 357: char * dylinker_name; ! 358: size = dc->cmdsize - sizeof(struct dylinker_command); ! 359: ! 360: if(need_bswap) ! 361: dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc); ! 362: else ! 363: dylinker_name = (char*)((dc->name.offset)+(int)dc); ! 364: ! 365: #ifdef OVERRIDE_DYLINKER ! 366: dylinker_name = DYLINKER_NAME; ! 367: #else ! 368: if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1) ! 369: qerror("can't allocate the new dylinker name\n"); ! 370: #endif ! 371: ! 372: DPRINTF("dylinker_name %s\n", dylinker_name); ! 373: return load_object(dylinker_name, NULL, NULL); ! 374: } ! 375: ! 376: int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide) ! 377: { ! 378: unsigned long addr = sc->vmaddr; ! 379: unsigned long size = sc->filesize; ! 380: unsigned long error = 0; ! 381: ! 382: if(need_bswap) ! 383: bswap_segcmd(sc); ! 384: ! 385: if(sc->vmaddr == 0) ! 386: { ! 387: DPRINTF("load_segment: sc->vmaddr == 0 returning\n"); ! 388: return -1; ! 389: } ! 390: ! 391: if (strcmp(sc->segname, "__PAGEZERO") == 0) ! 392: { ! 393: DPRINTF("load_segment: __PAGEZERO returning\n"); ! 394: return -1; ! 395: } ! 396: ! 397: /* Right now mmap memory */ ! 398: /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */ ! 399: DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide); ! 400: ! 401: if(sc->filesize > 0) ! 402: { ! 403: int opt = 0; ! 404: ! 405: if(fixed) ! 406: opt |= MAP_FIXED; ! 407: ! 408: DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide); ! 409: ! 410: addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff); ! 411: ! 412: if(addr==-1) ! 413: qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); ! 414: ! 415: error = addr-sc->vmaddr; ! 416: } ! 417: else ! 418: { ! 419: addr = sc->vmaddr+slide; ! 420: error = slide; ! 421: } ! 422: ! 423: if(sc->vmsize > sc->filesize) ! 424: { ! 425: addr += sc->filesize; ! 426: size = sc->vmsize-sc->filesize; ! 427: addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0); ! 428: if(addr==-1) ! 429: qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); ! 430: } ! 431: ! 432: return error; ! 433: } ! 434: ! 435: void *load_data(int fd, long offset, unsigned int size) ! 436: { ! 437: char *data; ! 438: ! 439: data = malloc(size); ! 440: if (!data) ! 441: return NULL; ! 442: lseek(fd, offset, SEEK_SET); ! 443: if (read(fd, data, size) != size) { ! 444: free(data); ! 445: return NULL; ! 446: } ! 447: return data; ! 448: } ! 449: ! 450: /* load a mach-o object file */ ! 451: int load_object(const char *filename, struct target_pt_regs * regs, void ** mh) ! 452: { ! 453: int need_bswap = 0; ! 454: int entry_point = 0; ! 455: int dyld_entry_point = 0; ! 456: int slide, mmapfixed; ! 457: int fd; ! 458: struct load_command *lcmds, *lc; ! 459: int is_fat = 0; ! 460: unsigned int i, magic; ! 461: int mach_hdr_pos = 0; ! 462: struct mach_header mach_hdr; ! 463: ! 464: /* for symbol lookup whith -d flag. */ ! 465: struct symtab_command * symtabcmd = 0; ! 466: struct nlist_extended *symtab, *sym; ! 467: struct nlist *symtab_std, *syment; ! 468: char *strtab; ! 469: ! 470: fd = open(filename, O_RDONLY); ! 471: if (fd < 0) ! 472: qerror("can't open file '%s'", filename); ! 473: ! 474: /* Read magic header. */ ! 475: if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) ! 476: qerror("unable to read Magic of '%s'", filename); ! 477: ! 478: /* Check Mach identification. */ ! 479: if(magic == MH_MAGIC) ! 480: { ! 481: is_fat = 0; ! 482: need_bswap = 0; ! 483: } else if (magic == MH_CIGAM) ! 484: { ! 485: is_fat = 0; ! 486: need_bswap = 1; ! 487: } else if (magic == FAT_MAGIC) ! 488: { ! 489: is_fat = 1; ! 490: need_bswap = 0; ! 491: } else if (magic == FAT_CIGAM) ! 492: { ! 493: is_fat = 1; ! 494: need_bswap = 1; ! 495: } ! 496: else ! 497: qerror("Not a Mach-O file.", filename); ! 498: ! 499: DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]"); ! 500: if(is_fat) ! 501: { ! 502: int found = 0; ! 503: struct fat_header fh; ! 504: struct fat_arch *fa; ! 505: ! 506: lseek(fd, 0, SEEK_SET); ! 507: ! 508: /* Read Fat header. */ ! 509: if (read(fd, &fh, sizeof (fh)) != sizeof (fh)) ! 510: qerror("unable to read file header"); ! 511: ! 512: if(need_bswap) ! 513: bswap_fh(&fh); ! 514: ! 515: /* Read Fat Arch. */ ! 516: fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch); ! 517: ! 518: if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch) ! 519: qerror("unable to read file header"); ! 520: ! 521: for( i = 0; i < fh.nfat_arch; i++, fa++) ! 522: { ! 523: if(need_bswap) ! 524: bswap_fa(fa); ! 525: if(fa->cputype == TARGET_CPU_TYPE) ! 526: { ! 527: mach_hdr_pos = fa->offset; ! 528: lseek(fd, mach_hdr_pos, SEEK_SET); ! 529: ! 530: /* Read Mach header. */ ! 531: ! 532: if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header)) ! 533: qerror("unable to read file header"); ! 534: ! 535: if(mach_hdr.magic == MH_MAGIC) ! 536: need_bswap = 0; ! 537: else if (mach_hdr.magic == MH_CIGAM) ! 538: need_bswap = 1; ! 539: else ! 540: qerror("Invalid mach header in Fat Mach-O File"); ! 541: found = 1; ! 542: break; ! 543: } ! 544: } ! 545: if(!found) ! 546: qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME); ! 547: } ! 548: else ! 549: { ! 550: lseek(fd, 0, SEEK_SET); ! 551: /* Read Mach header */ ! 552: if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr)) ! 553: qerror("%s: unable to read file header", filename); ! 554: } ! 555: ! 556: if(need_bswap) ! 557: bswap_mh(&mach_hdr); ! 558: ! 559: if ((mach_hdr.cputype) != TARGET_CPU_TYPE) ! 560: qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME); ! 561: ! 562: ! 563: switch(mach_hdr.filetype) ! 564: { ! 565: case MH_EXECUTE: break; ! 566: case MH_FVMLIB: ! 567: case MH_DYLIB: ! 568: case MH_DYLINKER: break; ! 569: default: ! 570: qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype); ! 571: } ! 572: ! 573: /* read segment headers */ ! 574: lcmds = malloc(mach_hdr.sizeofcmds); ! 575: ! 576: if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds) ! 577: qerror("%s: unable to read load_command", filename); ! 578: slide = 0; ! 579: mmapfixed = 0; ! 580: for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++) ! 581: { ! 582: ! 583: if(need_bswap) ! 584: bswap_lc(lc); ! 585: switch(lc->cmd) ! 586: { ! 587: case LC_SEGMENT: ! 588: /* The main_exe can't be relocated */ ! 589: if(mach_hdr.filetype == MH_EXECUTE) ! 590: mmapfixed = 1; ! 591: ! 592: slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide); ! 593: ! 594: /* other segment must be mapped according to slide exactly, if load_segment did something */ ! 595: if(slide != -1) ! 596: mmapfixed = 1; ! 597: else ! 598: slide = 0; /* load_segment didn't map the segment */ ! 599: ! 600: if(mach_hdr.filetype == MH_EXECUTE && slide != 0) ! 601: qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide); ! 602: ! 603: if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0) ! 604: { ! 605: /* Text section */ ! 606: if(mach_hdr.filetype == MH_EXECUTE) ! 607: { ! 608: /* return the mach_header */ ! 609: *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide); ! 610: } ! 611: else ! 612: { ! 613: /* it is dyld save the section for gdb, we will be interested in dyld symbol ! 614: while debuging */ ! 615: macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide); ! 616: macho_offset = slide; ! 617: } ! 618: } ! 619: break; ! 620: case LC_LOAD_DYLINKER: ! 621: dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap ); ! 622: break; ! 623: case LC_LOAD_DYLIB: ! 624: /* dyld will do that for us */ ! 625: break; ! 626: case LC_THREAD: ! 627: case LC_UNIXTHREAD: ! 628: { ! 629: struct target_pt_regs * _regs; ! 630: if(mach_hdr.filetype == MH_DYLINKER) ! 631: _regs = regs; ! 632: else ! 633: _regs = 0; ! 634: entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap ); ! 635: } ! 636: break; ! 637: case LC_SYMTAB: ! 638: /* Save the symtab and strtab */ ! 639: symtabcmd = (struct symtab_command *)lc; ! 640: break; ! 641: case LC_ID_DYLINKER: ! 642: case LC_ID_DYLIB: ! 643: case LC_UUID: ! 644: case LC_DYSYMTAB: ! 645: case LC_TWOLEVEL_HINTS: ! 646: case LC_PREBIND_CKSUM: ! 647: case LC_SUB_LIBRARY: ! 648: break; ! 649: default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename); ! 650: } ! 651: lc = (struct load_command*)((int)(lc)+(lc->cmdsize)); ! 652: } ! 653: ! 654: if(symtabcmd) ! 655: { ! 656: if(need_bswap) ! 657: bswap_symtabcmd(symtabcmd); ! 658: ! 659: symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist)); ! 660: strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize); ! 661: ! 662: symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms); ! 663: ! 664: if(need_bswap) ! 665: { ! 666: for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++) ! 667: bswap_sym(syment); ! 668: } ! 669: ! 670: for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++) ! 671: { ! 672: struct nlist *sym_follow, *sym_next = 0; ! 673: unsigned int j; ! 674: memset(sym, 0, sizeof(*sym)); ! 675: ! 676: sym->n_type = syment->n_type; ! 677: if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */ ! 678: continue; ! 679: ! 680: memcpy(sym, syment, sizeof(*syment)); ! 681: ! 682: /* Find the following symbol in order to get the current symbol size */ ! 683: for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) { ! 684: if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value)) ! 685: continue; ! 686: if(!sym_next) { ! 687: sym_next = sym_follow; ! 688: continue; ! 689: } ! 690: if(!(sym_next->n_value > sym_follow->n_value)) ! 691: continue; ! 692: sym_next = sym_follow; ! 693: } ! 694: if(sym_next) ! 695: sym->st_size = sym_next->n_value - sym->st_value; ! 696: else ! 697: sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */ ! 698: ! 699: sym->st_value += slide; ! 700: } ! 701: ! 702: free((void*)symtab_std); ! 703: ! 704: { ! 705: DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms); ! 706: struct syminfo *s; ! 707: s = malloc(sizeof(*s)); ! 708: s->disas_symtab = symtab; ! 709: s->disas_strtab = strtab; ! 710: s->disas_num_syms = symtabcmd->nsyms; ! 711: s->next = syminfos; ! 712: syminfos = s; ! 713: } ! 714: } ! 715: close(fd); ! 716: if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point) ! 717: return dyld_entry_point; ! 718: else ! 719: return entry_point+slide; ! 720: } ! 721: ! 722: extern unsigned long stack_size; ! 723: ! 724: unsigned long setup_arg_pages(void * mh, char ** argv, char ** env) ! 725: { ! 726: unsigned long stack_base, error, size; ! 727: int i; ! 728: int * stack; ! 729: int argc, envc; ! 730: ! 731: /* Create enough stack to hold everything. If we don't use ! 732: * it for args, we'll use it for something else... ! 733: */ ! 734: size = stack_size; ! 735: ! 736: error = target_mmap(0, ! 737: size + qemu_host_page_size, ! 738: PROT_READ | PROT_WRITE, ! 739: MAP_PRIVATE | MAP_ANONYMOUS, ! 740: -1, 0); ! 741: if (error == -1) ! 742: qerror("stk mmap"); ! 743: ! 744: /* we reserve one extra page at the top of the stack as guard */ ! 745: target_mprotect(error + size, qemu_host_page_size, PROT_NONE); ! 746: ! 747: stack_base = error + size; ! 748: stack = (void*)stack_base; ! 749: /* ! 750: * | STRING AREA | ! 751: * +-------------+ ! 752: * | 0 | ! 753: * +-------------+ ! 754: * | apple[n] | ! 755: * +-------------+ ! 756: * : ! 757: * +-------------+ ! 758: * | apple[0] | ! 759: * +-------------+ ! 760: * | 0 | ! 761: * +-------------+ ! 762: * | env[n] | ! 763: * +-------------+ ! 764: * : ! 765: * : ! 766: * +-------------+ ! 767: * | env[0] | ! 768: * +-------------+ ! 769: * | 0 | ! 770: * +-------------+ ! 771: * | arg[argc-1] | ! 772: * +-------------+ ! 773: * : ! 774: * : ! 775: * +-------------+ ! 776: * | arg[0] | ! 777: * +-------------+ ! 778: * | argc | ! 779: * +-------------+ ! 780: * sp-> | mh | address of where the a.out's file offset 0 is in memory ! 781: * +-------------+ ! 782: */ ! 783: /* Construct the stack Stack grows down */ ! 784: stack--; ! 785: ! 786: /* XXX: string should go up there */ ! 787: ! 788: *stack = 0; ! 789: stack--; ! 790: ! 791: /* Push the absolute path of our executable */ ! 792: DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]); ! 793: stl(stack, (int) argv[0]); ! 794: ! 795: stack--; ! 796: ! 797: stl(stack, 0); ! 798: stack--; ! 799: ! 800: /* Get envc */ ! 801: for(envc = 0; env[envc]; envc++); ! 802: ! 803: for(i = envc-1; i >= 0; i--) ! 804: { ! 805: DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]); ! 806: stl(stack, (int)env[i]); ! 807: stack--; ! 808: ! 809: /* XXX: remove that when string will be on top of the stack */ ! 810: page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID); ! 811: } ! 812: ! 813: /* Add on the stack the interp_prefix choosen if so */ ! 814: if(interp_prefix[0]) ! 815: { ! 816: char *dyld_root; ! 817: asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix); ! 818: page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID); ! 819: ! 820: stl(stack, (int)dyld_root); ! 821: stack--; ! 822: } ! 823: ! 824: #ifdef DONT_USE_DYLD_SHARED_MAP ! 825: { ! 826: char *shared_map_mode; ! 827: asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid"); ! 828: page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID); ! 829: ! 830: stl(stack, (int)shared_map_mode); ! 831: stack--; ! 832: } ! 833: #endif ! 834: ! 835: #ifdef ACTIVATE_DYLD_TRACE ! 836: char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes", ! 837: "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes", ! 838: "DYLD_PRINT_INITIALIZERS=yes", ! 839: "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" }; ! 840: ! 841: char ** extra_env = malloc(sizeof(extra_env_static)); ! 842: bcopy(extra_env_static, extra_env, sizeof(extra_env_static)); ! 843: page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID); ! 844: ! 845: for(i = 0; i<9; i++) ! 846: { ! 847: DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]); ! 848: stl(stack, (int) extra_env[i]); ! 849: stack--; ! 850: } ! 851: #endif ! 852: ! 853: stl(stack, 0); ! 854: stack--; ! 855: ! 856: /* Get argc */ ! 857: for(argc = 0; argv[argc]; argc++); ! 858: ! 859: for(i = argc-1; i >= 0; i--) ! 860: { ! 861: DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]); ! 862: stl(stack, (int) argv[i]); ! 863: stack--; ! 864: ! 865: /* XXX: remove that when string will be on top of the stack */ ! 866: page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID); ! 867: } ! 868: ! 869: DPRINTF("pushing argc %d \n", argc); ! 870: stl(stack, argc); ! 871: stack--; ! 872: ! 873: DPRINTF("pushing mh 0x%x \n", (int)mh); ! 874: stl(stack, (int) mh); ! 875: ! 876: /* Stack points on the mh */ ! 877: return (unsigned long)stack; ! 878: } ! 879: ! 880: int mach_exec(const char * filename, char ** argv, char ** envp, ! 881: struct target_pt_regs * regs) ! 882: { ! 883: int entrypoint, stack; ! 884: void * mh; /* the Mach Header that will be used by dyld */ ! 885: ! 886: DPRINTF("mach_exec at 0x%x\n", (int)mach_exec); ! 887: ! 888: entrypoint = load_object(filename, regs, &mh); ! 889: stack = setup_arg_pages(mh, argv, envp); ! 890: #if defined(TARGET_I386) ! 891: regs->eip = entrypoint; ! 892: regs->esp = stack; ! 893: #elif defined(TARGET_PPC) ! 894: regs->nip = entrypoint; ! 895: regs->gpr[1] = stack; ! 896: #endif ! 897: DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh); ! 898: ! 899: if(!entrypoint) ! 900: qerror("%s: no entry point!\n", filename); ! 901: ! 902: return 0; ! 903: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.