1 /* Unexec for DEC alpha.
  2 
  3    Copyright (C) 1994, 2000, 2001, 2002, 2003, 2004,
  4                  2005, 2006, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
  5 
  6 Author: Rainer Schoepf <schoepf@sc.ZIB-Berlin.DE>
  7 
  8 This file is part of GNU Emacs.
  9 
 10 GNU Emacs is free software: you can redistribute it and/or modify
 11 it under the terms of the GNU General Public License as published by
 12 the Free Software Foundation, either version 3 of the License, or
 13 (at your option) any later version.
 14 
 15 GNU Emacs is distributed in the hope that it will be useful,
 16 but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 GNU General Public License for more details.
 19 
 20 You should have received a copy of the GNU General Public License
 21 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 22 
 23 
 24 #include <config.h>
 25 #include <sys/types.h>
 26 #include <sys/file.h>
 27 #include <sys/stat.h>
 28 #include <sys/mman.h>
 29 #include <stdio.h>
 30 #include <errno.h>
 31 #ifdef HAVE_STRING_H
 32 #include <string.h>
 33 #endif
 34 #if !defined (__NetBSD__) && !defined (__OpenBSD__)
 35 #include <filehdr.h>
 36 #include <aouthdr.h>
 37 #include <scnhdr.h>
 38 #include <syms.h>
 39 #ifndef __linux__
 40 # include <reloc.h>
 41 # include <elf_abi.h>
 42 #endif
 43 #else /* __NetBSD__ or __OpenBSD__ */
 44 /*
 45  * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
 46  * there's no desire to support ECOFF as the executable format in the
 47  * long term.
 48  */
 49 #include <sys/exec_ecoff.h>
 50 
 51 /* Structures, constants, etc., that NetBSD defines strangely. */
 52 #define filehdr         ecoff_filehdr
 53 #define aouthdr         ecoff_aouthdr
 54 #define scnhdr          ecoff_scnhdr
 55 #define HDRR            struct ecoff_symhdr
 56 #define pHDRR           HDRR *
 57 #define cbHDRR          sizeof(HDRR)
 58 #ifdef __OpenBSD__
 59 #define ALPHAMAGIC      ECOFF_MAGIC_NATIVE_ALPHA
 60 #else
 61 #define ALPHAMAGIC      ECOFF_MAGIC_NETBSD_ALPHA
 62 #endif
 63 #define ZMAGIC          ECOFF_ZMAGIC
 64 
 65 /* Misc. constants that NetBSD doesn't define at all. */
 66 #define ALPHAUMAGIC     0617
 67 #define _MIPS_NSCNS_MAX 35
 68 #define STYP_TEXT       0x00000020
 69 #define STYP_DATA       0x00000040
 70 #define STYP_BSS        0x00000080
 71 #define STYP_RDATA      0x00000100
 72 #define STYP_SDATA      0x00000200
 73 #define STYP_SBSS       0x00000400
 74 #define STYP_INIT       0x80000000
 75 #define _TEXT           ".text"
 76 #define _DATA           ".data"
 77 #define _BSS            ".bss"
 78 #define _INIT           ".init"
 79 #define _RDATA          ".rdata"
 80 #define _SDATA          ".sdata"
 81 #define _SBSS           ".sbss"
 82 #endif /* __NetBSD__ || __OpenBSD__ */
 83 
 84 static void fatal_unexec __P ((char *, char *));
 85 static void mark_x __P ((char *));
 86 
 87 static void update_dynamic_symbols __P ((char *, char *, int, struct aouthdr));
 88 
 89 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
 90         errno = EEOF; \
 91         if (read (_fd, _buffer, _size) != _size) \
 92           fatal_unexec (_error_message, _error_arg);
 93 
 94 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
 95         if (write (_fd, _buffer, _size) != _size) \
 96           fatal_unexec (_error_message, _error_arg);
 97 
 98 #define SEEK(_fd, _position, _error_message, _error_arg) \
 99         errno = EEOF; \
100         if (lseek (_fd, _position, L_SET) != _position) \
101           fatal_unexec (_error_message, _error_arg);
102 
103 #ifdef HAVE_UNISTD_H
104 #include <unistd.h>
105 #else
106 void *sbrk ();
107 #endif
108 
109 #define EEOF -1
110 
111 static struct scnhdr *text_section;
112 static struct scnhdr *rel_dyn_section;
113 static struct scnhdr *dynstr_section;
114 static struct scnhdr *dynsym_section;
115 static struct scnhdr *init_section;
116 static struct scnhdr *finit_section;
117 static struct scnhdr *rdata_section;
118 static struct scnhdr *rconst_section;
119 static struct scnhdr *data_section;
120 static struct scnhdr *pdata_section;
121 static struct scnhdr *xdata_section;
122 static struct scnhdr *got_section;
123 static struct scnhdr *lit8_section;
124 static struct scnhdr *lit4_section;
125 static struct scnhdr *sdata_section;
126 static struct scnhdr *sbss_section;
127 static struct scnhdr *bss_section;
128 
129 static struct scnhdr old_data_scnhdr;
130 
131 static unsigned long Brk;
132 
133 struct headers {
134     struct filehdr fhdr;
135     struct aouthdr aout;
136     struct scnhdr section[_MIPS_NSCNS_MAX];
137 };
138 
139 
140 void
141 unexec (new_name, a_name, data_start, bss_start, entry_address)
142      char *new_name, *a_name;
143      unsigned long data_start, bss_start, entry_address;
144 {
145   int new, old;
146   char * oldptr;
147   struct headers ohdr, nhdr;
148   struct stat stat;
149   long pagesize, brk;
150   long newsyms, symrel;
151   int nread;
152   int i;
153   long vaddr, scnptr;
154 #define BUFSIZE 8192
155   char buffer[BUFSIZE];
156 
157   if ((old = open (a_name, O_RDONLY)) < 0)
158     fatal_unexec ("opening %s", a_name);
159 
160   new = creat (new_name, 0666);
161   if (new < 0) fatal_unexec ("creating %s", new_name);
162 
163   if ((fstat (old, &stat) == -1))
164     fatal_unexec ("fstat %s", a_name);
165 
166   oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
167 
168   if (oldptr == (char *)-1)
169     fatal_unexec ("mmap %s", a_name);
170 
171   close (old);
172 
173   /* This is a copy of the a.out header of the original executable */
174 
175   ohdr = (*(struct headers *)oldptr);
176 
177   /* This is where we build the new header from the in-memory copy */
178 
179   nhdr = *((struct headers *)TEXT_START);
180 
181   /* First do some consistency checks */
182 
183   if (nhdr.fhdr.f_magic != ALPHAMAGIC
184       && nhdr.fhdr.f_magic != ALPHAUMAGIC)
185     {
186       fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
187                nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
188       exit (1);
189     }
190 
191   if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
192     {
193       fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
194                nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout));
195       exit (1);
196     }
197   if (nhdr.aout.magic != ZMAGIC)
198     {
199       fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
200                nhdr.aout.magic, ZMAGIC);
201       exit (1);
202     }
203 
204 
205   /* Now check the existence of certain header section and grab
206      their addresses. */
207 
208 #define CHECK_SCNHDR(ptr, name, flags)                                  \
209   ptr = NULL;                                                           \
210   for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++)                       \
211     if (strncmp (nhdr.section[i].s_name, name, 8) == 0)                 \
212       {                                                                 \
213         if (nhdr.section[i].s_flags != flags)                           \
214           fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
215                    nhdr.section[i].s_flags, flags, name);               \
216         ptr = nhdr.section + i;                                         \
217       }                                                                 \
218 
219   CHECK_SCNHDR (text_section,  _TEXT,  STYP_TEXT);
220   CHECK_SCNHDR (init_section,  _INIT,  STYP_INIT);
221 #ifdef _REL_DYN
222   CHECK_SCNHDR (rel_dyn_section, _REL_DYN,  STYP_REL_DYN);
223 #endif /* _REL_DYN */
224 #ifdef _DYNSYM
225   CHECK_SCNHDR (dynsym_section, _DYNSYM,  STYP_DYNSYM);
226 #endif /* _REL_DYN */
227 #ifdef _DYNSTR
228   CHECK_SCNHDR (dynstr_section, _DYNSTR,  STYP_DYNSTR);
229 #endif /* _REL_DYN */
230 #ifdef _FINI
231   CHECK_SCNHDR (finit_section, _FINI,  STYP_FINI);
232 #endif /* _FINI */
233   CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
234 #ifdef _RCONST
235   CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
236 #endif
237 #ifdef _PDATA
238   CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
239 #endif /* _PDATA */
240 #ifdef _GOT
241   CHECK_SCNHDR (got_section,   _GOT,   STYP_GOT);
242 #endif /* _GOT */
243   CHECK_SCNHDR (data_section,  _DATA,  STYP_DATA);
244 #ifdef _XDATA
245   CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
246 #endif /* _XDATA */
247 #ifdef _LIT8
248   CHECK_SCNHDR (lit8_section,  _LIT8,  STYP_LIT8);
249   CHECK_SCNHDR (lit4_section,  _LIT4,  STYP_LIT4);
250 #endif /* _LIT8 */
251   CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
252   CHECK_SCNHDR (sbss_section,  _SBSS,  STYP_SBSS);
253   CHECK_SCNHDR (bss_section,   _BSS,   STYP_BSS);
254 
255 
256   pagesize = getpagesize ();
257   brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
258 
259   /* Remember the current break */
260 
261   Brk = brk;
262 
263   bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
264 
265   nhdr.aout.dsize = brk - DATA_START;
266   nhdr.aout.bsize = 0;
267   if (entry_address == 0)
268     {
269       extern __start ();
270       nhdr.aout.entry = (unsigned long)__start;
271     }
272   else
273     nhdr.aout.entry = entry_address;
274 
275   nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
276 
277   if (rdata_section != NULL)
278     {
279       rdata_section->s_size = data_start - DATA_START;
280 
281       /* Adjust start and virtual addresses of rdata_section, too.  */
282       rdata_section->s_vaddr = DATA_START;
283       rdata_section->s_paddr = DATA_START;
284       rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
285     }
286 
287   data_section->s_vaddr = data_start;
288   data_section->s_paddr = data_start;
289   data_section->s_size = brk - data_start;
290 
291   if (rdata_section != NULL)
292     {
293       data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
294     }
295 
296   vaddr = data_section->s_vaddr + data_section->s_size;
297   scnptr = data_section->s_scnptr + data_section->s_size;
298   if (lit8_section != NULL)
299     {
300       lit8_section->s_vaddr = vaddr;
301       lit8_section->s_paddr = vaddr;
302       lit8_section->s_size = 0;
303       lit8_section->s_scnptr = scnptr;
304     }
305   if (lit4_section != NULL)
306     {
307       lit4_section->s_vaddr = vaddr;
308       lit4_section->s_paddr = vaddr;
309       lit4_section->s_size = 0;
310       lit4_section->s_scnptr = scnptr;
311     }
312   if (sdata_section != NULL)
313     {
314       sdata_section->s_vaddr = vaddr;
315       sdata_section->s_paddr = vaddr;
316       sdata_section->s_size = 0;
317       sdata_section->s_scnptr = scnptr;
318     }
319 #ifdef _XDATA
320   if (xdata_section != NULL)
321     {
322       xdata_section->s_vaddr = vaddr;
323       xdata_section->s_paddr = vaddr;
324       xdata_section->s_size = 0;
325       xdata_section->s_scnptr = scnptr;
326     }
327 #endif
328 #ifdef _GOT
329   if (got_section != NULL)
330     {
331       bcopy (got_section, buffer, sizeof (struct scnhdr));
332 
333       got_section->s_vaddr = vaddr;
334       got_section->s_paddr = vaddr;
335       got_section->s_size = 0;
336       got_section->s_scnptr = scnptr;
337     }
338 #endif /*_GOT */
339   if (sbss_section != NULL)
340     {
341       sbss_section->s_vaddr = vaddr;
342       sbss_section->s_paddr = vaddr;
343       sbss_section->s_size = 0;
344       sbss_section->s_scnptr = scnptr;
345     }
346   if (bss_section != NULL)
347     {
348       bss_section->s_vaddr = vaddr;
349       bss_section->s_paddr = vaddr;
350       bss_section->s_size = 0;
351       bss_section->s_scnptr = scnptr;
352     }
353 
354   WRITE (new, (char *)TEXT_START, nhdr.aout.tsize,
355          "writing text section to %s", new_name);
356   WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
357          "writing data section to %s", new_name);
358 
359 #ifdef _GOT
360 #define old_got_section ((struct scnhdr *)buffer)
361 
362   if (got_section != NULL)
363     {
364       SEEK (new, old_got_section->s_scnptr,
365             "seeking to start of got_section in %s", new_name);
366       WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
367              "writing new got_section of %s", new_name);
368       SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
369             "seeking to end of data section of %s", new_name);
370     }
371 
372 #undef old_got_section
373 #endif
374 
375   /*
376    * Construct new symbol table header
377    */
378 
379   bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
380 
381 #define symhdr ((pHDRR)buffer)
382   newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
383   symrel = newsyms - nhdr.fhdr.f_symptr;
384   nhdr.fhdr.f_symptr = newsyms;
385   symhdr->cbLineOffset += symrel;
386   symhdr->cbDnOffset += symrel;
387   symhdr->cbPdOffset += symrel;
388   symhdr->cbSymOffset += symrel;
389   symhdr->cbOptOffset += symrel;
390   symhdr->cbAuxOffset += symrel;
391   symhdr->cbSsOffset += symrel;
392   symhdr->cbSsExtOffset += symrel;
393   symhdr->cbFdOffset += symrel;
394   symhdr->cbRfdOffset += symrel;
395   symhdr->cbExtOffset += symrel;
396 
397   WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
398 
399   /*
400    * Copy the symbol table and line numbers
401    */
402   WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
403          stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
404          "writing symbol table of %s", new_name);
405 
406 #ifdef _REL_DYN
407   if (rel_dyn_section)
408     update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
409 #endif
410 
411 #undef symhdr
412 
413   SEEK (new, 0, "seeking to start of header in %s", new_name);
414   WRITE (new, &nhdr, sizeof (nhdr),
415          "writing header of %s", new_name);
416 
417   close (old);
418   close (new);
419   mark_x (new_name);
420 }
421 
422 
423 static void
424 update_dynamic_symbols (old, new_name, new, aout)
425      char *old;                 /* Pointer to old executable */
426      char *new_name;            /* Name of new executable */
427      int new;                   /* File descriptor for new executable */
428      struct aouthdr aout;       /* a.out info from the file header */
429 {
430 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
431 
432   typedef struct dynrel_info {
433     char * addr;
434     unsigned type:8;
435     unsigned index:24;
436     unsigned info:8;
437     unsigned pad:8;
438   } dr_info;
439 
440   int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
441   int i;
442   dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
443   Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
444 
445   for (i = 0; i < nsyms; i++) {
446     register Elf32_Sym x;
447 
448     if (rd_base[i].index == 0)
449       continue;
450 
451     x = ds_base[rd_base[i].index];
452 
453 #if 0
454       fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
455                old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
456 #endif
457 
458 
459     if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
460         && (x.st_shndx == 0)
461         /* && (x.st_value == NULL) */
462         ) {
463       /* OK, this is probably a reference to an object in a shared
464          library, so copy the old value. This is done in several steps:
465          1. reladdr is the address of the location in question relative to
466             the start of the data section,
467          2. oldref is the addr is the mapped in temacs executable,
468          3. newref is the address of the location in question in the
469             undumped executable,
470          4. len is the size of the object reference in bytes --
471             currently only 4 (long) and 8 (quad) are supported.
472             */
473       register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr;
474       char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
475       unsigned long newref = aout.tsize + reladdr;
476       int len;
477 
478 #if 0
479       fprintf (stderr, "...relocated\n");
480 #endif
481 
482       if (rd_base[i].type == R_REFLONG)
483         len = 4;
484       else if (rd_base[i].type == R_REFQUAD)
485         len = 8;
486       else
487         fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i);
488 
489       SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
490       WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
491     }
492 
493 #if 0
494     else
495       fprintf (stderr, "...not relocated\n");
496 #endif
497 
498   }
499 
500 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
501 }
502 
503 
504 /*
505  * mark_x
506  *
507  * After successfully building the new a.out, mark it executable
508  */
509 
510 static void
511 mark_x (name)
512      char *name;
513 {
514   struct stat sbuf;
515   int um = umask (777);
516   umask (um);
517   if (stat (name, &sbuf) < 0)
518     fatal_unexec ("getting protection on %s", name);
519   sbuf.st_mode |= 0111 & ~um;
520   if (chmod (name, sbuf.st_mode) < 0)
521     fatal_unexec ("setting protection on %s", name);
522 }
523 
524 static void
525 fatal_unexec (s, arg)
526      char *s;
527      char *arg;
528 {
529   if (errno == EEOF)
530     fputs ("unexec: unexpected end of file, ", stderr);
531   else
532     fprintf (stderr, "unexec: %s, ", strerror (errno));
533   fprintf (stderr, s, arg);
534   fputs (".\n", stderr);
535   exit (1);
536 }
537 
538 /* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
539    (do not change this comment) */