Fix some file names.
[emacs.git] / src / unexcw.c
blob04f108b1beeea5936d11f5c345878b42a9999180
1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004, 2005, 2006, 2007, 2008 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 <lisp.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <a.out.h>
26 #include <unistd.h>
27 #include <assert.h>
29 #define DOTEXE ".exe"
31 extern int bss_sbrk_did_unexec;
33 /* emacs symbols that indicate where bss and data end for emacs internals */
34 extern char my_endbss[];
35 extern char my_edata[];
38 ** header for Windows executable files
40 typedef struct
42 FILHDR file_header;
43 PEAOUTHDR file_optional_header;
44 SCNHDR section_header[32];
45 } exe_header_t;
47 int debug_unexcw = 0;
50 ** Read the header from the executable into memory so we can more easily access it.
52 static exe_header_t *
53 read_exe_header (int fd, exe_header_t * exe_header_buffer)
55 int i;
56 int ret;
58 assert (fd >= 0);
59 assert (exe_header_buffer != 0);
61 ret = lseek (fd, 0L, SEEK_SET);
62 assert (ret != -1);
64 ret =
65 read (fd, &exe_header_buffer->file_header,
66 sizeof (exe_header_buffer->file_header));
67 assert (ret == sizeof (exe_header_buffer->file_header));
69 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
70 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
71 assert (exe_header_buffer->file_header.f_magic == 0x014c);
72 assert (exe_header_buffer->file_header.f_nscns > 0);
73 assert (exe_header_buffer->file_header.f_nscns <=
74 sizeof (exe_header_buffer->section_header) /
75 sizeof (exe_header_buffer->section_header[0]));
76 assert (exe_header_buffer->file_header.f_opthdr > 0);
78 ret =
79 read (fd, &exe_header_buffer->file_optional_header,
80 sizeof (exe_header_buffer->file_optional_header));
81 assert (ret == sizeof (exe_header_buffer->file_optional_header));
83 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
85 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
87 ret =
88 read (fd, &exe_header_buffer->section_header[i],
89 sizeof (exe_header_buffer->section_header[i]));
90 assert (ret == sizeof (exe_header_buffer->section_header[i]));
93 return (exe_header_buffer);
97 ** Fix the dumped emacs executable:
99 ** - copy .data section data of interest from running executable into
100 ** output .exe file
102 ** - convert .bss section into an initialized data section (like
103 ** .data) and copy .bss section data of interest from running
104 ** executable into output .exe file
106 static void
107 fixup_executable (int fd)
109 exe_header_t exe_header_buffer;
110 exe_header_t *exe_header;
111 int i;
112 int ret;
113 int found_data = 0;
114 int found_bss = 0;
116 exe_header = read_exe_header (fd, &exe_header_buffer);
117 assert (exe_header != 0);
119 assert (exe_header->file_header.f_nscns > 0);
120 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
122 unsigned long start_address =
123 exe_header->section_header[i].s_vaddr +
124 exe_header->file_optional_header.ImageBase;
125 unsigned long end_address =
126 exe_header->section_header[i].s_vaddr +
127 exe_header->file_optional_header.ImageBase +
128 exe_header->section_header[i].s_paddr;
129 if (debug_unexcw)
130 printf ("%8s start 0x%08x end 0x%08x\n",
131 exe_header->section_header[i].s_name,
132 start_address, end_address);
133 if (my_edata >= (char *) start_address
134 && my_edata < (char *) end_address)
136 /* data section */
137 ret =
138 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
139 SEEK_SET);
140 assert (ret != -1);
141 ret =
142 write (fd, (char *) start_address,
143 my_edata - (char *) start_address);
144 assert (ret == my_edata - (char *) start_address);
145 ++found_data;
146 if (debug_unexcw)
147 printf (" .data, mem start 0x%08x mem length %d\n",
148 start_address, my_edata - (char *) start_address);
149 if (debug_unexcw)
150 printf (" .data, file start %d file length %d\n",
151 (int) exe_header->section_header[i].s_scnptr,
152 (int) exe_header->section_header[i].s_paddr);
154 else if (my_endbss >= (char *) start_address
155 && my_endbss < (char *) end_address)
157 /* bss section */
158 ++found_bss;
159 if (exe_header->section_header[i].s_flags & 0x00000080)
161 /* convert uninitialized data section to initialized data section */
162 struct stat statbuf;
163 ret = fstat (fd, &statbuf);
164 assert (ret != -1);
166 exe_header->section_header[i].s_flags &= ~0x00000080;
167 exe_header->section_header[i].s_flags |= 0x00000040;
169 exe_header->section_header[i].s_scnptr =
170 (statbuf.st_size +
171 exe_header->file_optional_header.FileAlignment) /
172 exe_header->file_optional_header.FileAlignment *
173 exe_header->file_optional_header.FileAlignment;
175 exe_header->section_header[i].s_size =
176 (exe_header->section_header[i].s_paddr +
177 exe_header->file_optional_header.FileAlignment) /
178 exe_header->file_optional_header.FileAlignment *
179 exe_header->file_optional_header.FileAlignment;
181 ret =
182 lseek (fd,
183 (long) (exe_header->section_header[i].s_scnptr +
184 exe_header->section_header[i].s_size - 1),
185 SEEK_SET);
186 assert (ret != -1);
187 ret = write (fd, "", 1);
188 assert (ret == 1);
190 ret =
191 lseek (fd,
192 (long) ((char *) &exe_header->section_header[i] -
193 (char *) exe_header), SEEK_SET);
194 assert (ret != -1);
195 ret =
196 write (fd, &exe_header->section_header[i],
197 sizeof (exe_header->section_header[i]));
198 assert (ret == sizeof (exe_header->section_header[i]));
199 if (debug_unexcw)
200 printf (" seek to %ld, write %d\n",
201 (long) ((char *) &exe_header->section_header[i] -
202 (char *) exe_header),
203 sizeof (exe_header->section_header[i]));
205 /* write initialized data section */
206 ret =
207 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
208 SEEK_SET);
209 assert (ret != -1);
210 ret =
211 write (fd, (char *) start_address,
212 my_endbss - (char *) start_address);
213 assert (ret == (my_endbss - (char *) start_address));
214 if (debug_unexcw)
215 printf (" .bss, mem start 0x%08x mem length %d\n",
216 start_address, my_endbss - (char *) start_address);
217 if (debug_unexcw)
218 printf (" .bss, file start %d file length %d\n",
219 (int) exe_header->section_header[i].s_scnptr,
220 (int) exe_header->section_header[i].s_paddr);
223 assert (found_bss == 1);
224 assert (found_data == 1);
228 ** Windows likes .exe suffixes on executables.
230 static char *
231 add_exe_suffix_if_necessary (const char *name, char *modified)
233 int i = strlen (name);
234 if (i <= (sizeof (DOTEXE) - 1))
236 sprintf (modified, "%s%s", name, DOTEXE);
238 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
240 strcpy (modified, name);
242 else
244 sprintf (modified, "%s%s", name, DOTEXE);
246 return (modified);
250 unexec (char *outfile, char *infile, unsigned start_data, unsigned d1,
251 unsigned d2)
253 char infile_buffer[FILENAME_MAX];
254 char outfile_buffer[FILENAME_MAX];
255 int fd_in;
256 int fd_out;
257 int ret;
258 int ret2;
260 if (bss_sbrk_did_unexec)
262 /* can only dump once */
263 printf ("You can only dump Emacs once on this platform.\n");
264 return (1);
267 report_sheap_usage (1);
269 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
270 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
272 fd_in = open (infile, O_RDONLY | O_BINARY);
273 assert (fd_in >= 0);
274 fd_out = open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
275 assert (fd_out >= 0);
276 for (;;)
278 char buffer[4096];
279 ret = read (fd_in, buffer, sizeof (buffer));
280 if (ret == 0)
282 /* eof */
283 break;
285 assert (ret > 0);
286 /* data */
287 ret2 = write (fd_out, buffer, ret);
288 assert (ret2 == ret);
290 ret = close (fd_in);
291 assert (ret == 0);
293 bss_sbrk_did_unexec = 1;
294 fixup_executable (fd_out);
295 bss_sbrk_did_unexec = 0;
297 ret = close (fd_out);
298 assert (ret == 0);
300 return (0);
303 /* arch-tag: fc44f6c3-ca0a-45e0-a5a2-58b6101b1e65
304 (do not change this comment) */