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