1 /* Dump Emacs in macho format.
2 Copyright (C) 1990, 1993, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4 Written by Bradley Taylor (btaylor@next.com).
6 This file is part of GNU Emacs.
8 GNU Emacs is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
29 #include <mach/mach.h>
30 #include <mach-o/loader.h>
31 #include <mach-o/reloc.h>
35 /* Instead of unistd.h, this used to include libc.h.
36 "Nelson H. F. Beebe" <beebe@math.utah.edu> says that doesn't work
37 in system version 3.3. */
43 * Kludge: we don't expect any program data beyond VM_HIGHDATA
44 * What is really needed is a way to find out from malloc() which
45 * pages it vm_allocated and write only those out into the data segment.
47 * This kludge may break when we stop using fixed virtual address
48 * shared libraries. Actually, emacs will probably continue working, but be
49 * much larger on disk than it needs to be (because non-malloced data will
52 static const unsigned VM_HIGHDATA
= 0x2000000;
54 typedef struct region_t
{
58 vm_prot_t max_protection
;
59 vm_inherit_t inheritance
;
68 struct load_command
***the_commands
,
69 unsigned *the_commands_len
72 if (*the_commands
== NULL
) {
73 *the_commands_len
= 1;
74 *the_commands
= malloc(sizeof(*the_commands
));
76 (*the_commands_len
)++;
77 *the_commands
= realloc(*the_commands
,
79 sizeof(**the_commands
)));
86 struct load_command
*command
,
87 struct load_command
***the_commands
,
88 unsigned *the_commands_len
91 struct load_command
**tmp
;
93 grow(the_commands
, the_commands_len
);
94 tmp
= &(*the_commands
)[*the_commands_len
- 1];
95 *tmp
= malloc(command
->cmdsize
);
96 bcopy(command
, *tmp
, command
->cmdsize
);
100 fatal_unexec(char *format
, ...)
104 va_start(ap
, format
);
105 fprintf(stderr
, "unexec: ");
106 vfprintf(stderr
, format
, ap
);
107 fprintf(stderr
, "\n");
114 struct mach_header
*the_header
,
115 struct load_command
***the_commands
,
116 unsigned *the_commands_len
119 struct load_command command
;
120 struct load_command
*buf
;
124 if (read(fd
, the_header
, sizeof(*the_header
)) != sizeof(*the_header
)) {
125 fatal_unexec("cannot read macho header");
128 for (i
= 0; i
< the_header
->ncmds
; i
++) {
129 if (read(fd
, &command
, sizeof(struct load_command
)) !=
130 sizeof(struct load_command
)) {
131 fatal_unexec("cannot read macho load command header");
134 size
= command
.cmdsize
- sizeof(struct load_command
);
136 fatal_unexec("bogus load command size");
139 buf
= malloc(command
.cmdsize
);
140 buf
->cmd
= command
.cmd
;
141 buf
->cmdsize
= command
.cmdsize
;
142 if (read(fd
, ((char *)buf
+
143 sizeof(struct load_command
)),
145 fatal_unexec("cannot read load command data");
148 save_command(buf
, the_commands
, the_commands_len
);
155 vm_address_t start_address
,
157 vm_address_t end_address
160 vm_address_t address
;
163 address
= (start_address
+ *size
);
164 gapsize
= end_address
- address
;
166 if (vm_allocate(task_self(), &address
, gapsize
,
167 FALSE
) != KERN_SUCCESS
) {
168 fatal_unexec("cannot vm_allocate");
176 vm_address_t
*address
,
182 struct section
*sect
;
184 sect
= (struct section
*) getsectbyname(SEG_DATA
, SECT_DATA
);
188 ret
= vm_region(task_self(),
192 ®ion
.max_protection
,
197 if (ret
!= KERN_SUCCESS
|| region
.address
>= VM_HIGHDATA
) {
201 if (region
.address
> *address
+ *size
) {
202 if (!filldatagap(*address
, size
,
207 *size
+= region
.size
;
209 if (region
.address
== sect
->addr
) {
210 *address
= region
.address
;
214 region
.address
+= region
.size
;
224 vm_address_t address
;
226 if (vm_allocate(task_self(), &address
, size
, TRUE
) != KERN_SUCCESS
) {
229 return ((char *)address
);
238 vm_deallocate(task_self(), (vm_address_t
)buf
, size
);
248 struct load_command
**the_commands
= NULL
;
249 unsigned the_commands_len
;
250 struct mach_header the_header
;
257 vm_address_t data_address
;
259 vm_size_t vmaddr_growth
= 0;
260 vm_size_t dataseg_vmaddr
, dataseg_vmend
;
262 struct segment_command
*segment
;
265 unsigned long extreloff
= 0;
266 unsigned long nextrel
= 0;
267 struct dysymtab_command
*dysymtab
;
268 struct relocation_info reloc_info
;
271 if (!read_macho(infd
, &the_header
, &the_commands
, &the_commands_len
)) {
276 malloc_cookie
= malloc_freezedry ();
277 if (!get_data_region(&data_address
, &data_size
)) {
283 * DO NOT USE MALLOC IN THIS SECTION
289 for (i
= 0; i
< the_commands_len
; i
++) {
290 switch (the_commands
[i
]->cmd
) {
292 segment
= ((struct segment_command
*)
294 if (strcmp(segment
->segname
, SEG_DATA
) == 0) {
295 fdatastart
= segment
->fileoff
;
296 fdatasize
= segment
->filesize
;
297 fgrowth
= (data_size
-
299 segment
->vmsize
= data_size
;
300 segment
->filesize
= data_size
;
301 dataseg_vmaddr
= segment
->vmaddr
;
302 dataseg_vmend
= segment
->vmaddr
+ segment
->vmsize
;
303 vmaddr_growth
= segment
->vmaddr
+ segment
->vmsize
;
305 ((struct segment_command
*)the_commands
[i
])->fileoff
+= fgrowth
;
308 if( strcmp( segment
->segname
, SEG_LINKEDIT
) == 0 ) {
309 segment
->vmaddr
= vmaddr_growth
;
314 ((struct symtab_command
*)
315 the_commands
[i
])->symoff
+= fgrowth
;
316 ((struct symtab_command
*)
317 the_commands
[i
])->stroff
+= fgrowth
;
320 ((struct symseg_command
*)
321 the_commands
[i
])->offset
+= fgrowth
;
325 dysymtab
= ((struct dysymtab_command
*)the_commands
[i
]);
326 extreloff
= dysymtab
->extreloff
;
327 nextrel
= dysymtab
->nextrel
;
328 dysymtab
->indirectsymoff
+= fgrowth
;
329 dysymtab
->extreloff
+= fgrowth
;
340 if (write(outfd
, &the_header
,
341 sizeof(the_header
)) != sizeof(the_header
)) {
342 fatal_unexec("cannot write output file");
349 for (i
= 0; i
< the_commands_len
; i
++) {
350 if (write(outfd
, the_commands
[i
],
351 the_commands
[i
]->cmdsize
) !=
352 the_commands
[i
]->cmdsize
) {
353 fatal_unexec("cannot write output file");
359 * Write original text
361 if (lseek(infd
, the_header
.sizeofcmds
+ sizeof(the_header
),
363 fatal_unexec("cannot seek input file");
366 size
= fdatastart
- (sizeof(the_header
) +
367 the_header
.sizeofcmds
);
368 buf
= my_malloc(size
);
369 if (read(infd
, buf
, size
) != size
) {
371 fatal_unexec("cannot read input file");
373 if (write(outfd
, buf
, size
) != size
) {
375 fatal_unexec("cannot write output file");
384 if (write(outfd
, (char *)data_address
,
385 data_size
) != data_size
) {
386 fatal_unexec("cannot write output file");
393 * OKAY TO USE MALLOC NOW
400 if (lseek(infd
, fdatasize
, L_INCR
) < 0) {
401 fatal_unexec("cannot seek input file");
404 size
= st
.st_size
- lseek(infd
, 0, L_INCR
);
407 if (read(infd
, buf
, size
) != size
) {
409 fatal_unexec("cannot read input file");
412 if (write(outfd
, buf
, size
) != size
) {
414 fatal_unexec("cannot write output file");
421 * Fix up relocation entries in the data segment.
424 if (lseek(infd
, extreloff
, L_SET
) < 0) {
425 fatal_unexec("cannot seek input file");
429 for (i
= 0; i
< nextrel
; i
++)
433 if (read(infd
, &reloc_info
, sizeof (reloc_info
)) != sizeof (reloc_info
)) {
434 fatal_unexec("cannot read input file");
437 if (reloc_info
.r_address
>= dataseg_vmaddr
&& reloc_info
.r_address
< dataseg_vmend
)
439 if (lseek (outfd
, fdatastart
+ reloc_info
.r_address
- dataseg_vmaddr
, L_SET
) < 0 ) {
440 fatal_unexec("cannot seek input file");
443 switch (reloc_info
.r_length
) {
445 if (write(outfd
, &zeroval
, 1) != 1) {
446 fatal_unexec("cannot write output file");
451 if (write(outfd
, &zeroval
, 2) != 2) {
452 fatal_unexec("cannot write output file");
457 if (write(outfd
, &zeroval
, 4) != 4) {
458 fatal_unexec("cannot write output file");
478 char tmpbuf
[L_tmpnam
];
481 infd
= open(infile
, O_RDONLY
, 0);
483 fatal_unexec("cannot open input file `%s'", infile
);
488 tmpfile
= rindex(tmpbuf
, '/');
489 if (tmpfile
== NULL
) {
494 outfd
= open(tmpfile
, O_WRONLY
|O_TRUNC
|O_CREAT
, 0755);
497 fatal_unexec("cannot open tmp file `%s'", tmpfile
);
500 if (!unexec_doit(infd
, outfd
)) {
508 if (rename(tmpfile
, outfile
) < 0) {
510 fatal_unexec("cannot rename `%s' to `%s'", tmpfile
, outfile
);
515 /* arch-tag: 9796bdc3-c050-417a-b2f5-4cfd31032634
516 (do not change this comment) */