1/* Unexec for MIPS (including IRIS4D).
2   Note that the GNU project considers support for MIPS operation
3   a peripheral activity which should not be allowed to divert effort
4   from development of the GNU system.  Changes in this code will be
5   installed when users send them in, but aside from that
6   we don't plan to think about it, or about whether other Emacs
7   maintenance might break it.
8
9   Copyright (C) 1988, 1994, 2001, 2002, 2003, 2004,
10                 2005, 2006, 2007  Free Software Foundation, Inc.
11
12This file is part of GNU Emacs.
13
14GNU Emacs is free software; you can redistribute it and/or modify
15it under the terms of the GNU General Public License as published by
16the Free Software Foundation; either version 2, or (at your option)
17any later version.
18
19GNU Emacs is distributed in the hope that it will be useful,
20but WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22GNU General Public License for more details.
23
24You should have received a copy of the GNU General Public License
25along with GNU Emacs; see the file COPYING.  If not, write to
26the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27Boston, MA 02110-1301, USA.  */
28
29
30#include <config.h>
31#include <sys/types.h>
32#include <sys/file.h>
33#include <sys/stat.h>
34#include <stdio.h>
35#include <varargs.h>
36
37#ifdef MACH
38
39#include <a.out.h>
40
41/* I don't know why this isn't defined.  */
42#ifndef STYP_INIT
43#define STYP_INIT  0x80000000
44#endif
45
46/* I don't know why this isn't defined.  */
47#ifndef _RDATA
48#define	_RDATA	".rdata"
49#define STYP_RDATA 0x00000100
50#endif
51
52/* Small ("near") data section.  */
53#ifndef _SDATA
54#define	_SDATA	".sdata"
55#define STYP_SDATA 0x00000200
56#endif
57
58/* Small ("near") bss section.  */
59#ifndef _SBSS
60#define _SBSS ".sbss"
61#define STYP_SBSS 0x00000400
62#endif
63
64/* We don't seem to have a sym.h or syms.h anywhere, so we'll do it the
65   hard way.  This stinks.  */
66typedef struct {
67  short   magic;
68  short   vstamp;
69  long    ilineMax;
70  struct { long foo, offset; } offsets[11];
71} HDRR, *pHDRR;
72
73#else /* not MACH */
74
75#include <filehdr.h>
76#include <aouthdr.h>
77#include <scnhdr.h>
78#include <sym.h>
79
80#endif /* not MACH */
81
82#if defined (IRIS_4D) || defined (sony)
83#include "getpagesize.h"
84#include <fcntl.h>
85#endif
86
87static void fatal_unexec ();
88static void mark_x ();
89
90#define READ(_fd, _buffer, _size, _error_message, _error_arg) \
91	errno = EEOF; \
92	if (read (_fd, _buffer, _size) != _size) \
93	  fatal_unexec (_error_message, _error_arg);
94
95#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
96	if (write (_fd, _buffer, _size) != _size) \
97	  fatal_unexec (_error_message, _error_arg);
98
99#define SEEK(_fd, _position, _error_message, _error_arg) \
100	errno = EEOF; \
101	if (lseek (_fd, _position, L_SET) != _position) \
102	  fatal_unexec (_error_message, _error_arg);
103
104extern int errno;
105extern char *strerror ();
106#define EEOF -1
107
108static struct scnhdr *text_section;
109static struct scnhdr *init_section;
110static struct scnhdr *finit_section;
111static struct scnhdr *rdata_section;
112static struct scnhdr *data_section;
113static struct scnhdr *lit8_section;
114static struct scnhdr *lit4_section;
115static struct scnhdr *sdata_section;
116static struct scnhdr *sbss_section;
117static struct scnhdr *bss_section;
118
119struct headers {
120    struct filehdr fhdr;
121    struct aouthdr aout;
122    struct scnhdr section[10];
123};
124
125/* Define name of label for entry point for the dumped executable.  */
126
127#ifndef DEFAULT_ENTRY_ADDRESS
128#define DEFAULT_ENTRY_ADDRESS __start
129#endif
130
131unexec (new_name, a_name, data_start, bss_start, entry_address)
132     char *new_name, *a_name;
133     unsigned data_start, bss_start, entry_address;
134{
135  int new, old;
136  int pagesize, brk;
137  int newsyms, symrel;
138  int nread;
139  struct headers hdr;
140  int i;
141  int vaddr, scnptr;
142#define BUFSIZE 8192
143  char buffer[BUFSIZE];
144
145  old = open (a_name, O_RDONLY, 0);
146  if (old < 0) fatal_unexec ("opening %s", a_name);
147
148  new = creat (new_name, 0666);
149  if (new < 0) fatal_unexec ("creating %s", new_name);
150
151  hdr = *((struct headers *)TEXT_START);
152#ifdef MIPS2
153  if (hdr.fhdr.f_magic != MIPSELMAGIC
154      && hdr.fhdr.f_magic != MIPSEBMAGIC
155      && hdr.fhdr.f_magic != (MIPSELMAGIC | 1)
156      && hdr.fhdr.f_magic != (MIPSEBMAGIC | 1))
157    {
158      fprintf (stderr,
159	       "unexec: input file magic number is %x, not %x, %x, %x or %x.\n",
160	       hdr.fhdr.f_magic,
161	       MIPSELMAGIC, MIPSEBMAGIC,
162	       MIPSELMAGIC | 1, MIPSEBMAGIC | 1);
163      exit(1);
164    }
165#else /* not MIPS2 */
166  if (hdr.fhdr.f_magic != MIPSELMAGIC
167      && hdr.fhdr.f_magic != MIPSEBMAGIC)
168    {
169      fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
170	       hdr.fhdr.f_magic, MIPSELMAGIC, MIPSEBMAGIC);
171      exit (1);
172    }
173#endif /* not MIPS2 */
174  if (hdr.fhdr.f_opthdr != sizeof (hdr.aout))
175    {
176      fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
177	       hdr.fhdr.f_opthdr, sizeof (hdr.aout));
178      exit (1);
179    }
180  if (hdr.aout.magic != ZMAGIC)
181    {
182      fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
183	       hdr.aout.magic, ZMAGIC);
184      exit (1);
185    }
186
187#define CHECK_SCNHDR(ptr, name, flags)					\
188  ptr = NULL;								\
189  for (i = 0; i < hdr.fhdr.f_nscns && !ptr; i++)			\
190    if (strcmp (hdr.section[i].s_name, name) == 0)			\
191      {									\
192	if (hdr.section[i].s_flags != flags)				\
193	  fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
194		   hdr.section[i].s_flags, flags, name);		\
195	ptr = hdr.section + i;						\
196      }									\
197
198  CHECK_SCNHDR (text_section,  _TEXT,  STYP_TEXT);
199  CHECK_SCNHDR (init_section,  _INIT,  STYP_INIT);
200  CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
201  CHECK_SCNHDR (data_section,  _DATA,  STYP_DATA);
202#ifdef _LIT8
203  CHECK_SCNHDR (lit8_section,  _LIT8,  STYP_LIT8);
204  CHECK_SCNHDR (lit4_section,  _LIT4,  STYP_LIT4);
205#endif /* _LIT8 */
206  CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
207  CHECK_SCNHDR (sbss_section,  _SBSS,  STYP_SBSS);
208  CHECK_SCNHDR (bss_section,   _BSS,   STYP_BSS);
209#if 0 /* Apparently this error check goes off on irix 3.3,
210	 but it doesn't indicate a real problem.  */
211  if (i != hdr.fhdr.f_nscns)
212    fprintf (stderr, "unexec: %d sections found instead of %d.\n",
213	     i, hdr.fhdr.f_nscns);
214#endif
215
216  text_section->s_scnptr = 0;
217
218  pagesize = getpagesize ();
219  /* Casting to int avoids compiler error on NEWS-OS 5.0.2.  */
220  brk = (((int) (sbrk (0))) + pagesize - 1) & (-pagesize);
221  hdr.aout.dsize = brk - DATA_START;
222  hdr.aout.bsize = 0;
223  if (entry_address == 0)
224    {
225      extern DEFAULT_ENTRY_ADDRESS ();
226      hdr.aout.entry = (unsigned)DEFAULT_ENTRY_ADDRESS;
227    }
228  else
229    hdr.aout.entry = entry_address;
230
231  hdr.aout.bss_start = hdr.aout.data_start + hdr.aout.dsize;
232  rdata_section->s_size = data_start - DATA_START;
233
234  /* Adjust start and virtual addresses of rdata_section, too.  */
235  rdata_section->s_vaddr = DATA_START;
236  rdata_section->s_paddr = DATA_START;
237  rdata_section->s_scnptr = text_section->s_scnptr + hdr.aout.tsize;
238
239  data_section->s_vaddr = data_start;
240  data_section->s_paddr = data_start;
241  data_section->s_size = brk - data_start;
242  data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
243  vaddr = data_section->s_vaddr + data_section->s_size;
244  scnptr = data_section->s_scnptr + data_section->s_size;
245  if (lit8_section != NULL)
246    {
247      lit8_section->s_vaddr = vaddr;
248      lit8_section->s_paddr = vaddr;
249      lit8_section->s_size = 0;
250      lit8_section->s_scnptr = scnptr;
251    }
252  if (lit4_section != NULL)
253    {
254      lit4_section->s_vaddr = vaddr;
255      lit4_section->s_paddr = vaddr;
256      lit4_section->s_size = 0;
257      lit4_section->s_scnptr = scnptr;
258    }
259  if (sdata_section != NULL)
260    {
261      sdata_section->s_vaddr = vaddr;
262      sdata_section->s_paddr = vaddr;
263      sdata_section->s_size = 0;
264      sdata_section->s_scnptr = scnptr;
265    }
266  if (sbss_section != NULL)
267    {
268      sbss_section->s_vaddr = vaddr;
269      sbss_section->s_paddr = vaddr;
270      sbss_section->s_size = 0;
271      sbss_section->s_scnptr = scnptr;
272    }
273  if (bss_section != NULL)
274    {
275      bss_section->s_vaddr = vaddr;
276      bss_section->s_paddr = vaddr;
277      bss_section->s_size = 0;
278      bss_section->s_scnptr = scnptr;
279    }
280
281  WRITE (new, (char *)TEXT_START, hdr.aout.tsize,
282	 "writing text section to %s", new_name);
283  WRITE (new, (char *)DATA_START, hdr.aout.dsize,
284	 "writing data section to %s", new_name);
285
286  SEEK (old, hdr.fhdr.f_symptr, "seeking to start of symbols in %s", a_name);
287  errno = EEOF;
288  nread = read (old, buffer, BUFSIZE);
289  if (nread < sizeof (HDRR)) fatal_unexec ("reading symbols from %s", a_name);
290  newsyms = hdr.aout.tsize + hdr.aout.dsize;
291  symrel = newsyms - hdr.fhdr.f_symptr;
292  hdr.fhdr.f_symptr = newsyms;
293#define symhdr ((pHDRR)buffer)
294#ifdef MACH
295  for (i = 0; i < 11; i++)
296    symhdr->offsets[i].offset += symrel;
297#else
298  symhdr->cbLineOffset += symrel;
299  symhdr->cbDnOffset += symrel;
300  symhdr->cbPdOffset += symrel;
301  symhdr->cbSymOffset += symrel;
302  symhdr->cbOptOffset += symrel;
303  symhdr->cbAuxOffset += symrel;
304  symhdr->cbSsOffset += symrel;
305  symhdr->cbSsExtOffset += symrel;
306  symhdr->cbFdOffset += symrel;
307  symhdr->cbRfdOffset += symrel;
308  symhdr->cbExtOffset += symrel;
309#endif
310#undef symhdr
311  do
312    {
313      if (write (new, buffer, nread) != nread)
314	fatal_unexec ("writing symbols to %s", new_name);
315      nread = read (old, buffer, BUFSIZE);
316      if (nread < 0) fatal_unexec ("reading symbols from %s", a_name);
317#undef BUFSIZE
318    } while (nread != 0);
319
320  SEEK (new, 0, "seeking to start of header in %s", new_name);
321  WRITE (new, &hdr, sizeof (hdr),
322	 "writing header of %s", new_name);
323
324  close (old);
325  close (new);
326  mark_x (new_name);
327}
328
329/*
330 * mark_x
331 *
332 * After successfully building the new a.out, mark it executable
333 */
334
335static void
336mark_x (name)
337     char *name;
338{
339  struct stat sbuf;
340  int um = umask (777);
341  umask (um);
342  if (stat (name, &sbuf) < 0)
343    fatal_unexec ("getting protection on %s", name);
344  sbuf.st_mode |= 0111 & ~um;
345  if (chmod (name, sbuf.st_mode) < 0)
346    fatal_unexec ("setting protection on %s", name);
347}
348
349static void
350fatal_unexec (s, va_alist)
351    va_dcl
352{
353  va_list ap;
354  if (errno == EEOF)
355    fputs ("unexec: unexpected end of file, ", stderr);
356  else
357    fprintf (stderr, "unexec: %s, ", strerror (errno));
358  va_start (ap);
359  _doprnt (s, ap, stderr);
360  fputs (".\n", stderr);
361  exit (1);
362}
363
364/* arch-tag: ebdd2058-3bbc-4de4-b5c7-5760379ab153
365   (do not change this comment) */
366