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