Add an undo command to url-cookie-mode
[emacs.git] / src / unexcw.c
blob762b996e4b67ed3fe6af8e1aee405ff992c8f754
1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004-2018 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 (at
11 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 <https://www.gnu.org/licenses/>. */
21 #include <config.h>
22 #include "unexec.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"
33 ** header for Windows executable files
35 typedef struct
37 FILHDR file_header;
38 PEAOUTHDR file_optional_header;
39 SCNHDR section_header[32];
40 } exe_header_t;
42 int debug_unexcw = 0;
45 ** Read the header from the executable into memory so we can more easily access it.
47 static exe_header_t *
48 read_exe_header (int fd, exe_header_t * exe_header_buffer)
50 int i;
51 int ret;
53 assert (fd >= 0);
54 assert (exe_header_buffer != 0);
56 ret = lseek (fd, 0L, SEEK_SET);
57 assert (ret != -1);
59 ret =
60 read (fd, &exe_header_buffer->file_header,
61 sizeof (exe_header_buffer->file_header));
62 assert (ret == sizeof (exe_header_buffer->file_header));
64 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
65 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
66 #ifdef __x86_64__
67 assert (exe_header_buffer->file_header.f_magic == 0x8664);
68 #else
69 assert (exe_header_buffer->file_header.f_magic == 0x014c);
70 #endif
71 assert (exe_header_buffer->file_header.f_nscns > 0);
72 assert (exe_header_buffer->file_header.f_nscns <=
73 ARRAYELTS (exe_header_buffer->section_header));
74 assert (exe_header_buffer->file_header.f_opthdr > 0);
76 ret =
77 read (fd, &exe_header_buffer->file_optional_header,
78 sizeof (exe_header_buffer->file_optional_header));
79 assert (ret == sizeof (exe_header_buffer->file_optional_header));
81 #ifdef __x86_64__
82 assert (exe_header_buffer->file_optional_header.magic == 0x020b);
83 #else
84 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
85 #endif
87 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
89 ret =
90 read (fd, &exe_header_buffer->section_header[i],
91 sizeof (exe_header_buffer->section_header[i]));
92 assert (ret == sizeof (exe_header_buffer->section_header[i]));
95 return (exe_header_buffer);
99 ** Fix the dumped emacs executable:
101 ** - copy .data section data of interest from running executable into
102 ** output .exe file
104 ** - convert .bss section into an initialized data section (like
105 ** .data) and copy .bss section data of interest from running
106 ** executable into output .exe file
108 static void
109 fixup_executable (int fd)
111 exe_header_t exe_header_buffer;
112 exe_header_t *exe_header;
113 int i;
114 int ret;
115 int found_data = 0;
116 int found_bss = 0;
118 exe_header = read_exe_header (fd, &exe_header_buffer);
119 assert (exe_header != 0);
121 assert (exe_header->file_header.f_nscns > 0);
122 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
124 unsigned long start_address =
125 exe_header->section_header[i].s_vaddr +
126 exe_header->file_optional_header.ImageBase;
127 unsigned long end_address =
128 exe_header->section_header[i].s_vaddr +
129 exe_header->file_optional_header.ImageBase +
130 exe_header->section_header[i].s_paddr;
131 if (debug_unexcw)
132 printf ("%8s start %#lx end %#lx\n",
133 exe_header->section_header[i].s_name,
134 start_address, end_address);
135 if (my_edata >= (char *) start_address
136 && my_edata < (char *) end_address)
138 /* data section */
139 ret =
140 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
141 SEEK_SET);
142 assert (ret != -1);
143 ret =
144 write (fd, (char *) start_address,
145 my_edata - (char *) start_address);
146 assert (ret == my_edata - (char *) start_address);
147 ++found_data;
148 if (debug_unexcw)
149 printf (" .data, mem start %#lx mem length %td\n",
150 start_address, my_edata - (char *) start_address);
151 if (debug_unexcw)
152 printf (" .data, file start %d file length %d\n",
153 (int) exe_header->section_header[i].s_scnptr,
154 (int) exe_header->section_header[i].s_paddr);
156 else if (my_endbss >= (char *) start_address
157 && my_endbss < (char *) end_address)
159 /* bss section */
160 ++found_bss;
161 if (exe_header->section_header[i].s_flags & 0x00000080)
163 /* convert uninitialized data section to initialized data section */
164 struct stat statbuf;
165 ret = fstat (fd, &statbuf);
166 assert (ret != -1);
168 exe_header->section_header[i].s_flags &= ~0x00000080;
169 exe_header->section_header[i].s_flags |= 0x00000040;
171 exe_header->section_header[i].s_scnptr =
172 (statbuf.st_size +
173 exe_header->file_optional_header.FileAlignment) /
174 exe_header->file_optional_header.FileAlignment *
175 exe_header->file_optional_header.FileAlignment;
177 exe_header->section_header[i].s_size =
178 (exe_header->section_header[i].s_paddr +
179 exe_header->file_optional_header.FileAlignment) /
180 exe_header->file_optional_header.FileAlignment *
181 exe_header->file_optional_header.FileAlignment;
183 /* Make sure the generated bootstrap binary isn't
184 * sparse. NT doesn't use a file cache for sparse
185 * executables, so if we bootstrap Emacs using a sparse
186 * bootstrap-emacs.exe, bootstrap takes about twenty
187 * times longer than it would otherwise. */
189 ret = posix_fallocate (fd,
190 ( exe_header->section_header[i].s_scnptr +
191 exe_header->section_header[i].s_size ),
194 assert (ret != -1);
196 ret =
197 lseek (fd,
198 (long) (exe_header->section_header[i].s_scnptr +
199 exe_header->section_header[i].s_size - 1),
200 SEEK_SET);
201 assert (ret != -1);
202 ret = write (fd, "", 1);
203 assert (ret == 1);
205 ret =
206 lseek (fd,
207 (long) ((char *) &exe_header->section_header[i] -
208 (char *) exe_header), SEEK_SET);
209 assert (ret != -1);
210 ret =
211 write (fd, &exe_header->section_header[i],
212 sizeof (exe_header->section_header[i]));
213 assert (ret == sizeof (exe_header->section_header[i]));
214 if (debug_unexcw)
215 printf (" seek to %ld, write %zu\n",
216 (long) ((char *) &exe_header->section_header[i] -
217 (char *) exe_header),
218 sizeof (exe_header->section_header[i]));
220 /* write initialized data section */
221 ret =
222 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
223 SEEK_SET);
224 assert (ret != -1);
225 ret =
226 write (fd, (char *) start_address,
227 my_endbss - (char *) start_address);
228 assert (ret == (my_endbss - (char *) start_address));
229 if (debug_unexcw)
230 printf (" .bss, mem start %#lx mem length %td\n",
231 start_address, my_endbss - (char *) start_address);
232 if (debug_unexcw)
233 printf (" .bss, file start %d file length %d\n",
234 (int) exe_header->section_header[i].s_scnptr,
235 (int) exe_header->section_header[i].s_paddr);
238 assert (found_bss == 1);
239 assert (found_data == 1);
243 ** Windows likes .exe suffixes on executables.
245 static char *
246 add_exe_suffix_if_necessary (const char *name, char *modified)
248 int i = strlen (name);
249 if (i <= (sizeof (DOTEXE) - 1))
251 sprintf (modified, "%s%s", name, DOTEXE);
253 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
255 strcpy (modified, name);
257 else
259 sprintf (modified, "%s%s", name, DOTEXE);
261 return (modified);
264 void
265 unexec (const char *outfile, const char *infile)
267 char infile_buffer[FILENAME_MAX];
268 char outfile_buffer[FILENAME_MAX];
269 int fd_in;
270 int fd_out;
271 int ret;
272 int ret2;
274 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
275 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
277 fd_in = emacs_open (infile, O_RDONLY, 0);
278 assert (fd_in >= 0);
279 fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT, 0755);
280 assert (fd_out >= 0);
281 for (;;)
283 char buffer[4096];
284 ret = read (fd_in, buffer, sizeof (buffer));
285 if (ret == 0)
287 /* eof */
288 break;
290 assert (ret > 0);
291 /* data */
292 ret2 = write (fd_out, buffer, ret);
293 assert (ret2 == ret);
295 ret = emacs_close (fd_in);
296 assert (ret == 0);
298 fixup_executable (fd_out);
300 ret = emacs_close (fd_out);
301 assert (ret == 0);