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