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