Mercurial > emacs
comparison src/unexcw.c @ 89912:dbc050262b30
Added on unicode branch
author | Miles Bader <miles@gnu.org> |
---|---|
date | Mon, 19 Apr 2004 07:12:41 +0000 |
parents | |
children | f9a65d7ebd29 |
comparison
equal
deleted
inserted
replaced
89911:cce857c68ba2 | 89912:dbc050262b30 |
---|---|
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) */ |