Remove support for DJGPP v1.x (bug#5813).
[bpt/emacs.git] / src / unexec.c
CommitLineData
429ab54e 1/* Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 2001, 2002, 2003,
114f9c96 2 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
7dd63af1
RS
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
7dd63af1 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
7dd63af1
RS
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
7dd63af1
RS
18
19
20/*
21 * unexec.c - Convert a running program into an a.out file.
22 *
23 * Author: Spencer W. Thomas
24 * Computer Science Dept.
25 * University of Utah
26 * Date: Tue Mar 2 1982
27 * Modified heavily since then.
28 *
29 * Synopsis:
30 * unexec (new_name, a_name, data_start, bss_start, entry_address)
31 * char *new_name, *a_name;
32 * unsigned data_start, bss_start, entry_address;
33 *
34 * Takes a snapshot of the program and makes an a.out format file in the
35 * file named by the string argument new_name.
36 * If a_name is non-NULL, the symbol table will be taken from the given file.
37 * On some machines, an existing a_name file is required.
38 *
39 * The boundaries within the a.out file may be adjusted with the data_start
40 * and bss_start arguments. Either or both may be given as 0 for defaults.
41 *
42 * Data_start gives the boundary between the text segment and the data
43 * segment of the program. The text segment can contain shared, read-only
44 * program code and literal data, while the data segment is always unshared
45 * and unprotected. Data_start gives the lowest unprotected address.
46 * The value you specify may be rounded down to a suitable boundary
47 * as required by the machine you are using.
48 *
49 * Specifying zero for data_start means the boundary between text and data
50 * should not be the same as when the program was loaded.
51 * If NO_REMAP is defined, the argument data_start is ignored and the
52 * segment boundaries are never changed.
53 *
54 * Bss_start indicates how much of the data segment is to be saved in the
55 * a.out file and restored when the program is executed. It gives the lowest
56 * unsaved address, and is rounded up to a page boundary. The default when 0
57 * is given assumes that the entire data segment is to be stored, including
58 * the previous data and bss as well as any additional storage allocated with
59 * break (2).
60 *
61 * The new file is set up to start at entry_address.
62 *
63 * If you make improvements I'd like to get them too.
64 * harpo!utah-cs!thomas, thomas@Utah-20
65 *
66 */
67
68/* Modified to support SysVr3 shared libraries by James Van Artsdalen
69 * of Dell Computer Corporation. james@bigtex.cactus.org.
70 */
71
72/* There are several compilation parameters affecting unexec:
73
74* COFF
75
76Define this if your system uses COFF for executables.
265a9e55 77
7dd63af1
RS
78* NO_REMAP
79
80Define this if you do not want to try to save Emacs's pure data areas
81as part of the text segment.
82
83Saving them as text is good because it allows users to share more.
84
85However, on machines that locate the text area far from the data area,
86the boundary cannot feasibly be moved. Such machines require
87NO_REMAP.
88
89Also, remapping can cause trouble with the built-in startup routine
90/lib/crt0.o, which defines `environ' as an initialized variable.
91Dumping `environ' as pure does not work! So, to use remapping,
92you must write a startup routine for your machine in Emacs's crt0.c.
93If NO_REMAP is defined, Emacs uses the system's crt0.o.
94
95* SECTION_ALIGNMENT
96
97Some machines that use COFF executables require that each section
98start on a certain boundary *in the COFF file*. Such machines should
99define SECTION_ALIGNMENT to a mask of the low-order bits that must be
100zero on such a boundary. This mask is used to control padding between
101segments in the COFF file.
102
103If SECTION_ALIGNMENT is not defined, the segments are written
104consecutively with no attempt at alignment. This is right for
105unmodified system V.
106
107* SEGMENT_MASK
108
109Some machines require that the beginnings and ends of segments
110*in core* be on certain boundaries. For most machines, a page
111boundary is sufficient. That is the default. When a larger
112boundary is needed, define SEGMENT_MASK to a mask of
113the bits that must be zero on such a boundary.
114
7dd63af1
RS
115* ADJUST_EXEC_HEADER
116
117This macro can be used to generate statements to adjust or
118initialize nonstandard fields in the file header
119
7dd63af1
RS
120*/
121
122#ifndef emacs
123#define PERROR(arg) perror (arg); return -1
124#else
18160b98 125#include <config.h>
7dd63af1
RS
126#define PERROR(file) report_error (file, new)
127#endif
128
129#ifndef CANNOT_DUMP /* all rest of file! */
130
f914a6bf 131#ifdef HAVE_COFF_H
2a4487ac 132#include <coff.h>
3680bdc6 133#ifdef MSDOS
8eb2807f 134#include <fcntl.h> /* for O_RDONLY, O_RDWR */
c17a2102
KH
135#include <crt0.h> /* for _crt0_startup_flags and its bits */
136static int save_djgpp_startup_flags;
3680bdc6
RS
137#define filehdr external_filehdr
138#define scnhdr external_scnhdr
139#define syment external_syment
140#define auxent external_auxent
141#define n_numaux e_numaux
142#define n_type e_type
143struct aouthdr
144{
234d3183
RS
145 unsigned short magic; /* type of file */
146 unsigned short vstamp; /* version stamp */
147 unsigned long tsize; /* text size in bytes, padded to FW bdry*/
148 unsigned long dsize; /* initialized data " " */
149 unsigned long bsize; /* uninitialized data " " */
150 unsigned long entry; /* entry pt. */
151 unsigned long text_start;/* base of text used for this file */
152 unsigned long data_start;/* base of data used for this file */
3680bdc6 153};
3680bdc6 154#endif /* not MSDOS */
f914a6bf 155#else /* not HAVE_COFF_H */
8d228cb0 156#include <a.out.h>
f914a6bf 157#endif /* not HAVE_COFF_H */
265a9e55 158
f34e2e18
RS
159/* Define getpagesize if the system does not.
160 Note that this may depend on symbols defined in a.out.h. */
7dd63af1
RS
161#include "getpagesize.h"
162
163#ifndef makedev /* Try to detect types.h already loaded */
164#include <sys/types.h>
265a9e55 165#endif /* makedev */
7dd63af1
RS
166#include <stdio.h>
167#include <sys/stat.h>
168#include <errno.h>
169
f914a6bf 170#include <sys/file.h>
2d30a233
RM
171
172#ifndef O_RDONLY
173#define O_RDONLY 0
174#endif
175#ifndef O_RDWR
176#define O_RDWR 2
177#endif
178
179
7dd63af1
RS
180extern char *start_of_text (); /* Start of text */
181extern char *start_of_data (); /* Start of initialized data */
182
7dd63af1
RS
183static long block_copy_start; /* Old executable start point */
184static struct filehdr f_hdr; /* File header */
185static struct aouthdr f_ohdr; /* Optional file header (a.out) */
186long bias; /* Bias to add for growth */
187long lnnoptr; /* Pointer to line-number info within file */
188#define SYMS_START block_copy_start
189
190static long text_scnptr;
191static long data_scnptr;
192
c8b14b5f
RS
193static long coff_offset;
194
7dd63af1
RS
195static int pagemask;
196
197/* Correct an int which is the bit pattern of a pointer to a byte
198 into an int which is the number of a byte.
199 This is a no-op on ordinary machines, but not on all. */
200
7dd63af1 201#define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
7dd63af1
RS
202
203#ifdef emacs
204
d7306fe6 205#include <setjmp.h>
2d30a233
RM
206#include "lisp.h"
207
7dd63af1
RS
208static
209report_error (file, fd)
210 char *file;
211 int fd;
212{
213 if (fd)
214 close (fd);
2d30a233 215 report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
7dd63af1
RS
216}
217#endif /* emacs */
218
219#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
220#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
221#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
222
223static
224report_error_1 (fd, msg, a1, a2)
225 int fd;
226 char *msg;
227 int a1, a2;
228{
229 close (fd);
230#ifdef emacs
231 error (msg, a1, a2);
232#else
233 fprintf (stderr, msg, a1, a2);
234 fprintf (stderr, "\n");
235#endif
236}
237\f
238static int make_hdr ();
239static int copy_text_and_data ();
240static int copy_sym ();
241static void mark_x ();
242
7dd63af1
RS
243/* ****************************************************************
244 * make_hdr
245 *
246 * Make the header in the new a.out from the header in core.
247 * Modify the text and data sizes.
248 */
249static int
250make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
251 int new, a_out;
252 unsigned data_start, bss_start, entry_address;
253 char *a_name;
254 char *new_name;
255{
256 int tem;
7dd63af1
RS
257 auto struct scnhdr f_thdr; /* Text section header */
258 auto struct scnhdr f_dhdr; /* Data section header */
259 auto struct scnhdr f_bhdr; /* Bss section header */
260 auto struct scnhdr scntemp; /* Temporary section header */
261 register int scns;
7dd63af1 262 unsigned int bss_end;
7dd63af1
RS
263
264 pagemask = getpagesize () - 1;
265
266 /* Adjust text/data boundary. */
267#ifdef NO_REMAP
268 data_start = (int) start_of_data ();
269#else /* not NO_REMAP */
270 if (!data_start)
271 data_start = (int) start_of_data ();
272#endif /* not NO_REMAP */
273 data_start = ADDR_CORRECT (data_start);
274
275#ifdef SEGMENT_MASK
276 data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */
277#else
278 data_start = data_start & ~pagemask; /* (Down) to page boundary. */
279#endif
280
281 bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
282 bss_end &= ~ pagemask;
283
284 /* Adjust data/bss boundary. */
285 if (bss_start != 0)
286 {
287 bss_start = (ADDR_CORRECT (bss_start) + pagemask);
288 /* (Up) to page bdry. */
289 bss_start &= ~ pagemask;
290 if (bss_start > bss_end)
291 {
292 ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
293 bss_start);
294 }
295 }
296 else
297 bss_start = bss_end;
298
299 if (data_start > bss_start) /* Can't have negative data size. */
300 {
301 ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
302 data_start, bss_start);
303 }
304
c8b14b5f
RS
305 coff_offset = 0L; /* stays zero, except in DJGPP */
306
7dd63af1
RS
307 /* Salvage as much info from the existing file as possible */
308 if (a_out >= 0)
309 {
c8b14b5f 310#ifdef MSDOS
c8b14b5f
RS
311 /* Support the coff-go32-exe format with a prepended stub, since
312 this is what GCC 2.8.0 and later generates by default in DJGPP. */
313 unsigned short mz_header[3];
314
315 if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
316 {
317 PERROR (a_name);
318 }
319 if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a) /* "MZ" or "ZM" */
320 {
321 coff_offset = (long)mz_header[2] * 512L;
322 if (mz_header[1])
323 coff_offset += (long)mz_header[1] - 512L;
324 lseek (a_out, coff_offset, 0);
325 }
326 else
327 lseek (a_out, 0L, 0);
c8b14b5f 328#endif /* MSDOS */
7dd63af1
RS
329 if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
330 {
331 PERROR (a_name);
332 }
333 block_copy_start += sizeof (f_hdr);
334 if (f_hdr.f_opthdr > 0)
335 {
336 if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
337 {
338 PERROR (a_name);
339 }
340 block_copy_start += sizeof (f_ohdr);
341 }
342 /* Loop through section headers, copying them in */
c8b14b5f 343 lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
7dd63af1
RS
344 for (scns = f_hdr.f_nscns; scns > 0; scns--) {
345 if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
346 {
347 PERROR (a_name);
348 }
349 if (scntemp.s_scnptr > 0L)
350 {
351 if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
352 block_copy_start = scntemp.s_scnptr + scntemp.s_size;
353 }
354 if (strcmp (scntemp.s_name, ".text") == 0)
355 {
356 f_thdr = scntemp;
357 }
358 else if (strcmp (scntemp.s_name, ".data") == 0)
359 {
360 f_dhdr = scntemp;
361 }
362 else if (strcmp (scntemp.s_name, ".bss") == 0)
363 {
364 f_bhdr = scntemp;
365 }
366 }
367 }
368 else
369 {
370 ERROR0 ("can't build a COFF file from scratch yet");
371 }
372
373 /* Now we alter the contents of all the f_*hdr variables
374 to correspond to what we want to dump. */
375
7dd63af1 376 f_hdr.f_flags |= (F_RELFLG | F_EXEC);
7dd63af1
RS
377#ifndef NO_REMAP
378 f_ohdr.text_start = (long) start_of_text ();
379 f_ohdr.tsize = data_start - f_ohdr.text_start;
380 f_ohdr.data_start = data_start;
381#endif /* NO_REMAP */
382 f_ohdr.dsize = bss_start - f_ohdr.data_start;
383 f_ohdr.bsize = bss_end - bss_start;
7dd63af1
RS
384 /* On some machines, the old values are right.
385 ??? Maybe on all machines with NO_REMAP. */
386 f_thdr.s_size = f_ohdr.tsize;
387 f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
388 f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
7dd63af1
RS
389 lnnoptr = f_thdr.s_lnnoptr;
390#ifdef SECTION_ALIGNMENT
391 /* Some systems require special alignment
392 of the sections in the file itself. */
393 f_thdr.s_scnptr
394 = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
395#endif /* SECTION_ALIGNMENT */
7dd63af1 396 text_scnptr = f_thdr.s_scnptr;
7dd63af1 397 f_dhdr.s_paddr = f_ohdr.data_start;
7dd63af1
RS
398 f_dhdr.s_vaddr = f_ohdr.data_start;
399 f_dhdr.s_size = f_ohdr.dsize;
400 f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
401#ifdef SECTION_ALIGNMENT
402 /* Some systems require special alignment
403 of the sections in the file itself. */
404 f_dhdr.s_scnptr
405 = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
406#endif /* SECTION_ALIGNMENT */
407#ifdef DATA_SECTION_ALIGNMENT
408 /* Some systems require special alignment
409 of the data section only. */
410 f_dhdr.s_scnptr
411 = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT;
412#endif /* DATA_SECTION_ALIGNMENT */
413 data_scnptr = f_dhdr.s_scnptr;
7dd63af1 414 f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
7dd63af1
RS
415 f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
416 f_bhdr.s_size = f_ohdr.bsize;
417 f_bhdr.s_scnptr = 0L;
7dd63af1 418 bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
7dd63af1
RS
419
420 if (f_hdr.f_symptr > 0L)
421 {
422 f_hdr.f_symptr += bias;
423 }
424
425 if (f_thdr.s_lnnoptr > 0L)
426 {
427 f_thdr.s_lnnoptr += bias;
428 }
429
430#ifdef ADJUST_EXEC_HEADER
431 ADJUST_EXEC_HEADER;
432#endif /* ADJUST_EXEC_HEADER */
433
434 if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
435 {
436 PERROR (new_name);
437 }
438
439 if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
440 {
441 PERROR (new_name);
442 }
443
7dd63af1
RS
444 if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
445 {
446 PERROR (new_name);
447 }
448
449 if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
450 {
451 PERROR (new_name);
452 }
453
454 if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
455 {
456 PERROR (new_name);
457 }
458
7dd63af1
RS
459 return (0);
460
7dd63af1
RS
461}
462\f
730f4d72
EZ
463write_segment (new, ptr, end)
464 int new;
465 register char *ptr, *end;
466{
467 register int i, nwrite, ret;
468 char buf[80];
469#ifndef USE_CRT_DLL
470 extern int errno;
471#endif
472 /* This is the normal amount to write at once.
473 It is the size of block that NFS uses. */
474 int writesize = 1 << 13;
475 int pagesize = getpagesize ();
476 char zeros[1 << 13];
477
478 bzero (zeros, sizeof (zeros));
479
480 for (i = 0; ptr < end;)
481 {
482 /* Distance to next multiple of writesize. */
483 nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
484 /* But not beyond specified end. */
485 if (nwrite > end - ptr) nwrite = end - ptr;
486 ret = write (new, ptr, nwrite);
487 /* If write gets a page fault, it means we reached
488 a gap between the old text segment and the old data segment.
489 This gap has probably been remapped into part of the text segment.
490 So write zeros for it. */
491 if (ret == -1
492#ifdef EFAULT
493 && errno == EFAULT
494#endif
495 )
496 {
497 /* Write only a page of zeros at once,
2b34df4e 498 so that we don't overshoot the start
730f4d72
EZ
499 of the valid memory in the old data segment. */
500 if (nwrite > pagesize)
501 nwrite = pagesize;
502 write (new, zeros, nwrite);
503 }
504#if 0 /* Now that we have can ask `write' to write more than a page,
505 it is legit for write do less than the whole amount specified. */
506 else if (nwrite != ret)
507 {
508 sprintf (buf,
509 "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
510 ptr, new, nwrite, ret, errno);
511 PERROR (buf);
512 }
513#endif
514 i += nwrite;
515 ptr += nwrite;
516 }
517}
7dd63af1
RS
518/* ****************************************************************
519 * copy_text_and_data
520 *
521 * Copy the text and data segments from memory to the new a.out
522 */
523static int
524copy_text_and_data (new, a_out)
525 int new, a_out;
526{
527 register char *end;
528 register char *ptr;
529
8eb2807f 530#ifdef MSDOS
8eb2807f
RS
531 /* Dump the original table of exception handlers, not the one
532 where our exception hooks are registered. */
533 __djgpp_exception_toggle ();
c17a2102
KH
534
535 /* Switch off startup flags that might have been set at runtime
536 and which might change the way that dumped Emacs works. */
537 save_djgpp_startup_flags = _crt0_startup_flags;
538 _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
8eb2807f
RS
539#endif
540
7dd63af1
RS
541 lseek (new, (long) text_scnptr, 0);
542 ptr = (char *) f_ohdr.text_start;
7dd63af1
RS
543 end = ptr + f_ohdr.tsize;
544 write_segment (new, ptr, end);
545
546 lseek (new, (long) data_scnptr, 0);
547 ptr = (char *) f_ohdr.data_start;
548 end = ptr + f_ohdr.dsize;
549 write_segment (new, ptr, end);
550
8eb2807f 551#ifdef MSDOS
8eb2807f
RS
552 /* Restore our exception hooks. */
553 __djgpp_exception_toggle ();
c17a2102
KH
554
555 /* Restore the startup flags. */
556 _crt0_startup_flags = save_djgpp_startup_flags;
8eb2807f 557#endif
8eb2807f 558
7dd63af1
RS
559
560 return 0;
561}
7dd63af1
RS
562\f
563/* ****************************************************************
564 * copy_sym
565 *
566 * Copy the relocation information and symbol table from the a.out to the new
567 */
568static int
569copy_sym (new, a_out, a_name, new_name)
570 int new, a_out;
571 char *a_name, *new_name;
572{
573 char page[1024];
574 int n;
575
576 if (a_out < 0)
577 return 0;
578
7dd63af1
RS
579 if (SYMS_START == 0L)
580 return 0;
7dd63af1 581
7dd63af1 582 if (lnnoptr) /* if there is line number info */
c8b14b5f 583 lseek (a_out, coff_offset + lnnoptr, 0); /* start copying from there */
7dd63af1 584 else
c8b14b5f 585 lseek (a_out, coff_offset + SYMS_START, 0); /* Position a.out to symtab. */
7dd63af1
RS
586
587 while ((n = read (a_out, page, sizeof page)) > 0)
588 {
589 if (write (new, page, n) != n)
590 {
591 PERROR (new_name);
592 }
593 }
594 if (n < 0)
595 {
596 PERROR (a_name);
597 }
598 return 0;
599}
600\f
601/* ****************************************************************
602 * mark_x
603 *
eb8c3be9 604 * After successfully building the new a.out, mark it executable
7dd63af1
RS
605 */
606static void
607mark_x (name)
608 char *name;
609{
610 struct stat sbuf;
611 int um;
612 int new = 0; /* for PERROR */
613
614 um = umask (777);
615 umask (um);
616 if (stat (name, &sbuf) == -1)
617 {
618 PERROR (name);
619 }
620 sbuf.st_mode |= 0111 & ~um;
621 if (chmod (name, sbuf.st_mode) == -1)
622 PERROR (name);
623}
624\f
7dd63af1
RS
625
626/*
627 * If the COFF file contains a symbol table and a line number section,
628 * then any auxiliary entries that have values for x_lnnoptr must
629 * be adjusted by the amount that the line number section has moved
630 * in the file (bias computed in make_hdr). The #@$%&* designers of
631 * the auxiliary entry structures used the absolute file offsets for
632 * the line number entry rather than an offset from the start of the
633 * line number section!
634 *
635 * When I figure out how to scan through the symbol table and pick out
636 * the auxiliary entries that need adjustment, this routine will
637 * be fixed. As it is now, all such entries are wrong and sdb
638 * will complain. Fred Fish, UniSoft Systems Inc.
639 */
640
641/* This function is probably very slow. Instead of reopening the new
642 file for input and output it should copy from the old to the new
643 using the two descriptors already open (WRITEDESC and READDESC).
644 Instead of reading one small structure at a time it should use
645 a reasonable size buffer. But I don't have time to work on such
646 things, so I am installing it as submitted to me. -- RMS. */
647
648adjust_lnnoptrs (writedesc, readdesc, new_name)
649 int writedesc;
650 int readdesc;
651 char *new_name;
652{
653 register int nsyms;
654 register int new;
7dd63af1
RS
655 struct syment symentry;
656 union auxent auxentry;
7dd63af1
RS
657
658 if (!lnnoptr || !f_hdr.f_symptr)
659 return 0;
660
3680bdc6
RS
661#ifdef MSDOS
662 if ((new = writedesc) < 0)
663#else
2d30a233 664 if ((new = open (new_name, O_RDWR)) < 0)
3680bdc6 665#endif
7dd63af1
RS
666 {
667 PERROR (new_name);
668 return -1;
669 }
670
671 lseek (new, f_hdr.f_symptr, 0);
672 for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
673 {
674 read (new, &symentry, SYMESZ);
675 if (symentry.n_numaux)
676 {
677 read (new, &auxentry, AUXESZ);
678 nsyms++;
1ba3de00
RS
679 if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400)
680 {
681 auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
682 lseek (new, -AUXESZ, 1);
683 write (new, &auxentry, AUXESZ);
684 }
7dd63af1
RS
685 }
686 }
3680bdc6 687#ifndef MSDOS
7dd63af1 688 close (new);
3680bdc6
RS
689#endif
690 return 0;
7dd63af1
RS
691}
692
730f4d72
EZ
693/* ****************************************************************
694 * unexec
695 *
696 * driving logic.
697 */
698unexec (new_name, a_name, data_start, bss_start, entry_address)
699 char *new_name, *a_name;
700 unsigned data_start, bss_start, entry_address;
701{
702 int new, a_out = -1;
703
704 if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
705 {
706 PERROR (a_name);
707 }
708 if ((new = creat (new_name, 0666)) < 0)
709 {
710 PERROR (new_name);
711 }
712
713 if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
714 || copy_text_and_data (new, a_out) < 0
715 || copy_sym (new, a_out, a_name, new_name) < 0
730f4d72 716 || adjust_lnnoptrs (new, a_out, new_name) < 0
730f4d72
EZ
717 )
718 {
719 close (new);
720 /* unlink (new_name); /* Failed, unlink new a.out */
721 return -1;
722 }
723
724 close (new);
725 if (a_out >= 0)
726 close (a_out);
727 mark_x (new_name);
728 return 0;
729}
730
7dd63af1 731#endif /* not CANNOT_DUMP */
ab5796a9
MB
732
733/* arch-tag: 62409b69-e27a-4a7c-9413-0210d6b54e7f
734 (do not change this comment) */