(mouse-region-delete-keys): New variable.
[emacs.git] / src / unexalpha.c
blob2adfd1fa57eaa3073d60b5da4f4ace44bbf57c41
1 /* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
3 Copyright (C) 1994 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
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>
30 #include <filehdr.h>
31 #include <aouthdr.h>
32 #include <scnhdr.h>
33 #include <syms.h>
34 #ifndef __linux__
35 # include <reloc.h>
36 # include <elf_abi.h>
37 #endif
39 static void fatal_unexec ();
40 static void mark_x ();
42 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
43 errno = EEOF; \
44 if (read (_fd, _buffer, _size) != _size) \
45 fatal_unexec (_error_message, _error_arg);
47 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
48 if (write (_fd, _buffer, _size) != _size) \
49 fatal_unexec (_error_message, _error_arg);
51 #define SEEK(_fd, _position, _error_message, _error_arg) \
52 errno = EEOF; \
53 if (lseek (_fd, _position, L_SET) != _position) \
54 fatal_unexec (_error_message, _error_arg);
56 extern int errno;
57 extern char *strerror ();
59 void *sbrk ();
61 #define EEOF -1
63 static struct scnhdr *text_section;
64 static struct scnhdr *rel_dyn_section;
65 static struct scnhdr *dynstr_section;
66 static struct scnhdr *dynsym_section;
67 static struct scnhdr *init_section;
68 static struct scnhdr *finit_section;
69 static struct scnhdr *rdata_section;
70 static struct scnhdr *rconst_section;
71 static struct scnhdr *data_section;
72 static struct scnhdr *pdata_section;
73 static struct scnhdr *xdata_section;
74 static struct scnhdr *got_section;
75 static struct scnhdr *lit8_section;
76 static struct scnhdr *lit4_section;
77 static struct scnhdr *sdata_section;
78 static struct scnhdr *sbss_section;
79 static struct scnhdr *bss_section;
81 static struct scnhdr old_data_scnhdr;
83 static unsigned long Brk;
85 struct headers {
86 struct filehdr fhdr;
87 struct aouthdr aout;
88 struct scnhdr section[_MIPS_NSCNS_MAX];
93 /* Define name of label for entry point for the dumped executable. */
95 #ifndef DEFAULT_ENTRY_ADDRESS
96 #define DEFAULT_ENTRY_ADDRESS __start
97 #endif
99 unexec (new_name, a_name, data_start, bss_start, entry_address)
100 char *new_name, *a_name;
101 unsigned long data_start, bss_start, entry_address;
103 int new, old;
104 char * oldptr;
105 struct headers ohdr, nhdr;
106 struct stat stat;
107 long pagesize, brk;
108 long newsyms, symrel;
109 int nread;
110 int i;
111 long vaddr, scnptr;
112 #define BUFSIZE 8192
113 char buffer[BUFSIZE];
115 if ((old = open (a_name, O_RDONLY)) < 0)
116 fatal_unexec ("opening %s", a_name);
118 new = creat (new_name, 0666);
119 if (new < 0) fatal_unexec ("creating %s", new_name);
121 if ((fstat (old, &stat) == -1))
122 fatal_unexec ("fstat %s", a_name);
124 oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
126 if (oldptr == (char *)-1)
127 fatal_unexec ("mmap %s", a_name);
129 close (old);
131 /* This is a copy of the a.out header of the original executable */
133 ohdr = (*(struct headers *)oldptr);
135 /* This is where we build the new header from the in-memory copy */
137 nhdr = *((struct headers *)TEXT_START);
139 /* First do some consistency checks */
141 if (nhdr.fhdr.f_magic != ALPHAMAGIC
142 && nhdr.fhdr.f_magic != ALPHAUMAGIC)
144 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
145 nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
146 exit (1);
149 if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
151 fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
152 nhdr.fhdr.f_opthdr, sizeof (nhdr.aout));
153 exit (1);
155 if (nhdr.aout.magic != ZMAGIC)
157 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
158 nhdr.aout.magic, ZMAGIC);
159 exit (1);
163 /* Now check the existence of certain header section and grab
164 their addresses. */
166 #define CHECK_SCNHDR(ptr, name, flags) \
167 ptr = NULL; \
168 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
169 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
171 if (nhdr.section[i].s_flags != flags) \
172 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
173 nhdr.section[i].s_flags, flags, name); \
174 ptr = nhdr.section + i; \
177 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
178 CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
179 #ifdef _REL_DYN
180 CHECK_SCNHDR (rel_dyn_section, _REL_DYN, STYP_REL_DYN);
181 #endif /* _REL_DYN */
182 #ifdef _DYNSYM
183 CHECK_SCNHDR (dynsym_section, _DYNSYM, STYP_DYNSYM);
184 #endif /* _REL_DYN */
185 #ifdef _DYNSTR
186 CHECK_SCNHDR (dynstr_section, _DYNSTR, STYP_DYNSTR);
187 #endif /* _REL_DYN */
188 #ifdef _FINI
189 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
190 #endif /* _FINI */
191 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
192 #ifdef _RCONST
193 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
194 #endif
195 #ifdef _PDATA
196 CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
197 #endif _PDATA
198 #ifdef _GOT
199 CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
200 #endif _GOT
201 CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
202 #ifdef _XDATA
203 CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
204 #endif /* _XDATA */
205 #ifdef _LIT8
206 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8);
207 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4);
208 #endif /* _LIT8 */
209 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
210 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS);
211 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS);
214 pagesize = getpagesize ();
215 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
217 /* Remember the current break */
219 Brk = brk;
221 bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
223 nhdr.aout.dsize = brk - DATA_START;
224 nhdr.aout.bsize = 0;
225 if (entry_address == 0)
227 extern DEFAULT_ENTRY_ADDRESS ();
228 nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS;
230 else
231 nhdr.aout.entry = entry_address;
233 nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
235 if (rdata_section != NULL)
237 rdata_section->s_size = data_start - DATA_START;
239 /* Adjust start and virtual addresses of rdata_section, too. */
240 rdata_section->s_vaddr = DATA_START;
241 rdata_section->s_paddr = DATA_START;
242 rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
245 data_section->s_vaddr = data_start;
246 data_section->s_paddr = data_start;
247 data_section->s_size = brk - data_start;
249 if (rdata_section != NULL)
251 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
254 vaddr = data_section->s_vaddr + data_section->s_size;
255 scnptr = data_section->s_scnptr + data_section->s_size;
256 if (lit8_section != NULL)
258 lit8_section->s_vaddr = vaddr;
259 lit8_section->s_paddr = vaddr;
260 lit8_section->s_size = 0;
261 lit8_section->s_scnptr = scnptr;
263 if (lit4_section != NULL)
265 lit4_section->s_vaddr = vaddr;
266 lit4_section->s_paddr = vaddr;
267 lit4_section->s_size = 0;
268 lit4_section->s_scnptr = scnptr;
270 if (sdata_section != NULL)
272 sdata_section->s_vaddr = vaddr;
273 sdata_section->s_paddr = vaddr;
274 sdata_section->s_size = 0;
275 sdata_section->s_scnptr = scnptr;
277 #ifdef _XDATA
278 if (xdata_section != NULL)
280 xdata_section->s_vaddr = vaddr;
281 xdata_section->s_paddr = vaddr;
282 xdata_section->s_size = 0;
283 xdata_section->s_scnptr = scnptr;
285 #endif
286 #ifdef _GOT
287 if (got_section != NULL)
289 bcopy (got_section, buffer, sizeof (struct scnhdr));
291 got_section->s_vaddr = vaddr;
292 got_section->s_paddr = vaddr;
293 got_section->s_size = 0;
294 got_section->s_scnptr = scnptr;
296 #endif /*_GOT */
297 if (sbss_section != NULL)
299 sbss_section->s_vaddr = vaddr;
300 sbss_section->s_paddr = vaddr;
301 sbss_section->s_size = 0;
302 sbss_section->s_scnptr = scnptr;
304 if (bss_section != NULL)
306 bss_section->s_vaddr = vaddr;
307 bss_section->s_paddr = vaddr;
308 bss_section->s_size = 0;
309 bss_section->s_scnptr = scnptr;
312 WRITE (new, (char *)TEXT_START, nhdr.aout.tsize,
313 "writing text section to %s", new_name);
314 WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
315 "writing data section to %s", new_name);
317 #ifdef _GOT
318 #define old_got_section ((struct scnhdr *)buffer)
320 if (got_section != NULL)
322 SEEK (new, old_got_section->s_scnptr,
323 "seeking to start of got_section in %s", new_name);
324 WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
325 "writing new got_section of %s", new_name);
326 SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
327 "seeking to end of data section of %s", new_name);
330 #undef old_got_section
331 #endif
334 * Construct new symbol table header
337 bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
339 #define symhdr ((pHDRR)buffer)
340 newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
341 symrel = newsyms - nhdr.fhdr.f_symptr;
342 nhdr.fhdr.f_symptr = newsyms;
343 symhdr->cbLineOffset += symrel;
344 symhdr->cbDnOffset += symrel;
345 symhdr->cbPdOffset += symrel;
346 symhdr->cbSymOffset += symrel;
347 symhdr->cbOptOffset += symrel;
348 symhdr->cbAuxOffset += symrel;
349 symhdr->cbSsOffset += symrel;
350 symhdr->cbSsExtOffset += symrel;
351 symhdr->cbFdOffset += symrel;
352 symhdr->cbRfdOffset += symrel;
353 symhdr->cbExtOffset += symrel;
355 WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
358 * Copy the symbol table and line numbers
360 WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
361 stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
362 "writing symbol table of %s", new_name);
364 #ifndef __linux__
365 update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
366 #endif
368 #undef symhdr
370 SEEK (new, 0, "seeking to start of header in %s", new_name);
371 WRITE (new, &nhdr, sizeof (nhdr),
372 "writing header of %s", new_name);
374 close (old);
375 close (new);
376 mark_x (new_name);
382 #ifndef __linux__
384 update_dynamic_symbols (old, new_name, new, aout)
385 char *old; /* Pointer to old executable */
386 char *new_name; /* Name of new executable */
387 int new; /* File descriptor for new executable */
388 struct aouthdr aout; /* a.out info from the file header */
390 typedef struct dynrel_info {
391 char * addr;
392 unsigned type:8;
393 unsigned index:24;
394 unsigned info:8;
395 unsigned pad:8;
396 } dr_info;
398 int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
399 int i;
400 dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
401 Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
403 for (i = 0; i < nsyms; i++) {
404 register Elf32_Sym x;
406 if (rd_base[i].index == 0)
407 continue;
409 x = ds_base[rd_base[i].index];
411 #if 0
412 fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
413 old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
414 #endif
417 if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
418 && (x.st_shndx == 0)
419 /* && (x.st_value == NULL) */
421 /* OK, this is probably a reference to an object in a shared
422 library, so copy the old value. This is done in several steps:
423 1. reladdr is the address of the location in question relative to
424 the start of the data section,
425 2. oldref is the addr is the mapped in temacs executable,
426 3. newref is the address of the location in question in the
427 undumped executable,
428 4. len is the size of the object reference in bytes --
429 currently only 4 (long) and 8 (quad) are supported.
431 register unsigned long reladdr = rd_base[i].addr - old_data_scnhdr.s_vaddr;
432 char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
433 unsigned long newref = aout.tsize + reladdr;
434 int len;
436 #if 0
437 fprintf (stderr, "...relocated\n");
438 #endif
440 if (rd_base[i].type == R_REFLONG)
441 len = 4;
442 else if (rd_base[i].type == R_REFQUAD)
443 len = 8;
444 else
445 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i);
447 SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
448 WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
451 #if 0
452 else
453 fprintf (stderr, "...not relocated\n");
454 #endif
460 #endif /* !__linux__ */
464 * mark_x
466 * After successfully building the new a.out, mark it executable
469 static void
470 mark_x (name)
471 char *name;
473 struct stat sbuf;
474 int um = umask (777);
475 umask (um);
476 if (stat (name, &sbuf) < 0)
477 fatal_unexec ("getting protection on %s", name);
478 sbuf.st_mode |= 0111 & ~um;
479 if (chmod (name, sbuf.st_mode) < 0)
480 fatal_unexec ("setting protection on %s", name);
483 static void
484 fatal_unexec (s, arg)
485 char *s;
486 char *arg;
488 if (errno == EEOF)
489 fputs ("unexec: unexpected end of file, ", stderr);
490 else
491 fprintf (stderr, "unexec: %s, ", strerror (errno));
492 fprintf (stderr, s, arg);
493 fputs (".\n", stderr);
494 exit (1);