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