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