(font-show-log): Add optional arg N to control the limit of font
[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
b061d5f1 137\f
3fb21e7a 138void
b061d5f1
RS
139unexec (new_name, a_name, data_start, bss_start, entry_address)
140 char *new_name, *a_name;
141 unsigned long data_start, bss_start, entry_address;
142{
143 int new, old;
144 char * oldptr;
145 struct headers ohdr, nhdr;
146 struct stat stat;
147 long pagesize, brk;
148 long newsyms, symrel;
149 int nread;
150 int i;
151 long vaddr, scnptr;
152#define BUFSIZE 8192
153 char buffer[BUFSIZE];
154
155 if ((old = open (a_name, O_RDONLY)) < 0)
156 fatal_unexec ("opening %s", a_name);
157
158 new = creat (new_name, 0666);
159 if (new < 0) fatal_unexec ("creating %s", new_name);
160
161 if ((fstat (old, &stat) == -1))
162 fatal_unexec ("fstat %s", a_name);
163
164 oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
165
166 if (oldptr == (char *)-1)
167 fatal_unexec ("mmap %s", a_name);
168
169 close (old);
170
171 /* This is a copy of the a.out header of the original executable */
172
173 ohdr = (*(struct headers *)oldptr);
174
175 /* This is where we build the new header from the in-memory copy */
176
177 nhdr = *((struct headers *)TEXT_START);
178
179 /* First do some consistency checks */
180
181 if (nhdr.fhdr.f_magic != ALPHAMAGIC
182 && nhdr.fhdr.f_magic != ALPHAUMAGIC)
183 {
184 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
185 nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
186 exit (1);
187 }
188
189 if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
190 {
191 fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
0c08e6df 192 nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout));
b061d5f1
RS
193 exit (1);
194 }
195 if (nhdr.aout.magic != ZMAGIC)
196 {
197 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
198 nhdr.aout.magic, ZMAGIC);
199 exit (1);
200 }
201
202
203 /* Now check the existence of certain header section and grab
204 their addresses. */
205
206#define CHECK_SCNHDR(ptr, name, flags) \
207 ptr = NULL; \
208 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
d7b43eaa 209 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
b061d5f1
RS
210 { \
211 if (nhdr.section[i].s_flags != flags) \
212 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
213 nhdr.section[i].s_flags, flags, name); \
214 ptr = nhdr.section + i; \
215 } \
216
217 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
218 CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
d7b43eaa
RS
219#ifdef _REL_DYN
220 CHECK_SCNHDR (rel_dyn_section, _REL_DYN, STYP_REL_DYN);
221#endif /* _REL_DYN */
222#ifdef _DYNSYM
223 CHECK_SCNHDR (dynsym_section, _DYNSYM, STYP_DYNSYM);
224#endif /* _REL_DYN */
225#ifdef _DYNSTR
226 CHECK_SCNHDR (dynstr_section, _DYNSTR, STYP_DYNSTR);
227#endif /* _REL_DYN */
b061d5f1
RS
228#ifdef _FINI
229 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
230#endif /* _FINI */
231 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
866fc66a
RS
232#ifdef _RCONST
233 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
234#endif
b061d5f1
RS
235#ifdef _PDATA
236 CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
20fd0b4f 237#endif /* _PDATA */
b061d5f1
RS
238#ifdef _GOT
239 CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
20fd0b4f 240#endif /* _GOT */
b061d5f1
RS
241 CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
242#ifdef _XDATA
243 CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
244#endif /* _XDATA */
245#ifdef _LIT8
246 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8);
247 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4);
248#endif /* _LIT8 */
249 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
250 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS);
251 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS);
b061d5f1
RS
252
253
254 pagesize = getpagesize ();
255 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
256
257 /* Remember the current break */
258
259 Brk = brk;
260
d7b43eaa
RS
261 bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
262
b061d5f1
RS
263 nhdr.aout.dsize = brk - DATA_START;
264 nhdr.aout.bsize = 0;
265 if (entry_address == 0)
266 {
132d0475
DN
267 extern __start ();
268 nhdr.aout.entry = (unsigned long)__start;
b061d5f1
RS
269 }
270 else
271 nhdr.aout.entry = entry_address;
272
273 nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
b061d5f1 274
866fc66a
RS
275 if (rdata_section != NULL)
276 {
277 rdata_section->s_size = data_start - DATA_START;
278
279 /* Adjust start and virtual addresses of rdata_section, too. */
280 rdata_section->s_vaddr = DATA_START;
281 rdata_section->s_paddr = DATA_START;
282 rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
283 }
b061d5f1
RS
284
285 data_section->s_vaddr = data_start;
286 data_section->s_paddr = data_start;
287 data_section->s_size = brk - data_start;
866fc66a
RS
288
289 if (rdata_section != NULL)
290 {
291 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
292 }
293
b061d5f1
RS
294 vaddr = data_section->s_vaddr + data_section->s_size;
295 scnptr = data_section->s_scnptr + data_section->s_size;
296 if (lit8_section != NULL)
297 {
298 lit8_section->s_vaddr = vaddr;
299 lit8_section->s_paddr = vaddr;
300 lit8_section->s_size = 0;
301 lit8_section->s_scnptr = scnptr;
302 }
303 if (lit4_section != NULL)
304 {
305 lit4_section->s_vaddr = vaddr;
306 lit4_section->s_paddr = vaddr;
307 lit4_section->s_size = 0;
308 lit4_section->s_scnptr = scnptr;
309 }
310 if (sdata_section != NULL)
311 {
312 sdata_section->s_vaddr = vaddr;
313 sdata_section->s_paddr = vaddr;
314 sdata_section->s_size = 0;
315 sdata_section->s_scnptr = scnptr;
316 }
317#ifdef _XDATA
318 if (xdata_section != NULL)
319 {
320 xdata_section->s_vaddr = vaddr;
321 xdata_section->s_paddr = vaddr;
322 xdata_section->s_size = 0;
323 xdata_section->s_scnptr = scnptr;
324 }
325#endif
326#ifdef _GOT
327 if (got_section != NULL)
328 {
7d713448
RS
329 bcopy (got_section, buffer, sizeof (struct scnhdr));
330
b061d5f1
RS
331 got_section->s_vaddr = vaddr;
332 got_section->s_paddr = vaddr;
333 got_section->s_size = 0;
334 got_section->s_scnptr = scnptr;
335 }
336#endif /*_GOT */
337 if (sbss_section != NULL)
338 {
339 sbss_section->s_vaddr = vaddr;
340 sbss_section->s_paddr = vaddr;
341 sbss_section->s_size = 0;
342 sbss_section->s_scnptr = scnptr;
343 }
344 if (bss_section != NULL)
345 {
346 bss_section->s_vaddr = vaddr;
347 bss_section->s_paddr = vaddr;
348 bss_section->s_size = 0;
349 bss_section->s_scnptr = scnptr;
350 }
351
352 WRITE (new, (char *)TEXT_START, nhdr.aout.tsize,
353 "writing text section to %s", new_name);
354 WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
355 "writing data section to %s", new_name);
356
7d713448
RS
357#ifdef _GOT
358#define old_got_section ((struct scnhdr *)buffer)
359
360 if (got_section != NULL)
361 {
362 SEEK (new, old_got_section->s_scnptr,
363 "seeking to start of got_section in %s", new_name);
364 WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
365 "writing new got_section of %s", new_name);
366 SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
367 "seeking to end of data section of %s", new_name);
368 }
369
370#undef old_got_section
371#endif
b061d5f1
RS
372
373 /*
374 * Construct new symbol table header
375 */
376
377 bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
378
379#define symhdr ((pHDRR)buffer)
380 newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
381 symrel = newsyms - nhdr.fhdr.f_symptr;
382 nhdr.fhdr.f_symptr = newsyms;
383 symhdr->cbLineOffset += symrel;
384 symhdr->cbDnOffset += symrel;
385 symhdr->cbPdOffset += symrel;
386 symhdr->cbSymOffset += symrel;
387 symhdr->cbOptOffset += symrel;
388 symhdr->cbAuxOffset += symrel;
389 symhdr->cbSsOffset += symrel;
390 symhdr->cbSsExtOffset += symrel;
391 symhdr->cbFdOffset += symrel;
392 symhdr->cbRfdOffset += symrel;
393 symhdr->cbExtOffset += symrel;
394
395 WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
396
397 /*
398 * Copy the symbol table and line numbers
399 */
400 WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
401 stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
402 "writing symbol table of %s", new_name);
403
6ca5cfd1
RS
404#ifdef _REL_DYN
405 if (rel_dyn_section)
406 update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
407#endif
b061d5f1
RS
408
409#undef symhdr
410
411 SEEK (new, 0, "seeking to start of header in %s", new_name);
412 WRITE (new, &nhdr, sizeof (nhdr),
413 "writing header of %s", new_name);
414
415 close (old);
416 close (new);
417 mark_x (new_name);
418}
419
420
3fb21e7a 421static void
d7b43eaa 422update_dynamic_symbols (old, new_name, new, aout)
866fc66a
RS
423 char *old; /* Pointer to old executable */
424 char *new_name; /* Name of new executable */
425 int new; /* File descriptor for new executable */
d7b43eaa 426 struct aouthdr aout; /* a.out info from the file header */
b061d5f1 427{
61e63089 428#if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
54dfb86c 429
d7b43eaa
RS
430 typedef struct dynrel_info {
431 char * addr;
432 unsigned type:8;
433 unsigned index:24;
434 unsigned info:8;
435 unsigned pad:8;
436 } dr_info;
437
438 int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
439 int i;
440 dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
441 Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
b061d5f1 442
d7b43eaa
RS
443 for (i = 0; i < nsyms; i++) {
444 register Elf32_Sym x;
b061d5f1 445
d7b43eaa
RS
446 if (rd_base[i].index == 0)
447 continue;
b061d5f1 448
d7b43eaa
RS
449 x = ds_base[rd_base[i].index];
450
451#if 0
452 fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
453 old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
454#endif
455
456
457 if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
458 && (x.st_shndx == 0)
459 /* && (x.st_value == NULL) */
460 ) {
461 /* OK, this is probably a reference to an object in a shared
462 library, so copy the old value. This is done in several steps:
463 1. reladdr is the address of the location in question relative to
464 the start of the data section,
465 2. oldref is the addr is the mapped in temacs executable,
466 3. newref is the address of the location in question in the
467 undumped executable,
468 4. len is the size of the object reference in bytes --
469 currently only 4 (long) and 8 (quad) are supported.
470 */
2881ec96 471 register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr;
d7b43eaa
RS
472 char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
473 unsigned long newref = aout.tsize + reladdr;
474 int len;
475
476#if 0
477 fprintf (stderr, "...relocated\n");
478#endif
479
177c0ea7 480 if (rd_base[i].type == R_REFLONG)
d7b43eaa 481 len = 4;
177c0ea7 482 else if (rd_base[i].type == R_REFQUAD)
d7b43eaa
RS
483 len = 8;
484 else
4042a81a 485 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i);
d7b43eaa
RS
486
487 SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
488 WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
b061d5f1
RS
489 }
490
d7b43eaa
RS
491#if 0
492 else
493 fprintf (stderr, "...not relocated\n");
494#endif
495
496 }
497
61e63089 498#endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
b061d5f1
RS
499}
500
b061d5f1
RS
501\f
502/*
503 * mark_x
504 *
505 * After successfully building the new a.out, mark it executable
506 */
507
508static void
509mark_x (name)
510 char *name;
511{
512 struct stat sbuf;
513 int um = umask (777);
514 umask (um);
515 if (stat (name, &sbuf) < 0)
516 fatal_unexec ("getting protection on %s", name);
517 sbuf.st_mode |= 0111 & ~um;
518 if (chmod (name, sbuf.st_mode) < 0)
519 fatal_unexec ("setting protection on %s", name);
520}
521
522static void
a084ed10
RS
523fatal_unexec (s, arg)
524 char *s;
525 char *arg;
b061d5f1 526{
b061d5f1
RS
527 if (errno == EEOF)
528 fputs ("unexec: unexpected end of file, ", stderr);
529 else
530 fprintf (stderr, "unexec: %s, ", strerror (errno));
a084ed10 531 fprintf (stderr, s, arg);
b061d5f1
RS
532 fputs (".\n", stderr);
533 exit (1);
534}
ab5796a9
MB
535
536/* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
537 (do not change this comment) */