unexelf.c 44.3 KB
Newer Older
1
/* Copyright (C) 1985-1988, 1990, 1992, 1999-2011
Glenn Morris's avatar
Glenn Morris committed
2
                 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
3

4
This file is part of GNU Emacs.
5

6
GNU Emacs is free software: you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8 9
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
10

11 12 13 14 15 16
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
17
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
18

19
/*
Jim Blandy's avatar
Jim Blandy committed
20 21 22 23 24 25 26 27 28
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them.   Help stamp out software-hoarding!  */


/*
 * unexec.c - Convert a running program into an a.out file.
 *
 * Author:	Spencer W. Thomas
29 30
 *		Computer Science Dept.
 *		University of Utah
Jim Blandy's avatar
Jim Blandy committed
31 32 33 34
 * Date:	Tue Mar  2 1982
 * Modified heavily since then.
 *
 * Synopsis:
35
 *	unexec (const char *new_name, const char *old_name);
Jim Blandy's avatar
Jim Blandy committed
36 37 38
 *
 * Takes a snapshot of the program and makes an a.out format file in the
 * file named by the string argument new_name.
39 40
 * If old_name is non-NULL, the symbol table will be taken from the given file.
 * On some machines, an existing old_name file is required.
Jim Blandy's avatar
Jim Blandy committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
 *
 */

/* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co.
 * ELF support added.
 *
 * Basic theory: the data space of the running process needs to be
 * dumped to the output file.  Normally we would just enlarge the size
 * of .data, scooting everything down.  But we can't do that in ELF,
 * because there is often something between the .data space and the
 * .bss space.
 *
 * In the temacs dump below, notice that the Global Offset Table
 * (.got) and the Dynamic link data (.dynamic) come between .data1 and
 * .bss.  It does not work to overlap .data with these fields.
 *
 * The solution is to create a new .data segment.  This segment is
 * filled with data from the current process.  Since the contents of
 * various sections refer to sections by index, the new .data segment
 * is made the last in the table to avoid changing any existing index.

 * This is an example of how the section headers are changed.  "Addr"
 * is a process virtual address.  "Offset" is a file offset.

raid:/nfs/raid/src/dist-18.56/src> dump -h temacs

temacs:

           **** SECTION HEADER TABLE ****
Dave Love's avatar
Dave Love committed
70 71
 [No]    Type    Flags   Addr         Offset       Size          Name
         Link    Info    Adralgn      Entsize
Jim Blandy's avatar
Jim Blandy committed
72

Dave Love's avatar
Dave Love committed
73 74
 [1]     1       2       0x80480d4    0xd4         0x13          .interp
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
75

Dave Love's avatar
Dave Love committed
76 77
 [2]     5       2       0x80480e8    0xe8         0x388         .hash
         3       0       0x4          0x4
Jim Blandy's avatar
Jim Blandy committed
78

Dave Love's avatar
Dave Love committed
79 80
 [3]     11      2       0x8048470    0x470        0x7f0         .dynsym
         4       1       0x4          0x10
Jim Blandy's avatar
Jim Blandy committed
81

Dave Love's avatar
Dave Love committed
82 83
 [4]     3       2       0x8048c60    0xc60        0x3ad         .dynstr
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
84

Dave Love's avatar
Dave Love committed
85 86
 [5]     9       2       0x8049010    0x1010       0x338         .rel.plt
         3       7       0x4          0x8
Jim Blandy's avatar
Jim Blandy committed
87

Dave Love's avatar
Dave Love committed
88 89
 [6]     1       6       0x8049348    0x1348       0x3           .init
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
90

Dave Love's avatar
Dave Love committed
91 92
 [7]     1       6       0x804934c    0x134c       0x680         .plt
         0       0       0x4          0x4
Jim Blandy's avatar
Jim Blandy committed
93

Dave Love's avatar
Dave Love committed
94 95
 [8]     1       6       0x80499cc    0x19cc       0x3c56f       .text
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
96

Dave Love's avatar
Dave Love committed
97 98
 [9]     1       6       0x8085f3c    0x3df3c      0x3           .fini
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
99

Dave Love's avatar
Dave Love committed
100 101
 [10]    1       2       0x8085f40    0x3df40      0x69c         .rodata
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
102

Dave Love's avatar
Dave Love committed
103 104
 [11]    1       2       0x80865dc    0x3e5dc      0xd51         .rodata1
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
105

Dave Love's avatar
Dave Love committed
106 107
 [12]    1       3       0x8088330    0x3f330      0x20afc       .data
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
108

Dave Love's avatar
Dave Love committed
109 110
 [13]    1       3       0x80a8e2c    0x5fe2c      0x89d         .data1
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
111

Dave Love's avatar
Dave Love committed
112 113
 [14]    1       3       0x80a96cc    0x606cc      0x1a8         .got
         0       0       0x4          0x4
Jim Blandy's avatar
Jim Blandy committed
114

Dave Love's avatar
Dave Love committed
115 116
 [15]    6       3       0x80a9874    0x60874      0x80          .dynamic
         4       0       0x4          0x8
Jim Blandy's avatar
Jim Blandy committed
117

Dave Love's avatar
Dave Love committed
118 119
 [16]    8       3       0x80a98f4    0x608f4      0x449c        .bss
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
120

Dave Love's avatar
Dave Love committed
121 122
 [17]    2       0       0            0x608f4      0x9b90        .symtab
         18      371     0x4          0x10
Jim Blandy's avatar
Jim Blandy committed
123

Dave Love's avatar
Dave Love committed
124 125
 [18]    3       0       0            0x6a484      0x8526        .strtab
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
126

Dave Love's avatar
Dave Love committed
127 128
 [19]    3       0       0            0x729aa      0x93          .shstrtab
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
129

Dave Love's avatar
Dave Love committed
130 131
 [20]    1       0       0            0x72a3d      0x68b7        .comment
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
132

Dave Love's avatar
Dave Love committed
133
 raid:/nfs/raid/src/dist-18.56/src> dump -h xemacs
Jim Blandy's avatar
Jim Blandy committed
134

Dave Love's avatar
Dave Love committed
135
 xemacs:
Jim Blandy's avatar
Jim Blandy committed
136

Dave Love's avatar
Dave Love committed
137 138 139
            **** SECTION HEADER TABLE ****
 [No]    Type    Flags   Addr         Offset       Size          Name
         Link    Info    Adralgn      Entsize
Jim Blandy's avatar
Jim Blandy committed
140

Dave Love's avatar
Dave Love committed
141 142
 [1]     1       2       0x80480d4    0xd4         0x13          .interp
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
143

Dave Love's avatar
Dave Love committed
144 145
 [2]     5       2       0x80480e8    0xe8         0x388         .hash
         3       0       0x4          0x4
Jim Blandy's avatar
Jim Blandy committed
146

Dave Love's avatar
Dave Love committed
147 148
 [3]     11      2       0x8048470    0x470        0x7f0         .dynsym
         4       1       0x4          0x10
Jim Blandy's avatar
Jim Blandy committed
149

Dave Love's avatar
Dave Love committed
150 151
 [4]     3       2       0x8048c60    0xc60        0x3ad         .dynstr
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
152

Dave Love's avatar
Dave Love committed
153 154
 [5]     9       2       0x8049010    0x1010       0x338         .rel.plt
         3       7       0x4          0x8
Jim Blandy's avatar
Jim Blandy committed
155

Dave Love's avatar
Dave Love committed
156 157
 [6]     1       6       0x8049348    0x1348       0x3           .init
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
158

Dave Love's avatar
Dave Love committed
159 160
 [7]     1       6       0x804934c    0x134c       0x680         .plt
         0       0       0x4          0x4
Jim Blandy's avatar
Jim Blandy committed
161

Dave Love's avatar
Dave Love committed
162 163
 [8]     1       6       0x80499cc    0x19cc       0x3c56f       .text
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
164

Dave Love's avatar
Dave Love committed
165 166
 [9]     1       6       0x8085f3c    0x3df3c      0x3           .fini
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
167

Dave Love's avatar
Dave Love committed
168 169
 [10]    1       2       0x8085f40    0x3df40      0x69c         .rodata
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
170

Dave Love's avatar
Dave Love committed
171 172
 [11]    1       2       0x80865dc    0x3e5dc      0xd51         .rodata1
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
173

Dave Love's avatar
Dave Love committed
174 175
 [12]    1       3       0x8088330    0x3f330      0x20afc       .data
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
176

Dave Love's avatar
Dave Love committed
177 178
 [13]    1       3       0x80a8e2c    0x5fe2c      0x89d         .data1
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
179

Dave Love's avatar
Dave Love committed
180 181
 [14]    1       3       0x80a96cc    0x606cc      0x1a8         .got
         0       0       0x4          0x4
Jim Blandy's avatar
Jim Blandy committed
182

Dave Love's avatar
Dave Love committed
183 184
 [15]    6       3       0x80a9874    0x60874      0x80          .dynamic
         4       0       0x4          0x8
Jim Blandy's avatar
Jim Blandy committed
185

Dave Love's avatar
Dave Love committed
186 187
 [16]    8       3       0x80c6800    0x7d800      0             .bss
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
188

Dave Love's avatar
Dave Love committed
189 190
 [17]    2       0       0            0x7d800      0x9b90        .symtab
         18      371     0x4          0x10
Jim Blandy's avatar
Jim Blandy committed
191

Dave Love's avatar
Dave Love committed
192 193
 [18]    3       0       0            0x87390      0x8526        .strtab
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
194

Dave Love's avatar
Dave Love committed
195 196
 [19]    3       0       0            0x8f8b6      0x93          .shstrtab
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
197

Dave Love's avatar
Dave Love committed
198 199
 [20]    1       0       0            0x8f949      0x68b7        .comment
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
200

Dave Love's avatar
Dave Love committed
201 202
 [21]    1       3       0x80a98f4    0x608f4      0x1cf0c       .data
         0       0       0x4          0
Jim Blandy's avatar
Jim Blandy committed
203

Dave Love's avatar
Dave Love committed
204 205 206 207 208 209 210 211
  * This is an example of how the file header is changed.  "Shoff" is
  * the section header offset within the file.  Since that table is
  * after the new .data section, it is moved.  "Shnum" is the number of
  * sections, which we increment.
  *
  * "Phoff" is the file offset to the program header.  "Phentsize" and
  * "Shentsz" are the program and section header entries sizes respectively.
  * These can be larger than the apparent struct sizes.
Jim Blandy's avatar
Jim Blandy committed
212

Dave Love's avatar
Dave Love committed
213
 raid:/nfs/raid/src/dist-18.56/src> dump -f temacs
Jim Blandy's avatar
Jim Blandy committed
214

Dave Love's avatar
Dave Love committed
215
 temacs:
Jim Blandy's avatar
Jim Blandy committed
216

Dave Love's avatar
Dave Love committed
217 218 219 220
                     **** ELF HEADER ****
 Class        Data       Type         Machine     Version
 Entry        Phoff      Shoff        Flags       Ehsize
 Phentsize    Phnum      Shentsz      Shnum       Shstrndx
Jim Blandy's avatar
Jim Blandy committed
221

Dave Love's avatar
Dave Love committed
222 223 224
 1            1          2            3           1
 0x80499cc    0x34       0x792f4      0           0x34
 0x20         5          0x28         21          19
Jim Blandy's avatar
Jim Blandy committed
225

Dave Love's avatar
Dave Love committed
226
 raid:/nfs/raid/src/dist-18.56/src> dump -f xemacs
Jim Blandy's avatar
Jim Blandy committed
227

Dave Love's avatar
Dave Love committed
228
 xemacs:
Jim Blandy's avatar
Jim Blandy committed
229

Dave Love's avatar
Dave Love committed
230 231 232 233
                     **** ELF HEADER ****
 Class        Data       Type         Machine     Version
 Entry        Phoff      Shoff        Flags       Ehsize
 Phentsize    Phnum      Shentsz      Shnum       Shstrndx
Jim Blandy's avatar
Jim Blandy committed
234

Dave Love's avatar
Dave Love committed
235 236 237
 1            1          2            3           1
 0x80499cc    0x34       0x96200      0           0x34
 0x20         5          0x28         22          19
Jim Blandy's avatar
Jim Blandy committed
238

Dave Love's avatar
Dave Love committed
239 240 241 242 243
  * These are the program headers.  "Offset" is the file offset to the
  * segment.  "Vaddr" is the memory load address.  "Filesz" is the
  * segment size as it appears in the file, and "Memsz" is the size in
  * memory.  Below, the third segment is the code and the fourth is the
  * data: the difference between Filesz and Memsz is .bss
Jim Blandy's avatar
Jim Blandy committed
244

Dave Love's avatar
Dave Love committed
245
 raid:/nfs/raid/src/dist-18.56/src> dump -o temacs
Jim Blandy's avatar
Jim Blandy committed
246

Dave Love's avatar
Dave Love committed
247 248 249 250
 temacs:
  ***** PROGRAM EXECUTION HEADER *****
 Type        Offset      Vaddr       Paddr
 Filesz      Memsz       Flags       Align
Jim Blandy's avatar
Jim Blandy committed
251

Dave Love's avatar
Dave Love committed
252 253
 6           0x34        0x8048034   0
 0xa0        0xa0        5           0
Jim Blandy's avatar
Jim Blandy committed
254

Dave Love's avatar
Dave Love committed
255 256
 3           0xd4        0           0
 0x13        0           4           0
Jim Blandy's avatar
Jim Blandy committed
257

Dave Love's avatar
Dave Love committed
258 259
 1           0x34        0x8048034   0
 0x3f2f9     0x3f2f9     5           0x1000
Jim Blandy's avatar
Jim Blandy committed
260

Dave Love's avatar
Dave Love committed
261 262
 1           0x3f330     0x8088330   0
 0x215c4     0x25a60     7           0x1000
Jim Blandy's avatar
Jim Blandy committed
263

Dave Love's avatar
Dave Love committed
264 265
 2           0x60874     0x80a9874   0
 0x80        0           7           0
Jim Blandy's avatar
Jim Blandy committed
266

Dave Love's avatar
Dave Love committed
267
 raid:/nfs/raid/src/dist-18.56/src> dump -o xemacs
Jim Blandy's avatar
Jim Blandy committed
268

Dave Love's avatar
Dave Love committed
269 270 271 272
 xemacs:
  ***** PROGRAM EXECUTION HEADER *****
 Type        Offset      Vaddr       Paddr
 Filesz      Memsz       Flags       Align
Jim Blandy's avatar
Jim Blandy committed
273

Dave Love's avatar
Dave Love committed
274 275
 6           0x34        0x8048034   0
 0xa0        0xa0        5           0
Jim Blandy's avatar
Jim Blandy committed
276

Dave Love's avatar
Dave Love committed
277 278
 3           0xd4        0           0
 0x13        0           4           0
Jim Blandy's avatar
Jim Blandy committed
279

Dave Love's avatar
Dave Love committed
280 281
 1           0x34        0x8048034   0
 0x3f2f9     0x3f2f9     5           0x1000
Jim Blandy's avatar
Jim Blandy committed
282

Dave Love's avatar
Dave Love committed
283 284
 1           0x3f330     0x8088330   0
 0x3e4d0     0x3e4d0     7           0x1000
Jim Blandy's avatar
Jim Blandy committed
285

Dave Love's avatar
Dave Love committed
286 287
 2           0x60874     0x80a9874   0
 0x80        0           7           0
Jim Blandy's avatar
Jim Blandy committed
288 289 290


 */
291

292 293
/* Modified by wtien@urbana.mcd.mot.com of Motorola Inc.
 *
294
 * The above mechanism does not work if the unexeced ELF file is being
295
 * re-layout by other applications (such as `strip'). All the applications
296
 * that re-layout the internal of ELF will layout all sections in ascending
297 298
 * order of their file offsets. After the re-layout, the data2 section will
 * still be the LAST section in the section header vector, but its file offset
299
 * is now being pushed far away down, and causes part of it not to be mapped
300
 * in (ie. not covered by the load segment entry in PHDR vector), therefore
301 302 303 304
 * causes the new binary to fail.
 *
 * The solution is to modify the unexec algorithm to insert the new data2
 * section header right before the new bss section header, so their file
305 306 307
 * offsets will be in the ascending order. Since some of the section's (all
 * sections AFTER the bss section) indexes are now changed, we also need to
 * modify some fields to make them point to the right sections. This is done
308
 * by macro PATCH_INDEX. All the fields that need to be patched are:
309
 *
310 311 312 313 314 315 316
 * 1. ELF header e_shstrndx field.
 * 2. section header sh_link and sh_info field.
 * 3. symbol table entry st_shndx field.
 *
 * The above example now should look like:

           **** SECTION HEADER TABLE ****
Dave Love's avatar
Dave Love committed
317 318
 [No]    Type    Flags   Addr         Offset       Size          Name
         Link    Info    Adralgn      Entsize
319

Dave Love's avatar
Dave Love committed
320 321
 [1]     1       2       0x80480d4    0xd4         0x13          .interp
         0       0       0x1          0
Jim Blandy's avatar
Jim Blandy committed
322

Dave Love's avatar
Dave Love committed
323 324
 [2]     5       2       0x80480e8    0xe8         0x388         .hash
         3       0       0x4          0x4
325

Dave Love's avatar
Dave Love committed
326 327
 [3]     11      2       0x8048470    0x470        0x7f0         .dynsym
         4       1       0x4          0x10
328

Dave Love's avatar
Dave Love committed
329 330
 [4]     3       2       0x8048c60    0xc60        0x3ad         .dynstr
         0       0       0x1          0
331

Dave Love's avatar
Dave Love committed
332 333
 [5]     9       2       0x8049010    0x1010       0x338         .rel.plt
         3       7       0x4          0x8
334

Dave Love's avatar
Dave Love committed
335 336
 [6]     1       6       0x8049348    0x1348       0x3           .init
         0       0       0x4          0
337

Dave Love's avatar
Dave Love committed
338 339
 [7]     1       6       0x804934c    0x134c       0x680         .plt
         0       0       0x4          0x4
340

Dave Love's avatar
Dave Love committed
341 342
 [8]     1       6       0x80499cc    0x19cc       0x3c56f       .text
         0       0       0x4          0
343

Dave Love's avatar
Dave Love committed
344 345
 [9]     1       6       0x8085f3c    0x3df3c      0x3           .fini
         0       0       0x4          0
346

Dave Love's avatar
Dave Love committed
347 348
 [10]    1       2       0x8085f40    0x3df40      0x69c         .rodata
         0       0       0x4          0
349

Dave Love's avatar
Dave Love committed
350 351
 [11]    1       2       0x80865dc    0x3e5dc      0xd51         .rodata1
         0       0       0x4          0
352

Dave Love's avatar
Dave Love committed
353 354
 [12]    1       3       0x8088330    0x3f330      0x20afc       .data
         0       0       0x4          0
355

Dave Love's avatar
Dave Love committed
356 357
 [13]    1       3       0x80a8e2c    0x5fe2c      0x89d         .data1
         0       0       0x4          0
358

Dave Love's avatar
Dave Love committed
359 360
 [14]    1       3       0x80a96cc    0x606cc      0x1a8         .got
         0       0       0x4          0x4
361

Dave Love's avatar
Dave Love committed
362 363
 [15]    6       3       0x80a9874    0x60874      0x80          .dynamic
         4       0       0x4          0x8
364

Dave Love's avatar
Dave Love committed
365 366
 [16]    1       3       0x80a98f4    0x608f4      0x1cf0c       .data
         0       0       0x4          0
367

Dave Love's avatar
Dave Love committed
368 369
 [17]    8       3       0x80c6800    0x7d800      0             .bss
         0       0       0x4          0
370

Dave Love's avatar
Dave Love committed
371 372
 [18]    2       0       0            0x7d800      0x9b90        .symtab
         19      371     0x4          0x10
373

Dave Love's avatar
Dave Love committed
374 375
 [19]    3       0       0            0x87390      0x8526        .strtab
         0       0       0x1          0
376

Dave Love's avatar
Dave Love committed
377 378
 [20]    3       0       0            0x8f8b6      0x93          .shstrtab
         0       0       0x1          0
379

Dave Love's avatar
Dave Love committed
380 381
 [21]    1       0       0            0x8f949      0x68b7        .comment
         0       0       0x1          0
382 383 384

 */

385 386 387
/* We do not use mmap because that fails with NFS.
   Instead we read the whole file, modify it, and write it out.  */

Dave Love's avatar
Dave Love committed
388
#include <config.h>
389 390
#include <unexec.h>

391
extern void fatal (const char *msgid, ...);
Dave Love's avatar
Dave Love committed
392

Jim Blandy's avatar
Jim Blandy committed
393 394 395 396 397 398 399
#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <memory.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
400
#if !defined (__NetBSD__) && !defined (__OpenBSD__)
Jim Blandy's avatar
Jim Blandy committed
401
#include <elf.h>
402
#endif /* not __NetBSD__ and not __OpenBSD__ */
Jim Blandy's avatar
Jim Blandy committed
403
#include <sys/mman.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
404
#if defined (_SYSTYPE_SYSV)
405 406
#include <sys/elf_mips.h>
#include <sym.h>
Dan Nicolaescu's avatar
Dan Nicolaescu committed
407
#endif /* _SYSTYPE_SYSV */
408
#if __sgi
409
#include <syms.h> /* for HDRR declaration */
410
#endif /* __sgi */
411

412 413 414 415 416 417 418 419 420 421 422 423
#ifndef MAP_ANON
#ifdef MAP_ANONYMOUS
#define MAP_ANON MAP_ANONYMOUS
#else
#define MAP_ANON 0
#endif
#endif

#ifndef MAP_FAILED
#define MAP_FAILED ((void *) -1)
#endif

424
#if defined (__alpha__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
/* Declare COFF debugging symbol table.  This used to be in
   /usr/include/sym.h, but this file is no longer included in Red Hat
   5.0 and presumably in any other glibc 2.x based distribution.  */
typedef struct {
	short magic;
	short vstamp;
	int ilineMax;
	int idnMax;
	int ipdMax;
	int isymMax;
	int ioptMax;
	int iauxMax;
	int issMax;
	int issExtMax;
	int ifdMax;
	int crfd;
	int iextMax;
	long cbLine;
	long cbLineOffset;
	long cbDnOffset;
	long cbPdOffset;
	long cbSymOffset;
	long cbOptOffset;
	long cbAuxOffset;
	long cbSsOffset;
	long cbSsExtOffset;
	long cbFdOffset;
	long cbRfdOffset;
	long cbExtOffset;
Dave Love's avatar
Dave Love committed
454
} HDRR, *pHDRR;
455 456
#define cbHDRR sizeof(HDRR)
#define hdrNil ((pHDRR)0)
457 458
#endif

459 460 461 462
#ifdef __NetBSD__
/*
 * NetBSD does not have normal-looking user-land ELF support.
 */
463
# if defined __alpha__ || defined __sparc_v9__
464 465 466 467 468 469
#  define ELFSIZE	64
# else
#  define ELFSIZE	32
# endif
# include <sys/exec_elf.h>

470 471
# ifndef PT_LOAD
#  define PT_LOAD	Elf_pt_load
472 473 474
#  if 0						/* was in pkgsrc patches for 20.7 */
#   define SHT_PROGBITS Elf_sht_progbits
#  endif
475 476 477 478 479 480 481 482 483 484
#  define SHT_SYMTAB	Elf_sht_symtab
#  define SHT_DYNSYM	Elf_sht_dynsym
#  define SHT_NULL	Elf_sht_null
#  define SHT_NOBITS	Elf_sht_nobits
#  define SHT_REL	Elf_sht_rel
#  define SHT_RELA	Elf_sht_rela

#  define SHN_UNDEF	Elf_eshn_undefined
#  define SHN_ABS	Elf_eshn_absolute
#  define SHN_COMMON	Elf_eshn_common
485
# endif /* !PT_LOAD */
486 487 488 489 490

# ifdef __alpha__
#  include <sys/exec_ecoff.h>
#  define HDRR		struct ecoff_symhdr
#  define pHDRR		HDRR *
491
# endif /* __alpha__ */
492

493
#ifdef __mips__			/* was in pkgsrc patches for 20.7 */
494 495 496
# define SHT_MIPS_DEBUG	DT_MIPS_FLAGS
# define HDRR		struct Elf_Shdr
#endif /* __mips__ */
497
#endif /* __NetBSD__ */
498

499 500 501 502
#ifdef __OpenBSD__
# include <sys/exec_elf.h>
#endif

503 504 505 506 507 508
#if __GNU_LIBRARY__ - 0 >= 6
# include <link.h>	/* get ElfW etc */
#endif

#ifndef ElfW
# ifdef __STDC__
Dave Love's avatar
Dave Love committed
509
#  define ElfBitsW(bits, type) Elf##bits##_##type
510
# else
Dave Love's avatar
Dave Love committed
511
#  define ElfBitsW(bits, type) Elf/**/bits/**/_/**/type
512
# endif
Dave Love's avatar
Dave Love committed
513 514 515 516 517 518 519 520
# ifdef _LP64
#  define ELFSIZE 64
# else
#  define ELFSIZE 32
# endif
  /* This macro expands `bits' before invoking ElfBitsW.  */
# define ElfExpandBitsW(bits, type) ElfBitsW (bits, type)
# define ElfW(type) ElfExpandBitsW (ELFSIZE, type)
Jim Blandy's avatar
Jim Blandy committed
521 522 523 524 525
#endif

/* Get the address of a particular section or program header entry,
 * accounting for the size of the entries.
 */
526
/*
527 528 529 530 531 532 533 534
   On PPC Reference Platform running Solaris 2.5.1
   the plt section is also of type NOBI like the bss section.
   (not really stored) and therefore sections after the bss
   section start at the plt offset. The plt section is always
   the one just before the bss section.
   Thus, we modify the test from
      if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset)
   to
535
      if (NEW_SECTION_H (nn).sh_offset >=
536 537 538 539 540 541 542 543 544 545 546 547 548
               OLD_SECTION_H (old_bss_index-1).sh_offset)
   This is just a hack. We should put the new data section
   before the .plt section.
   And we should not have this routine at all but use
   the libelf library to read the old file and create the new
   file.
   The changed code is minimal and depends on prep set in m/prep.h
   Erik Deumens
   Quantum Theory Project
   University of Florida
   deumens@qtp.ufl.edu
   Apr 23, 1996
   */
Jim Blandy's avatar
Jim Blandy committed
549 550

#define OLD_SECTION_H(n) \
551
     (*(ElfW(Shdr) *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
Jim Blandy's avatar
Jim Blandy committed
552
#define NEW_SECTION_H(n) \
553
     (*(ElfW(Shdr) *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
Jim Blandy's avatar
Jim Blandy committed
554
#define NEW_PROGRAM_H(n) \
555
     (*(ElfW(Phdr) *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
Jim Blandy's avatar
Jim Blandy committed
556

557 558
#define PATCH_INDEX(n) \
  do { \
559
	 if ((int) (n) >= old_bss_index) \
560
	   (n)++; } while (0)
Jim Blandy's avatar
Jim Blandy committed
561 562
typedef unsigned char byte;

563 564
/* Round X up to a multiple of Y.  */

565
static ElfW(Addr)
566
round_up (ElfW(Addr) x, ElfW(Addr) y)
567 568 569 570 571 572 573
{
  int rem = x % y;
  if (rem == 0)
    return x;
  return x - rem + y;
}

574 575 576 577 578 579 580 581
/* Return the index of the section named NAME.
   SECTION_NAMES, FILE_NAME and FILE_H give information
   about the file we are looking in.

   If we don't find the section NAME, that is a fatal error
   if NOERROR is 0; we return -1 if NOERROR is nonzero.  */

static int
582
find_section (const char *name, const char *section_names, const char *file_name,
583
	      ElfW(Ehdr) *old_file_h, ElfW(Shdr) *old_section_h, int noerror)
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
{
  int idx;

  for (idx = 1; idx < old_file_h->e_shnum; idx++)
    {
#ifdef DEBUG
      fprintf (stderr, "Looking for %s - found %s\n", name,
	       section_names + OLD_SECTION_H (idx).sh_name);
#endif
      if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name,
		   name))
	break;
    }
  if (idx == old_file_h->e_shnum)
    {
      if (noerror)
	return -1;
      else
602
	fatal ("Can't find %s in %s.\n", name, file_name);
603 604 605 606 607
    }

  return idx;
}

Jim Blandy's avatar
Jim Blandy committed
608 609 610 611 612 613 614 615 616 617
/* ****************************************************************
 * unexec
 *
 * driving logic.
 *
 * In ELF, this works by replacing the old .bss section with a new
 * .data section, and inserting an empty .bss immediately afterwards.
 *
 */
void
618
unexec (const char *new_name, const char *old_name)
Jim Blandy's avatar
Jim Blandy committed
619 620 621
{
  int new_file, old_file, new_file_size;

622 623 624 625
#if defined (emacs) || !defined (DEBUG)
  void *new_break;
#endif

626
  /* Pointers to the base of the image of the two files.  */
Jim Blandy's avatar
Jim Blandy committed
627 628
  caddr_t old_base, new_base;

629 630 631 632 633 634
#if MAP_ANON == 0
  int mmap_fd;
#else
# define mmap_fd -1
#endif

635 636
  /* Pointers to the file, program and section headers for the old and
     new files.  */
637 638 639
  ElfW(Ehdr) *old_file_h, *new_file_h;
  ElfW(Phdr) *old_program_h, *new_program_h;
  ElfW(Shdr) *old_section_h, *new_section_h;
Jim Blandy's avatar
Jim Blandy committed
640

641
  /* Point to the section name table in the old file.  */
Jim Blandy's avatar
Jim Blandy committed
642 643
  char *old_section_names;

644 645 646 647
  ElfW(Addr) old_bss_addr, new_bss_addr;
  ElfW(Word) old_bss_size, new_data2_size;
  ElfW(Off)  new_data2_offset;
  ElfW(Addr) new_data2_addr;
648 649
  ElfW(Off)  old_bss_offset;
  ElfW(Word) new_data2_incr;
Jim Blandy's avatar
Jim Blandy committed
650

651
  int n, nn;
652
  int old_bss_index, old_sbss_index, old_plt_index;
653 654
  int old_data_index, new_data2_index;
  int old_mdebug_index;
Jim Blandy's avatar
Jim Blandy committed
655
  struct stat stat_buf;
656
  int old_file_size;
Jim Blandy's avatar
Jim Blandy committed
657

658
  /* Open the old file, allocate a buffer of the right size, and read
659
     in the file contents.  */
Jim Blandy's avatar
Jim Blandy committed
660 661 662 663 664 665 666

  old_file = open (old_name, O_RDONLY);

  if (old_file < 0)
    fatal ("Can't open %s for reading: errno %d\n", old_name, errno);

  if (fstat (old_file, &stat_buf) == -1)
667
    fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
Jim Blandy's avatar
Jim Blandy committed
668

669 670 671
#if MAP_ANON == 0
  mmap_fd = open ("/dev/zero", O_RDONLY);
  if (mmap_fd < 0)
672
    fatal ("Can't open /dev/zero for reading: errno %d\n", errno, 0);
673 674
#endif

675 676 677 678 679 680
  /* We cannot use malloc here because that may use sbrk.  If it does,
     we'd dump our temporary buffers with Emacs, and we'd have to be
     extra careful to use the correct value of sbrk(0) after
     allocating all buffers in the code below, which we aren't.  */
  old_file_size = stat_buf.st_size;
  old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE,
681 682
		   MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
  if (old_base == MAP_FAILED)
683
    fatal ("Can't allocate buffer for %s\n", old_name, 0);
Jim Blandy's avatar
Jim Blandy committed
684

685 686 687
  if (read (old_file, old_base, stat_buf.st_size) != stat_buf.st_size)
    fatal ("Didn't read all of %s: errno %d\n", old_name, errno);

Jim Blandy's avatar
Jim Blandy committed
688 689
  /* Get pointers to headers & section names */

690 691 692
  old_file_h = (ElfW(Ehdr) *) old_base;
  old_program_h = (ElfW(Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
  old_section_h = (ElfW(Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
Jim Blandy's avatar
Jim Blandy committed
693
  old_section_names = (char *) old_base
694
    + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
Jim Blandy's avatar
Jim Blandy committed
695

696 697 698 699 700
  /* Find the mdebug section, if any.  */

  old_mdebug_index = find_section (".mdebug", old_section_names,
				   old_name, old_file_h, old_section_h, 1);

Jim Blandy's avatar
Jim Blandy committed
701
  /* Find the old .bss section.  Figure out parameters of the new
702
     data2 and bss sections.  */
Jim Blandy's avatar
Jim Blandy committed
703

704 705
  old_bss_index = find_section (".bss", old_section_names,
				old_name, old_file_h, old_section_h, 0);
Jim Blandy's avatar
Jim Blandy committed
706

707 708
  old_sbss_index = find_section (".sbss", old_section_names,
				 old_name, old_file_h, old_section_h, 1);
Dave Love's avatar
Dave Love committed
709
  if (old_sbss_index != -1)
710
    if (OLD_SECTION_H (old_sbss_index).sh_type != SHT_NOBITS)
Dave Love's avatar
Dave Love committed
711
      old_sbss_index = -1;
712

713 714 715 716 717 718 719 720
  /* PowerPC64 has .plt in the BSS section.  */
  old_plt_index = find_section (".plt", old_section_names,
				old_name, old_file_h, old_section_h, 1);
  if (old_plt_index != -1)
    if (OLD_SECTION_H (old_plt_index).sh_type != SHT_NOBITS)
      old_plt_index = -1;

  if (old_sbss_index == -1 && old_plt_index == -1)
721
    {
722 723
      old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
724
      old_bss_offset = OLD_SECTION_H (old_bss_index).sh_offset;
725 726
      new_data2_index = old_bss_index;
    }
727 728 729 730 731 732 733 734 735 736
  else if (old_plt_index != -1
	   && (old_sbss_index == -1
	       || (OLD_SECTION_H (old_sbss_index).sh_addr
		   > OLD_SECTION_H (old_plt_index).sh_addr)))
    {
      old_bss_addr = OLD_SECTION_H (old_plt_index).sh_addr;
      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
	+ OLD_SECTION_H (old_plt_index).sh_size;
      if (old_sbss_index != -1)
	old_bss_size += OLD_SECTION_H (old_sbss_index).sh_size;
737
      old_bss_offset = OLD_SECTION_H (old_plt_index).sh_offset;
738 739
      new_data2_index = old_plt_index;
    }
740 741
  else
    {
742 743 744
      old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
	+ OLD_SECTION_H (old_sbss_index).sh_size;
745
      old_bss_offset = OLD_SECTION_H (old_sbss_index).sh_offset;
746 747 748
      new_data2_index = old_sbss_index;
    }

749 750 751 752 753
  /* Find the old .data section.  Figure out parameters of
     the new data2 and bss sections.  */

  old_data_index = find_section (".data", old_section_names,
				 old_name, old_file_h, old_section_h, 0);
754

755
#if defined (emacs) || !defined (DEBUG)
756 757
  new_break = sbrk (0);
  new_bss_addr = (ElfW(Addr)) new_break;
Jim Blandy's avatar
Jim Blandy committed
758 759 760 761 762
#else
  new_bss_addr = old_bss_addr + old_bss_size + 0x1234;
#endif
  new_data2_addr = old_bss_addr;
  new_data2_size = new_bss_addr - old_bss_addr;
763 764 765 766 767 768 769
  new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset
    + (new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
  /* This is the amount by which the sections following the bss sections
     must be shifted in the image.  It can differ from new_data2_size if
     the end of the old .data section (and thus the offset of the .bss
     section) was unaligned.  */
  new_data2_incr = new_data2_size + (new_data2_offset - old_bss_offset);
Jim Blandy's avatar
Jim Blandy committed
770 771 772

#ifdef DEBUG
  fprintf (stderr, "old_bss_index %d\n", old_bss_index);
Karl Heuer's avatar
Karl Heuer committed
773 774
  fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
  fprintf (stderr, "old_bss_size %x\n", old_bss_size);
775
  fprintf (stderr, "old_bss_offset %x\n", old_bss_offset);
Karl Heuer's avatar
Karl Heuer committed
776 777 778 779
  fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
  fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
  fprintf (stderr, "new_data2_size %x\n", new_data2_size);
  fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);
780
  fprintf (stderr, "new_data2_incr %x\n", new_data2_incr);
Jim Blandy's avatar
Jim Blandy committed
781 782
#endif

Karl Heuer's avatar
Karl Heuer committed
783
  if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size)
Jim Blandy's avatar
Jim Blandy committed
784 785
    fatal (".bss shrank when undumping???\n", 0, 0);

786
  /* Set the output file to the right size.  Allocate a buffer to hold
787 788
     the image of the new file.  Set pointers to various interesting
     objects.  stat_buf still has old_file data.  */
Jim Blandy's avatar
Jim Blandy committed
789 790 791

  new_file = open (new_name, O_RDWR | O_CREAT, 0666);
  if (new_file < 0)
792
    fatal ("Can't creat (%s): errno %d\n", new_name, errno);
Jim Blandy's avatar
Jim Blandy committed
793

794
  new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_incr;
Jim Blandy's avatar
Jim Blandy committed
795 796

  if (ftruncate (new_file, new_file_size))
797
    fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
Jim Blandy's avatar
Jim Blandy committed
798

799
  new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE,
800 801
		   MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
  if (new_base == MAP_FAILED)
802
    fatal ("Can't allocate buffer for %s\n", old_name, 0);
803

804 805 806
  new_file_h = (ElfW(Ehdr) *) new_base;
  new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
  new_section_h = (ElfW(Shdr) *)
807
    ((byte *) new_base + old_file_h->e_shoff + new_data2_incr);
Jim Blandy's avatar
Jim Blandy committed
808 809

  /* Make our new file, program and section headers as copies of the
810
     originals.  */
Jim Blandy's avatar
Jim Blandy committed
811 812 813 814

  memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
  memcpy (new_program_h, old_program_h,
	  old_file_h->e_phnum * old_file_h->e_phentsize);
815 816 817

  /* Modify the e_shstrndx if necessary. */
  PATCH_INDEX (new_file_h->e_shstrndx);
Jim Blandy's avatar
Jim Blandy committed
818 819

  /* Fix up file header.  We'll add one section.  Section header is
820
     further away now.  */
Jim Blandy's avatar
Jim Blandy committed
821

822
  new_file_h->e_shoff += new_data2_incr;
Jim Blandy's avatar
Jim Blandy committed
823 824 825
  new_file_h->e_shnum += 1;

#ifdef DEBUG
Karl Heuer's avatar
Karl Heuer committed
826
  fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff);
Jim Blandy's avatar
Jim Blandy committed
827
  fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum);
Karl Heuer's avatar
Karl Heuer committed
828
  fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff);
Jim Blandy's avatar
Jim Blandy committed
829 830 831 832
  fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);
#endif

  /* Fix up a new program header.  Extend the writable data segment so
833 834 835 836 837
     that the bss area is covered too. Find that segment by looking
     for a segment that ends just before the .bss area.  Make sure
     that no segments are above the new .data2.  Put a loop at the end
     to adjust the offset and address of any segment that is above
     data2, just in case we decide to allow this later.  */
Jim Blandy's avatar
Jim Blandy committed
838 839 840

  for (n = new_file_h->e_phnum - 1; n >= 0; n--)
    {
841
      /* Compute maximum of all requirements for alignment of section.  */
842
      ElfW(Word) alignment = (NEW_PROGRAM_H (n)).p_align;
843 844 845
      if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
	alignment = OLD_SECTION_H (old_bss_index).sh_addralign;

846
#ifdef __sgi
847 848 849 850 851
	  /* According to r02kar@x4u2.desy.de (Karsten Kuenne)
	     and oliva@gnu.org (Alexandre Oliva), on IRIX 5.2, we
	     always get "Program segment above .bss" when dumping
	     when the executable doesn't have an sbss section.  */
      if (old_sbss_index != -1)
852
#endif /* __sgi */
853
      if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz
854 855 856 857
	  > (old_sbss_index == -1
	     ? old_bss_addr
	     : round_up (old_bss_addr, alignment)))
	  fatal ("Program segment above .bss in %s\n", old_name, 0);
Jim Blandy's avatar
Jim Blandy committed
858

859
      if (NEW_PROGRAM_H (n).p_type == PT_LOAD
860 861 862 863
	  && (round_up ((NEW_PROGRAM_H (n)).p_vaddr
			+ (NEW_PROGRAM_H (n)).p_filesz,
			alignment)
	      == round_up (old_bss_addr, alignment)))
Jim Blandy's avatar
Jim Blandy committed
864 865 866 867 868
	break;
    }
  if (n < 0)
    fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);

869 870 871
  /* Make sure that the size includes any padding before the old .bss
     section.  */
  NEW_PROGRAM_H (n).p_filesz = new_bss_addr - NEW_PROGRAM_H (n).p_vaddr;
872
  NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
Jim Blandy's avatar
Jim Blandy committed
873 874 875 876

#if 0 /* Maybe allow section after data2 - does this ever happen? */
  for (n = new_file_h->e_phnum - 1; n >= 0; n--)
    {
877 878 879
      if (NEW_PROGRAM_H (n).p_vaddr
	  && NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr)
	NEW_PROGRAM_H (n).p_vaddr += new_data2_size - old_bss_size;
Jim Blandy's avatar
Jim Blandy committed
880

881
      if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset)
882
	NEW_PROGRAM_H (n).p_offset += new_data2_incr;
Jim Blandy's avatar
Jim Blandy committed
883 884 885 886
    }
#endif

  /* Fix up section headers based on new .data2 section.  Any section
887 888 889 890
     whose offset or virtual address is after the new .data2 section
     gets its value adjusted.  .bss size becomes zero and new address
     is set.  data2 section header gets added by copying the existing
     .data header and modifying the offset, address and size.  */
Jim Blandy's avatar
Jim Blandy committed
891

892
  /* Walk through all section headers, insert the new data2 section right
893
     before the new bss section. */
894
  for (n = 1, nn = 1; n < (int) old_file_h->e_shnum; n++, nn++)
Jim Blandy's avatar
Jim Blandy committed
895 896
    {
      caddr_t src;
897 898 899
      /* If it is (s)bss section, insert the new data2 section before it.  */
      /* new_data2_index is the index of either old_sbss or old_bss, that was
	 chosen as a section for new_data2.   */
900
      if (n == new_data2_index)
901 902
	{
	  /* Steal the data section header for this data2 section. */