|
|
1.1 ! root 1: /* Dump Emacs in macho format. ! 2: Copyright (C) 1990 Free Software Foundation, Inc. ! 3: Written by Bradley Taylor ([email protected]). ! 4: ! 5: This file is part of GNU Emacs. ! 6: ! 7: GNU Emacs is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 1, or (at your option) ! 10: any later version. ! 11: ! 12: GNU Emacs is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU Emacs; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: ! 22: #undef __STRICT_BSD__ ! 23: ! 24: #include <stdio.h> ! 25: #include <stdlib.h> ! 26: #include <stdarg.h> ! 27: #include <mach/mach.h> ! 28: #include <mach-o/loader.h> ! 29: #include <mach-o/fat.h> ! 30: #include <sys/file.h> ! 31: #include <sys/stat.h> ! 32: #include <libc.h> ! 33: ! 34: int malloc_cookie; ! 35: ! 36: /* ! 37: * Kludge: we don't expect any program data beyond VM_HIGHDATA ! 38: * What is really needed is a way to find out from malloc() which ! 39: * pages it vm_allocated and write only those out into the data segment. ! 40: * ! 41: * This kludge may break when we stop using fixed virtual address ! 42: * shared libraries. Actually, emacs will probably continue working, but be ! 43: * much larger on disk than it needs to be (because non-malloced data will ! 44: * be in the file). ! 45: */ ! 46: static const unsigned VM_HIGHDATA = 0x2000000; ! 47: ! 48: typedef struct region_t { ! 49: vm_address_t address; ! 50: vm_size_t size; ! 51: vm_prot_t protection; ! 52: vm_prot_t max_protection; ! 53: vm_inherit_t inheritance; ! 54: boolean_t shared; ! 55: port_t object_name; ! 56: vm_offset_t offset; ! 57: } region_t; ! 58: ! 59: ! 60: static void ! 61: grow( ! 62: struct load_command ***the_commands, ! 63: unsigned *the_commands_len ! 64: ) ! 65: { ! 66: if (*the_commands == NULL) { ! 67: *the_commands_len = 1; ! 68: *the_commands = malloc(sizeof(*the_commands)); ! 69: } else { ! 70: (*the_commands_len)++; ! 71: *the_commands = realloc(*the_commands, ! 72: (*the_commands_len * ! 73: sizeof(**the_commands))); ! 74: } ! 75: } ! 76: ! 77: ! 78: static void ! 79: save_command( ! 80: struct load_command *command, ! 81: struct load_command ***the_commands, ! 82: unsigned *the_commands_len ! 83: ) ! 84: { ! 85: struct load_command **tmp; ! 86: ! 87: grow(the_commands, the_commands_len); ! 88: tmp = &(*the_commands)[*the_commands_len - 1]; ! 89: *tmp = malloc(command->cmdsize); ! 90: bcopy(command, *tmp, command->cmdsize); ! 91: } ! 92: ! 93: static void ! 94: fatal_unexec(char *format, ...) ! 95: { ! 96: va_list ap; ! 97: ! 98: va_start(ap, format); ! 99: fprintf(stderr, "unexec: "); ! 100: vfprintf(stderr, format, ap); ! 101: fprintf(stderr, "\n"); ! 102: va_end(ap); ! 103: } ! 104: ! 105: static int ! 106: read_macho( ! 107: int fd, ! 108: struct mach_header *the_header, ! 109: struct load_command ***the_commands, ! 110: unsigned *the_commands_len ! 111: ) ! 112: { ! 113: struct load_command command; ! 114: struct load_command *buf; ! 115: int i; ! 116: int size; ! 117: ! 118: if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) { ! 119: fatal_unexec("cannot read macho header"); ! 120: return (0); ! 121: } ! 122: /* the mach header should already be in native form */ ! 123: if (the_header->magic != MH_MAGIC) { ! 124: fatal_unexec("wrong magic in macho header"); ! 125: } ! 126: for (i = 0; i < the_header->ncmds; i++) { ! 127: if (read(fd, &command, sizeof(struct load_command)) != ! 128: sizeof(struct load_command)) { ! 129: fatal_unexec("cannot read macho load command header"); ! 130: return (0); ! 131: } ! 132: size = command.cmdsize - sizeof(struct load_command); ! 133: if (size < 0) { ! 134: fatal_unexec("bogus load command size"); ! 135: return (0); ! 136: } ! 137: buf = malloc(command.cmdsize); ! 138: buf->cmd = command.cmd; ! 139: buf->cmdsize = command.cmdsize; ! 140: if (read(fd, ((char *)buf + ! 141: sizeof(struct load_command)), ! 142: size) != size) { ! 143: fatal_unexec("cannot read load command data"); ! 144: return (0); ! 145: } ! 146: save_command(buf, the_commands, the_commands_len); ! 147: } ! 148: /* Leave the file pointer at the beginning of the text segment */ ! 149: return (1); ! 150: } ! 151: ! 152: static int ! 153: filldatagap( ! 154: vm_address_t start_address, ! 155: vm_size_t *size, ! 156: vm_address_t end_address ! 157: ) ! 158: { ! 159: vm_address_t address; ! 160: vm_size_t gapsize; ! 161: ! 162: address = (start_address + *size); ! 163: gapsize = end_address - address; ! 164: *size += gapsize; ! 165: if (vm_allocate(task_self(), &address, gapsize, ! 166: FALSE) != KERN_SUCCESS) { ! 167: fatal_unexec("cannot vm_allocate"); ! 168: return (0); ! 169: } ! 170: return (1); ! 171: } ! 172: ! 173: static int ! 174: get_data_region( ! 175: vm_address_t *address, ! 176: vm_size_t *size ! 177: ) ! 178: { ! 179: region_t region; ! 180: kern_return_t ret; ! 181: const struct section *sect; ! 182: ! 183: sect = getsectbyname(SEG_DATA, SECT_DATA); ! 184: region.address = 0; ! 185: *address = 0; ! 186: for (;;) { ! 187: ret = vm_region(task_self(), ! 188: ®ion.address, ! 189: ®ion.size, ! 190: ®ion.protection, ! 191: ®ion.max_protection, ! 192: ®ion.inheritance, ! 193: ®ion.shared, ! 194: ®ion.object_name, ! 195: ®ion.offset); ! 196: if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) { ! 197: break; ! 198: } ! 199: if (*address != 0) { ! 200: if (region.address > *address + *size) { ! 201: if (!filldatagap(*address, size, ! 202: region.address)) { ! 203: return (0); ! 204: } ! 205: } ! 206: *size += region.size; ! 207: } else { ! 208: if (region.address == sect->addr) { ! 209: *address = region.address; ! 210: *size = region.size; ! 211: } ! 212: } ! 213: region.address += region.size; ! 214: } ! 215: return (1); ! 216: } ! 217: ! 218: static char * ! 219: my_malloc( ! 220: vm_size_t size ! 221: ) ! 222: { ! 223: vm_address_t address; ! 224: ! 225: if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) { ! 226: return (NULL); ! 227: } ! 228: return ((char *)address); ! 229: } ! 230: ! 231: static void ! 232: my_free( ! 233: char *buf, ! 234: vm_size_t size ! 235: ) ! 236: { ! 237: vm_deallocate(task_self(), (vm_address_t)buf, size); ! 238: } ! 239: ! 240: static int ! 241: unexec_doit( ! 242: int infd, ! 243: int outfd ! 244: ) ! 245: { ! 246: int i; ! 247: struct load_command **the_commands = NULL; ! 248: unsigned the_commands_len; ! 249: struct mach_header the_header; ! 250: int fgrowth; ! 251: int fdatastart; ! 252: int fdatasize; ! 253: int size; ! 254: struct stat st; ! 255: char *buf; ! 256: vm_address_t data_address; ! 257: vm_size_t data_size; ! 258: ! 259: struct segment_command *segment; ! 260: ! 261: if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) { ! 262: return (0); ! 263: } ! 264: ! 265: malloc_cookie = malloc_freezedry(); ! 266: ! 267: if (!get_data_region(&data_address, &data_size)) { ! 268: return (0); ! 269: } ! 270: ! 271: ! 272: /* ! 273: * DO NOT USE MALLOC IN THIS SECTION ! 274: */ ! 275: { ! 276: /* ! 277: * Fix offsets ! 278: */ ! 279: for (i = 0; i < the_commands_len; i++) { ! 280: switch (the_commands[i]->cmd) { ! 281: case LC_SEGMENT: ! 282: segment = ((struct segment_command *) ! 283: the_commands[i]); ! 284: if (strcmp(segment->segname, SEG_DATA) == 0) { ! 285: fdatastart = segment->fileoff; ! 286: fdatasize = segment->filesize; ! 287: fgrowth = (data_size - ! 288: segment->filesize); ! 289: segment->vmsize = data_size; ! 290: segment->filesize = data_size; ! 291: } ! 292: break; ! 293: case LC_SYMTAB: ! 294: ((struct symtab_command *) ! 295: the_commands[i])->symoff += fgrowth; ! 296: ((struct symtab_command *) ! 297: the_commands[i])->stroff += fgrowth; ! 298: break; ! 299: case LC_SYMSEG: ! 300: ((struct symseg_command *) ! 301: the_commands[i])->offset += fgrowth; ! 302: break; ! 303: default: ! 304: break; ! 305: } ! 306: } ! 307: ! 308: /* ! 309: * Write header ! 310: */ ! 311: if (write(outfd, &the_header, ! 312: sizeof(the_header)) != sizeof(the_header)) { ! 313: fatal_unexec("cannot write output file"); ! 314: return (0); ! 315: } ! 316: ! 317: /* ! 318: * Write commands ! 319: */ ! 320: for (i = 0; i < the_commands_len; i++) { ! 321: if (write(outfd, the_commands[i], ! 322: the_commands[i]->cmdsize) != ! 323: the_commands[i]->cmdsize) { ! 324: fatal_unexec("cannot write output file"); ! 325: return (0); ! 326: } ! 327: } ! 328: ! 329: /* ! 330: * Write original text ! 331: * We're already positioned at the beginning of the text ! 332: * segment, so all we need to do is to copy the bytes. ! 333: */ ! 334: size = fdatastart - (sizeof(the_header) + ! 335: the_header.sizeofcmds); ! 336: buf = my_malloc(size); ! 337: if (read(infd, buf, size) != size) { ! 338: my_free(buf, size); ! 339: fatal_unexec("cannot read input file"); ! 340: } ! 341: if (write(outfd, buf, size) != size) { ! 342: my_free(buf, size); ! 343: fatal_unexec("cannot write output file"); ! 344: return (0); ! 345: } ! 346: my_free(buf, size); ! 347: ! 348: ! 349: /* ! 350: * Write new data ! 351: */ ! 352: if (write(outfd, (char *)data_address, ! 353: data_size) != data_size) { ! 354: fatal_unexec("cannot write output file"); ! 355: return (0); ! 356: } ! 357: ! 358: } ! 359: ! 360: /* ! 361: * OKAY TO USE MALLOC NOW ! 362: */ ! 363: ! 364: /* ! 365: * Write rest of file ! 366: */ ! 367: fstat(infd, &st); ! 368: if (lseek(infd, fdatasize, L_INCR) < 0) { ! 369: fatal_unexec("cannot seek input file"); ! 370: return (0); ! 371: } ! 372: size = st.st_size - lseek(infd, 0, L_INCR); ! 373: ! 374: buf = malloc(size); ! 375: if (read(infd, buf, size) != size) { ! 376: free(buf); ! 377: fatal_unexec("cannot read input file"); ! 378: return (0); ! 379: } ! 380: if (write(outfd, buf, size) != size) { ! 381: free(buf); ! 382: fatal_unexec("cannot write output file"); ! 383: return (0); ! 384: } ! 385: free(buf); ! 386: return (1); ! 387: } ! 388: ! 389: void ! 390: unexec( ! 391: char *outfile, ! 392: char *infile ! 393: ) ! 394: { ! 395: int infd; ! 396: int outfd; ! 397: char tmpbuf[L_tmpnam]; ! 398: char *tmpfile; ! 399: ! 400: infd = open(infile, O_RDONLY, 0); ! 401: if (infd < 0) { ! 402: fatal_unexec("cannot open input file `%s'", infile); ! 403: exit(1); ! 404: } ! 405: ! 406: tmpnam(tmpbuf); ! 407: tmpfile = rindex(tmpbuf, '/'); ! 408: if (tmpfile == NULL) { ! 409: tmpfile = tmpbuf; ! 410: } else { ! 411: tmpfile++; ! 412: } ! 413: outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755); ! 414: if (outfd < 0) { ! 415: close(infd); ! 416: fatal_unexec("cannot open tmp file `%s'", tmpfile); ! 417: exit(1); ! 418: } ! 419: if (!unexec_doit(infd, outfd)) { ! 420: close(infd); ! 421: close(outfd); ! 422: unlink(tmpfile); ! 423: exit(1); ! 424: } ! 425: close(infd); ! 426: close(outfd); ! 427: if (rename(tmpfile, outfile) < 0) { ! 428: unlink(tmpfile); ! 429: fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile); ! 430: exit(1); ! 431: } ! 432: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.