PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/unexcw.c

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