1/* BFD back end for traditional Unix core files (U-area and raw sections)
2   Copyright (C) 1988-2017 Free Software Foundation, Inc.
3   Written by John Gilmore of Cygnus Support.
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program 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 3 of the License, or
10   (at your option) any later version.
11
12   This program 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.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "libbfd.h"
25#include "libaout.h"           /* BFD a.out internal data structures */
26
27#include <sys/param.h>
28#ifdef HAVE_DIRENT_H
29# include <dirent.h>
30#else
31# ifdef HAVE_SYS_NDIR_H
32#  include <sys/ndir.h>
33# endif
34# ifdef HAVE_SYS_DIR_H
35#  include <sys/dir.h>
36# endif
37# ifdef HAVE_NDIR_H
38#  include <ndir.h>
39# endif
40#endif
41#include <signal.h>
42
43#include <sys/user.h>		/* After a.out.h  */
44
45#ifdef TRAD_HEADER
46#include TRAD_HEADER
47#endif
48
49#ifndef NBPG
50# define NBPG getpagesize()
51#endif
52
53struct trad_core_struct
54{
55  asection *data_section;
56  asection *stack_section;
57  asection *reg_section;
58  struct user u;
59};
60
61#define core_upage(bfd)  (&((bfd)->tdata.trad_core_data->u))
62#define core_datasec(bfd)  ((bfd)->tdata.trad_core_data->data_section)
63#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section)
64#define core_regsec(bfd)   ((bfd)->tdata.trad_core_data->reg_section)
65
66/* forward declarations */
67
68#define trad_unix_core_file_matches_executable_p generic_core_file_matches_executable_p
69#define trad_unix_core_file_pid _bfd_nocore_core_file_pid
70
71
72/* Handle 4.2-style (and perhaps also sysV-style) core dump file.  */
73
74static const bfd_target *
75trad_unix_core_file_p (bfd *abfd)
76{
77  int val;
78  struct user u;
79  struct trad_core_struct *rawptr;
80  bfd_size_type amt;
81  flagword flags;
82
83#ifdef TRAD_CORE_USER_OFFSET
84  /* If defined, this macro is the file position of the user struct.  */
85  if (bfd_seek (abfd, (file_ptr) TRAD_CORE_USER_OFFSET, SEEK_SET) != 0)
86    return 0;
87#endif
88
89  val = bfd_bread ((void *) &u, (bfd_size_type) sizeof u, abfd);
90  if (val != sizeof u)
91    {
92      /* Too small to be a core file */
93      bfd_set_error (bfd_error_wrong_format);
94      return 0;
95    }
96
97  /* Sanity check perhaps??? */
98  if (u.u_dsize > 0x1000000)	/* Remember, it's in pages...  */
99    {
100      bfd_set_error (bfd_error_wrong_format);
101      return 0;
102    }
103  if (u.u_ssize > 0x1000000)
104    {
105      bfd_set_error (bfd_error_wrong_format);
106      return 0;
107    }
108
109  /* Check that the size claimed is no greater than the file size.  */
110  {
111    struct stat statbuf;
112
113    if (bfd_stat (abfd, &statbuf) < 0)
114      return 0;
115
116    if ((ufile_ptr) NBPG * (UPAGES + u.u_dsize
117#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
118			    - u.u_tsize
119#endif
120			    + u.u_ssize)
121	> (ufile_ptr) statbuf.st_size)
122      {
123	bfd_set_error (bfd_error_wrong_format);
124	return 0;
125      }
126#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE
127    if (((ufile_ptr) NBPG * (UPAGES + u.u_dsize + u.u_ssize)
128#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED
129	/* Some systems write the file too big.  */
130	 + TRAD_CORE_EXTRA_SIZE_ALLOWED
131#endif
132	 )
133	< (ufile_ptr) statbuf.st_size)
134      {
135	/* The file is too big.  Maybe it's not a core file
136	   or we otherwise have bad values for u_dsize and u_ssize).  */
137	bfd_set_error (bfd_error_wrong_format);
138	return 0;
139      }
140#endif
141  }
142
143  /* OK, we believe you.  You're a core file (sure, sure).  */
144
145  /* Allocate both the upage and the struct core_data at once, so
146     a single free() will free them both.  */
147  amt = sizeof (struct trad_core_struct);
148  rawptr = (struct trad_core_struct *) bfd_zmalloc (amt);
149  if (rawptr == NULL)
150    return 0;
151
152  abfd->tdata.trad_core_data = rawptr;
153
154  rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */
155
156  /* Create the sections.  */
157
158  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
159  core_stacksec(abfd) = bfd_make_section_anyway_with_flags (abfd, ".stack",
160							    flags);
161  if (core_stacksec (abfd) == NULL)
162    goto fail;
163  core_datasec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".data",
164							    flags);
165  if (core_datasec (abfd) == NULL)
166    goto fail;
167  core_regsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg",
168							   SEC_HAS_CONTENTS);
169  if (core_regsec (abfd) == NULL)
170    goto fail;
171
172  core_datasec (abfd)->size =  NBPG * u.u_dsize
173#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
174    - NBPG * u.u_tsize
175#endif
176      ;
177  core_stacksec (abfd)->size = NBPG * u.u_ssize;
178  core_regsec (abfd)->size = NBPG * UPAGES; /* Larger than sizeof struct u */
179
180  /* What a hack... we'd like to steal it from the exec file,
181     since the upage does not seem to provide it.  FIXME.  */
182#ifdef HOST_DATA_START_ADDR
183  core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
184#else
185  core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
186#endif
187
188#ifdef HOST_STACK_START_ADDR
189  core_stacksec (abfd)->vma = HOST_STACK_START_ADDR;
190#else
191  core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
192#endif
193
194  /* This is tricky.  As the "register section", we give them the entire
195     upage and stack.  u.u_ar0 points to where "register 0" is stored.
196     There are two tricks with this, though.  One is that the rest of the
197     registers might be at positive or negative (or both) displacements
198     from *u_ar0.  The other is that u_ar0 is sometimes an absolute address
199     in kernel memory, and on other systems it is an offset from the beginning
200     of the `struct user'.
201
202     As a practical matter, we don't know where the registers actually are,
203     so we have to pass the whole area to GDB.  We encode the value of u_ar0
204     by setting the .regs section up so that its virtual memory address
205     0 is at the place pointed to by u_ar0 (by setting the vma of the start
206     of the section to -u_ar0).  GDB uses this info to locate the regs,
207     using minor trickery to get around the offset-or-absolute-addr problem.  */
208  core_regsec (abfd)->vma = - (bfd_vma) (unsigned long) u.u_ar0;
209
210  core_datasec (abfd)->filepos = NBPG * UPAGES;
211  core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize
212#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
213    - NBPG * u.u_tsize
214#endif
215      ;
216  core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
217
218  /* Align to word at least */
219  core_stacksec (abfd)->alignment_power = 2;
220  core_datasec (abfd)->alignment_power = 2;
221  core_regsec (abfd)->alignment_power = 2;
222
223  return abfd->xvec;
224
225 fail:
226  bfd_release (abfd, abfd->tdata.any);
227  abfd->tdata.any = NULL;
228  bfd_section_list_clear (abfd);
229  return NULL;
230}
231
232static char *
233trad_unix_core_file_failing_command (bfd *abfd)
234{
235#ifndef NO_CORE_COMMAND
236  char *com = abfd->tdata.trad_core_data->u.u_comm;
237  if (*com)
238    return com;
239  else
240#endif
241    return 0;
242}
243
244static int
245trad_unix_core_file_failing_signal (bfd *ignore_abfd ATTRIBUTE_UNUSED)
246{
247#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL
248  return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd);
249#else
250  return -1;		/* FIXME, where is it? */
251#endif
252}
253
254/* If somebody calls any byte-swapping routines, shoot them.  */
255static void
256swap_abort (void)
257{
258  abort (); /* This way doesn't require any declaration for ANSI to fuck up */
259}
260
261#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
262#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
263#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
264#define	NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
265#define	NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
266#define	NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
267
268const bfd_target core_trad_vec =
269  {
270    "trad-core",
271    bfd_target_unknown_flavour,
272    BFD_ENDIAN_UNKNOWN,		/* target byte order */
273    BFD_ENDIAN_UNKNOWN,		/* target headers byte order */
274    (HAS_RELOC | EXEC_P |	/* object flags */
275     HAS_LINENO | HAS_DEBUG |
276     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
277    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
278    0,				/* symbol prefix */
279    ' ',			/* ar_pad_char */
280    16,				/* ar_max_namelen */
281    0,				/* match priority.  */
282    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data */
283    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data */
284    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data */
285    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs */
286    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs */
287    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs */
288
289    {				/* bfd_check_format */
290      _bfd_dummy_target,		/* unknown format */
291      _bfd_dummy_target,		/* object file */
292      _bfd_dummy_target,		/* archive */
293      trad_unix_core_file_p		/* a core file */
294    },
295    {				/* bfd_set_format */
296      bfd_false, bfd_false,
297      bfd_false, bfd_false
298    },
299    {				/* bfd_write_contents */
300      bfd_false, bfd_false,
301      bfd_false, bfd_false
302    },
303
304    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
305    BFD_JUMP_TABLE_COPY (_bfd_generic),
306    BFD_JUMP_TABLE_CORE (trad_unix),
307    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
308    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
309    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
310    BFD_JUMP_TABLE_WRITE (_bfd_generic),
311    BFD_JUMP_TABLE_LINK (_bfd_nolink),
312    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
313
314    NULL,
315
316    NULL			/* backend_data */
317  };
318