Auto-commit of generated files.
[bpt/emacs.git] / src / unexcw.c
CommitLineData
3e62da95
SM
1/* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
3
acaf905b 4 Copyright (C) 2004-2012 Free Software Foundation, Inc.
3e62da95
SM
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
3e62da95 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
3e62da95
SM
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
3e62da95
SM
20
21#include <config.h>
ce701a33
PE
22#include "unexec.h"
23
3e62da95
SM
24#include <lisp.h>
25#include <stdio.h>
26#include <fcntl.h>
27#include <a.out.h>
28#include <unistd.h>
29#include <assert.h>
30
31#define DOTEXE ".exe"
32
33extern int bss_sbrk_did_unexec;
34
a4579d33
KB
35extern int __malloc_initialized;
36
3e62da95
SM
37/* emacs symbols that indicate where bss and data end for emacs internals */
38extern char my_endbss[];
39extern char my_edata[];
40
41/*
42** header for Windows executable files
43*/
44typedef struct
45{
46 FILHDR file_header;
47 PEAOUTHDR file_optional_header;
48 SCNHDR section_header[32];
49} exe_header_t;
50
51int debug_unexcw = 0;
52
53/*
54** Read the header from the executable into memory so we can more easily access it.
55*/
56static exe_header_t *
57read_exe_header (int fd, exe_header_t * exe_header_buffer)
58{
59 int i;
60 int ret;
61
62 assert (fd >= 0);
63 assert (exe_header_buffer != 0);
64
65 ret = lseek (fd, 0L, SEEK_SET);
66 assert (ret != -1);
67
68 ret =
69 read (fd, &exe_header_buffer->file_header,
70 sizeof (exe_header_buffer->file_header));
71 assert (ret == sizeof (exe_header_buffer->file_header));
72
73 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
74 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
75 assert (exe_header_buffer->file_header.f_magic == 0x014c);
76 assert (exe_header_buffer->file_header.f_nscns > 0);
77 assert (exe_header_buffer->file_header.f_nscns <=
78 sizeof (exe_header_buffer->section_header) /
79 sizeof (exe_header_buffer->section_header[0]));
80 assert (exe_header_buffer->file_header.f_opthdr > 0);
81
82 ret =
83 read (fd, &exe_header_buffer->file_optional_header,
84 sizeof (exe_header_buffer->file_optional_header));
85 assert (ret == sizeof (exe_header_buffer->file_optional_header));
86
87 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
88
89 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
90 {
91 ret =
92 read (fd, &exe_header_buffer->section_header[i],
93 sizeof (exe_header_buffer->section_header[i]));
94 assert (ret == sizeof (exe_header_buffer->section_header[i]));
95 }
96
97 return (exe_header_buffer);
98}
99
100/*
101** Fix the dumped emacs executable:
102**
103** - copy .data section data of interest from running executable into
104** output .exe file
105**
106** - convert .bss section into an initialized data section (like
107** .data) and copy .bss section data of interest from running
108** executable into output .exe file
109*/
110static void
111fixup_executable (int fd)
112{
113 exe_header_t exe_header_buffer;
114 exe_header_t *exe_header;
115 int i;
116 int ret;
117 int found_data = 0;
118 int found_bss = 0;
119
120 exe_header = read_exe_header (fd, &exe_header_buffer);
121 assert (exe_header != 0);
122
123 assert (exe_header->file_header.f_nscns > 0);
124 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
125 {
126 unsigned long start_address =
127 exe_header->section_header[i].s_vaddr +
128 exe_header->file_optional_header.ImageBase;
129 unsigned long end_address =
130 exe_header->section_header[i].s_vaddr +
131 exe_header->file_optional_header.ImageBase +
132 exe_header->section_header[i].s_paddr;
133 if (debug_unexcw)
134 printf ("%8s start 0x%08x end 0x%08x\n",
135 exe_header->section_header[i].s_name,
136 start_address, end_address);
137 if (my_edata >= (char *) start_address
138 && my_edata < (char *) end_address)
139 {
140 /* data section */
141 ret =
142 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
143 SEEK_SET);
144 assert (ret != -1);
145 ret =
146 write (fd, (char *) start_address,
147 my_edata - (char *) start_address);
148 assert (ret == my_edata - (char *) start_address);
149 ++found_data;
150 if (debug_unexcw)
151 printf (" .data, mem start 0x%08x mem length %d\n",
152 start_address, my_edata - (char *) start_address);
153 if (debug_unexcw)
154 printf (" .data, file start %d file length %d\n",
155 (int) exe_header->section_header[i].s_scnptr,
156 (int) exe_header->section_header[i].s_paddr);
157 }
158 else if (my_endbss >= (char *) start_address
159 && my_endbss < (char *) end_address)
160 {
161 /* bss section */
162 ++found_bss;
163 if (exe_header->section_header[i].s_flags & 0x00000080)
164 {
165 /* convert uninitialized data section to initialized data section */
166 struct stat statbuf;
167 ret = fstat (fd, &statbuf);
168 assert (ret != -1);
169
170 exe_header->section_header[i].s_flags &= ~0x00000080;
171 exe_header->section_header[i].s_flags |= 0x00000040;
172
173 exe_header->section_header[i].s_scnptr =
174 (statbuf.st_size +
175 exe_header->file_optional_header.FileAlignment) /
176 exe_header->file_optional_header.FileAlignment *
177 exe_header->file_optional_header.FileAlignment;
178
179 exe_header->section_header[i].s_size =
180 (exe_header->section_header[i].s_paddr +
181 exe_header->file_optional_header.FileAlignment) /
182 exe_header->file_optional_header.FileAlignment *
183 exe_header->file_optional_header.FileAlignment;
184
185 ret =
186 lseek (fd,
187 (long) (exe_header->section_header[i].s_scnptr +
188 exe_header->section_header[i].s_size - 1),
189 SEEK_SET);
190 assert (ret != -1);
191 ret = write (fd, "", 1);
192 assert (ret == 1);
193
194 ret =
195 lseek (fd,
196 (long) ((char *) &exe_header->section_header[i] -
197 (char *) exe_header), SEEK_SET);
198 assert (ret != -1);
199 ret =
200 write (fd, &exe_header->section_header[i],
201 sizeof (exe_header->section_header[i]));
202 assert (ret == sizeof (exe_header->section_header[i]));
203 if (debug_unexcw)
204 printf (" seek to %ld, write %d\n",
205 (long) ((char *) &exe_header->section_header[i] -
206 (char *) exe_header),
207 sizeof (exe_header->section_header[i]));
208 }
209 /* write initialized data section */
210 ret =
211 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
212 SEEK_SET);
213 assert (ret != -1);
a4579d33
KB
214 /* force the dumped emacs to reinitialize malloc */
215 __malloc_initialized = 0;
3e62da95
SM
216 ret =
217 write (fd, (char *) start_address,
218 my_endbss - (char *) start_address);
a4579d33 219 __malloc_initialized = 1;
3e62da95
SM
220 assert (ret == (my_endbss - (char *) start_address));
221 if (debug_unexcw)
222 printf (" .bss, mem start 0x%08x mem length %d\n",
223 start_address, my_endbss - (char *) start_address);
224 if (debug_unexcw)
225 printf (" .bss, file start %d file length %d\n",
226 (int) exe_header->section_header[i].s_scnptr,
227 (int) exe_header->section_header[i].s_paddr);
228 }
229 }
230 assert (found_bss == 1);
231 assert (found_data == 1);
232}
233
234/*
235** Windows likes .exe suffixes on executables.
236*/
237static char *
238add_exe_suffix_if_necessary (const char *name, char *modified)
239{
240 int i = strlen (name);
241 if (i <= (sizeof (DOTEXE) - 1))
242 {
243 sprintf (modified, "%s%s", name, DOTEXE);
244 }
245 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
246 {
247 strcpy (modified, name);
248 }
249 else
250 {
251 sprintf (modified, "%s%s", name, DOTEXE);
252 }
253 return (modified);
254}
255
381259ef 256void
dd5ecd6b 257unexec (const char *outfile, const char *infile)
3e62da95
SM
258{
259 char infile_buffer[FILENAME_MAX];
260 char outfile_buffer[FILENAME_MAX];
261 int fd_in;
262 int fd_out;
263 int ret;
264 int ret2;
265
266 if (bss_sbrk_did_unexec)
267 {
268 /* can only dump once */
60a294e2 269 printf ("You can only dump Emacs once on this platform.\n");
fffe2e14 270 return;
3e62da95
SM
271 }
272
273 report_sheap_usage (1);
274
275 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
276 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
277
278 fd_in = open (infile, O_RDONLY | O_BINARY);
279 assert (fd_in >= 0);
280 fd_out = open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
281 assert (fd_out >= 0);
282 for (;;)
283 {
284 char buffer[4096];
285 ret = read (fd_in, buffer, sizeof (buffer));
286 if (ret == 0)
287 {
288 /* eof */
289 break;
290 }
291 assert (ret > 0);
292 /* data */
293 ret2 = write (fd_out, buffer, ret);
294 assert (ret2 == ret);
295 }
296 ret = close (fd_in);
297 assert (ret == 0);
298
299 bss_sbrk_did_unexec = 1;
300 fixup_executable (fd_out);
301 bss_sbrk_did_unexec = 0;
302
303 ret = close (fd_out);
304 assert (ret == 0);
3e62da95 305}