Merge from mainline.
[emacs.git] / src / unexcw.c
blob4930eb4631597ec31d6e218394857d82198b98f0
1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
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 of the License, or
11 (at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
22 #include <setjmp.h>
23 #include <lisp.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <a.out.h>
27 #include <unistd.h>
28 #include <assert.h>
30 #define DOTEXE ".exe"
32 extern int bss_sbrk_did_unexec;
34 /* emacs symbols that indicate where bss and data end for emacs internals */
35 extern char my_endbss[];
36 extern char my_edata[];
39 ** header for Windows executable files
41 typedef struct
43 FILHDR file_header;
44 PEAOUTHDR file_optional_header;
45 SCNHDR section_header[32];
46 } exe_header_t;
48 int debug_unexcw = 0;
51 ** Read the header from the executable into memory so we can more easily access it.
53 static exe_header_t *
54 read_exe_header (int fd, exe_header_t * exe_header_buffer)
56 int i;
57 int ret;
59 assert (fd >= 0);
60 assert (exe_header_buffer != 0);
62 ret = lseek (fd, 0L, SEEK_SET);
63 assert (ret != -1);
65 ret =
66 read (fd, &exe_header_buffer->file_header,
67 sizeof (exe_header_buffer->file_header));
68 assert (ret == sizeof (exe_header_buffer->file_header));
70 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
71 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
72 assert (exe_header_buffer->file_header.f_magic == 0x014c);
73 assert (exe_header_buffer->file_header.f_nscns > 0);
74 assert (exe_header_buffer->file_header.f_nscns <=
75 sizeof (exe_header_buffer->section_header) /
76 sizeof (exe_header_buffer->section_header[0]));
77 assert (exe_header_buffer->file_header.f_opthdr > 0);
79 ret =
80 read (fd, &exe_header_buffer->file_optional_header,
81 sizeof (exe_header_buffer->file_optional_header));
82 assert (ret == sizeof (exe_header_buffer->file_optional_header));
84 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
86 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
88 ret =
89 read (fd, &exe_header_buffer->section_header[i],
90 sizeof (exe_header_buffer->section_header[i]));
91 assert (ret == sizeof (exe_header_buffer->section_header[i]));
94 return (exe_header_buffer);
98 ** Fix the dumped emacs executable:
100 ** - copy .data section data of interest from running executable into
101 ** output .exe file
103 ** - convert .bss section into an initialized data section (like
104 ** .data) and copy .bss section data of interest from running
105 ** executable into output .exe file
107 static void
108 fixup_executable (int fd)
110 exe_header_t exe_header_buffer;
111 exe_header_t *exe_header;
112 int i;
113 int ret;
114 int found_data = 0;
115 int found_bss = 0;
117 exe_header = read_exe_header (fd, &exe_header_buffer);
118 assert (exe_header != 0);
120 assert (exe_header->file_header.f_nscns > 0);
121 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
123 unsigned long start_address =
124 exe_header->section_header[i].s_vaddr +
125 exe_header->file_optional_header.ImageBase;
126 unsigned long end_address =
127 exe_header->section_header[i].s_vaddr +
128 exe_header->file_optional_header.ImageBase +
129 exe_header->section_header[i].s_paddr;
130 if (debug_unexcw)
131 printf ("%8s start 0x%08x end 0x%08x\n",
132 exe_header->section_header[i].s_name,
133 start_address, end_address);
134 if (my_edata >= (char *) start_address
135 && my_edata < (char *) end_address)
137 /* data section */
138 ret =
139 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
140 SEEK_SET);
141 assert (ret != -1);
142 ret =
143 write (fd, (char *) start_address,
144 my_edata - (char *) start_address);
145 assert (ret == my_edata - (char *) start_address);
146 ++found_data;
147 if (debug_unexcw)
148 printf (" .data, mem start 0x%08x mem length %d\n",
149 start_address, my_edata - (char *) start_address);
150 if (debug_unexcw)
151 printf (" .data, file start %d file length %d\n",
152 (int) exe_header->section_header[i].s_scnptr,
153 (int) exe_header->section_header[i].s_paddr);
155 else if (my_endbss >= (char *) start_address
156 && my_endbss < (char *) end_address)
158 /* bss section */
159 ++found_bss;
160 if (exe_header->section_header[i].s_flags & 0x00000080)
162 /* convert uninitialized data section to initialized data section */
163 struct stat statbuf;
164 ret = fstat (fd, &statbuf);
165 assert (ret != -1);
167 exe_header->section_header[i].s_flags &= ~0x00000080;
168 exe_header->section_header[i].s_flags |= 0x00000040;
170 exe_header->section_header[i].s_scnptr =
171 (statbuf.st_size +
172 exe_header->file_optional_header.FileAlignment) /
173 exe_header->file_optional_header.FileAlignment *
174 exe_header->file_optional_header.FileAlignment;
176 exe_header->section_header[i].s_size =
177 (exe_header->section_header[i].s_paddr +
178 exe_header->file_optional_header.FileAlignment) /
179 exe_header->file_optional_header.FileAlignment *
180 exe_header->file_optional_header.FileAlignment;
182 ret =
183 lseek (fd,
184 (long) (exe_header->section_header[i].s_scnptr +
185 exe_header->section_header[i].s_size - 1),
186 SEEK_SET);
187 assert (ret != -1);
188 ret = write (fd, "", 1);
189 assert (ret == 1);
191 ret =
192 lseek (fd,
193 (long) ((char *) &exe_header->section_header[i] -
194 (char *) exe_header), SEEK_SET);
195 assert (ret != -1);
196 ret =
197 write (fd, &exe_header->section_header[i],
198 sizeof (exe_header->section_header[i]));
199 assert (ret == sizeof (exe_header->section_header[i]));
200 if (debug_unexcw)
201 printf (" seek to %ld, write %d\n",
202 (long) ((char *) &exe_header->section_header[i] -
203 (char *) exe_header),
204 sizeof (exe_header->section_header[i]));
206 /* write initialized data section */
207 ret =
208 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
209 SEEK_SET);
210 assert (ret != -1);
211 ret =
212 write (fd, (char *) start_address,
213 my_endbss - (char *) start_address);
214 assert (ret == (my_endbss - (char *) start_address));
215 if (debug_unexcw)
216 printf (" .bss, mem start 0x%08x mem length %d\n",
217 start_address, my_endbss - (char *) start_address);
218 if (debug_unexcw)
219 printf (" .bss, file start %d file length %d\n",
220 (int) exe_header->section_header[i].s_scnptr,
221 (int) exe_header->section_header[i].s_paddr);
224 assert (found_bss == 1);
225 assert (found_data == 1);
229 ** Windows likes .exe suffixes on executables.
231 static char *
232 add_exe_suffix_if_necessary (const char *name, char *modified)
234 int i = strlen (name);
235 if (i <= (sizeof (DOTEXE) - 1))
237 sprintf (modified, "%s%s", name, DOTEXE);
239 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
241 strcpy (modified, name);
243 else
245 sprintf (modified, "%s%s", name, DOTEXE);
247 return (modified);
251 unexec (char *outfile, char *infile, unsigned start_data, unsigned d1,
252 unsigned d2)
254 char infile_buffer[FILENAME_MAX];
255 char outfile_buffer[FILENAME_MAX];
256 int fd_in;
257 int fd_out;
258 int ret;
259 int ret2;
261 if (bss_sbrk_did_unexec)
263 /* can only dump once */
264 printf ("You can only dump Emacs once on this platform.\n");
265 return (1);
268 report_sheap_usage (1);
270 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
271 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
273 fd_in = open (infile, O_RDONLY | O_BINARY);
274 assert (fd_in >= 0);
275 fd_out = open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
276 assert (fd_out >= 0);
277 for (;;)
279 char buffer[4096];
280 ret = read (fd_in, buffer, sizeof (buffer));
281 if (ret == 0)
283 /* eof */
284 break;
286 assert (ret > 0);
287 /* data */
288 ret2 = write (fd_out, buffer, ret);
289 assert (ret2 == ret);
291 ret = close (fd_in);
292 assert (ret == 0);
294 bss_sbrk_did_unexec = 1;
295 fixup_executable (fd_out);
296 bss_sbrk_did_unexec = 0;
298 ret = close (fd_out);
299 assert (ret == 0);
301 return (0);
304 /* arch-tag: fc44f6c3-ca0a-45e0-a5a2-58b6101b1e65
305 (do not change this comment) */