1 /* Dump Emacs in macho format.
2 Copyright (C) 1990, 1993 Free Software Foundation, Inc.
3 Written by Bradley Taylor (btaylor@next.com).
5 This file is part of GNU Emacs.
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 2, or (at your option)
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.
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, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
28 #include <mach/mach.h>
29 #include <mach-o/loader.h>
38 * Kludge: we don't expect any program data beyond VM_HIGHDATA
39 * What is really needed is a way to find out from malloc() which
40 * pages it vm_allocated and write only those out into the data segment.
42 * This kludge may break when we stop using fixed virtual address
43 * shared libraries. Actually, emacs will probably continue working, but be
44 * much larger on disk than it needs to be (because non-malloced data will
47 static const unsigned VM_HIGHDATA
= 0x2000000;
49 typedef struct region_t
{
53 vm_prot_t max_protection
;
54 vm_inherit_t inheritance
;
63 struct load_command
***the_commands
,
64 unsigned *the_commands_len
67 if (*the_commands
== NULL
) {
68 *the_commands_len
= 1;
69 *the_commands
= malloc(sizeof(*the_commands
));
71 (*the_commands_len
)++;
72 *the_commands
= realloc(*the_commands
,
74 sizeof(**the_commands
)));
81 struct load_command
*command
,
82 struct load_command
***the_commands
,
83 unsigned *the_commands_len
86 struct load_command
**tmp
;
88 grow(the_commands
, the_commands_len
);
89 tmp
= &(*the_commands
)[*the_commands_len
- 1];
90 *tmp
= malloc(command
->cmdsize
);
91 bcopy(command
, *tmp
, command
->cmdsize
);
95 fatal_unexec(char *format
, ...)
100 fprintf(stderr
, "unexec: ");
101 vfprintf(stderr
, format
, ap
);
102 fprintf(stderr
, "\n");
109 struct mach_header
*the_header
,
110 struct load_command
***the_commands
,
111 unsigned *the_commands_len
114 struct load_command command
;
115 struct load_command
*buf
;
119 if (read(fd
, the_header
, sizeof(*the_header
)) != sizeof(*the_header
)) {
120 fatal_unexec("cannot read macho header");
123 for (i
= 0; i
< the_header
->ncmds
; i
++) {
124 if (read(fd
, &command
, sizeof(struct load_command
)) !=
125 sizeof(struct load_command
)) {
126 fatal_unexec("cannot read macho load command header");
129 size
= command
.cmdsize
- sizeof(struct load_command
);
131 fatal_unexec("bogus load command size");
134 buf
= malloc(command
.cmdsize
);
135 buf
->cmd
= command
.cmd
;
136 buf
->cmdsize
= command
.cmdsize
;
137 if (read(fd
, ((char *)buf
+
138 sizeof(struct load_command
)),
140 fatal_unexec("cannot read load command data");
143 save_command(buf
, the_commands
, the_commands_len
);
150 vm_address_t start_address
,
152 vm_address_t end_address
155 vm_address_t address
;
158 address
= (start_address
+ *size
);
159 gapsize
= end_address
- address
;
161 if (vm_allocate(task_self(), &address
, gapsize
,
162 FALSE
) != KERN_SUCCESS
) {
163 fatal_unexec("cannot vm_allocate");
171 vm_address_t
*address
,
177 struct section
*sect
;
179 sect
= (struct section
*) getsectbyname(SEG_DATA
, SECT_DATA
);
183 ret
= vm_region(task_self(),
187 ®ion
.max_protection
,
192 if (ret
!= KERN_SUCCESS
|| region
.address
>= VM_HIGHDATA
) {
196 if (region
.address
> *address
+ *size
) {
197 if (!filldatagap(*address
, size
,
202 *size
+= region
.size
;
204 if (region
.address
== sect
->addr
) {
205 *address
= region
.address
;
209 region
.address
+= region
.size
;
219 vm_address_t address
;
221 if (vm_allocate(task_self(), &address
, size
, TRUE
) != KERN_SUCCESS
) {
224 return ((char *)address
);
233 vm_deallocate(task_self(), (vm_address_t
)buf
, size
);
243 struct load_command
**the_commands
= NULL
;
244 unsigned the_commands_len
;
245 struct mach_header the_header
;
252 vm_address_t data_address
;
255 struct segment_command
*segment
;
257 if (!read_macho(infd
, &the_header
, &the_commands
, &the_commands_len
)) {
262 malloc_cookie
= malloc_freezedry ();
263 if (!get_data_region(&data_address
, &data_size
)) {
269 * DO NOT USE MALLOC IN THIS SECTION
275 for (i
= 0; i
< the_commands_len
; i
++) {
276 switch (the_commands
[i
]->cmd
) {
278 segment
= ((struct segment_command
*)
280 if (strcmp(segment
->segname
, SEG_DATA
) == 0) {
281 fdatastart
= segment
->fileoff
;
282 fdatasize
= segment
->filesize
;
283 fgrowth
= (data_size
-
285 segment
->vmsize
= data_size
;
286 segment
->filesize
= data_size
;
290 ((struct symtab_command
*)
291 the_commands
[i
])->symoff
+= fgrowth
;
292 ((struct symtab_command
*)
293 the_commands
[i
])->stroff
+= fgrowth
;
296 ((struct symseg_command
*)
297 the_commands
[i
])->offset
+= fgrowth
;
307 if (write(outfd
, &the_header
,
308 sizeof(the_header
)) != sizeof(the_header
)) {
309 fatal_unexec("cannot write output file");
316 for (i
= 0; i
< the_commands_len
; i
++) {
317 if (write(outfd
, the_commands
[i
],
318 the_commands
[i
]->cmdsize
) !=
319 the_commands
[i
]->cmdsize
) {
320 fatal_unexec("cannot write output file");
326 * Write original text
328 if (lseek(infd
, the_header
.sizeofcmds
+ sizeof(the_header
),
330 fatal_unexec("cannot seek input file");
333 size
= fdatastart
- (sizeof(the_header
) +
334 the_header
.sizeofcmds
);
335 buf
= my_malloc(size
);
336 if (read(infd
, buf
, size
) != size
) {
338 fatal_unexec("cannot read input file");
340 if (write(outfd
, buf
, size
) != size
) {
342 fatal_unexec("cannot write output file");
351 if (write(outfd
, (char *)data_address
,
352 data_size
) != data_size
) {
353 fatal_unexec("cannot write output file");
360 * OKAY TO USE MALLOC NOW
367 if (lseek(infd
, fdatasize
, L_INCR
) < 0) {
368 fatal_unexec("cannot seek input file");
371 size
= st
.st_size
- lseek(infd
, 0, L_INCR
);
374 if (read(infd
, buf
, size
) != size
) {
376 fatal_unexec("cannot read input file");
379 if (write(outfd
, buf
, size
) != size
) {
381 fatal_unexec("cannot write output file");
396 char tmpbuf
[L_tmpnam
];
399 infd
= open(infile
, O_RDONLY
, 0);
401 fatal_unexec("cannot open input file `%s'", infile
);
406 tmpfile
= rindex(tmpbuf
, '/');
407 if (tmpfile
== NULL
) {
412 outfd
= open(tmpfile
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0755);
415 fatal_unexec("cannot open tmp file `%s'", tmpfile
);
418 if (!unexec_doit(infd
, outfd
)) {
426 if (rename(tmpfile
, outfile
) < 0) {
428 fatal_unexec("cannot rename `%s' to `%s'", tmpfile
, outfile
);