1167465Smp/* BFD back end for traditional Unix core files (U-area and raw sections)
259243Sobrien   Copyright (C) 1988-2022 Free Software Foundation, Inc.
359243Sobrien   Written by John Gilmore of Cygnus Support.
459243Sobrien
559243Sobrien   This file is part of BFD, the Binary File Descriptor library.
659243Sobrien
759243Sobrien   This program is free software; you can redistribute it and/or modify
859243Sobrien   it under the terms of the GNU General Public License as published by
959243Sobrien   the Free Software Foundation; either version 3 of the License, or
1059243Sobrien   (at your option) any later version.
1159243Sobrien
1259243Sobrien   This program is distributed in the hope that it will be useful,
1359243Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1459243Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1559243Sobrien   GNU General Public License for more details.
1659243Sobrien
17100616Smp   You should have received a copy of the GNU General Public License
1859243Sobrien   along with this program; if not, write to the Free Software
1959243Sobrien   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2059243Sobrien   MA 02110-1301, USA.  */
2159243Sobrien
2259243Sobrien#include "sysdep.h"
2359243Sobrien#include "bfd.h"
2459243Sobrien#include "libbfd.h"
2559243Sobrien#include "libaout.h"	       /* BFD a.out internal data structures */
2659243Sobrien
2759243Sobrien#include <sys/param.h>
2859243Sobrien#include <dirent.h>
2959243Sobrien#include <signal.h>
3059243Sobrien
3159243Sobrien#include <sys/user.h>		/* After a.out.h  */
3259243Sobrien
3359243Sobrien#ifdef TRAD_HEADER
3459243Sobrien#include TRAD_HEADER
3559243Sobrien#endif
36167465Smp
3759243Sobrien#ifndef NBPG
3859243Sobrien# define NBPG getpagesize()
3959243Sobrien#endif
4059243Sobrien
4159243Sobrienstruct trad_core_struct
4259243Sobrien{
4359243Sobrien  asection *data_section;
4459243Sobrien  asection *stack_section;
4559243Sobrien  asection *reg_section;
46167465Smp  struct user u;
4759243Sobrien};
48145479Smp
49145479Smp#define core_upage(bfd)  (&((bfd)->tdata.trad_core_data->u))
50145479Smp#define core_datasec(bfd)  ((bfd)->tdata.trad_core_data->data_section)
5159243Sobrien#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section)
5259243Sobrien#define core_regsec(bfd)   ((bfd)->tdata.trad_core_data->reg_section)
5359243Sobrien
5459243Sobrien/* forward declarations */
5559243Sobrien
5659243Sobrien#define trad_unix_core_file_matches_executable_p generic_core_file_matches_executable_p
5759243Sobrien#define trad_unix_core_file_pid _bfd_nocore_core_file_pid
5859243Sobrien
5959243Sobrien
6059243Sobrien/* Handle 4.2-style (and perhaps also sysV-style) core dump file.  */
6159243Sobrien
6259243Sobrienstatic bfd_cleanup
6359243Sobrientrad_unix_core_file_p (bfd *abfd)
6459243Sobrien{
6559243Sobrien  int val;
6659243Sobrien  struct user u;
6759243Sobrien  struct trad_core_struct *rawptr;
6859243Sobrien  size_t amt;
6959243Sobrien  flagword flags;
7059243Sobrien
7159243Sobrien#ifdef TRAD_CORE_USER_OFFSET
7259243Sobrien  /* If defined, this macro is the file position of the user struct.  */
7359243Sobrien  if (bfd_seek (abfd, (file_ptr) TRAD_CORE_USER_OFFSET, SEEK_SET) != 0)
7459243Sobrien    return 0;
7559243Sobrien#endif
7659243Sobrien
7759243Sobrien  val = bfd_bread ((void *) &u, (bfd_size_type) sizeof u, abfd);
7859243Sobrien  if (val != sizeof u)
7959243Sobrien    {
8059243Sobrien      /* Too small to be a core file */
8159243Sobrien      bfd_set_error (bfd_error_wrong_format);
8259243Sobrien      return 0;
8359243Sobrien    }
8459243Sobrien
8559243Sobrien  /* Sanity check perhaps??? */
8659243Sobrien  if (u.u_dsize > 0x1000000)	/* Remember, it's in pages...  */
8759243Sobrien    {
8859243Sobrien      bfd_set_error (bfd_error_wrong_format);
8959243Sobrien      return 0;
9059243Sobrien    }
9159243Sobrien  if (u.u_ssize > 0x1000000)
9259243Sobrien    {
9359243Sobrien      bfd_set_error (bfd_error_wrong_format);
9459243Sobrien      return 0;
9559243Sobrien    }
9659243Sobrien
9759243Sobrien  /* Check that the size claimed is no greater than the file size.  */
9859243Sobrien  {
9959243Sobrien    struct stat statbuf;
10059243Sobrien
10159243Sobrien    if (bfd_stat (abfd, &statbuf) < 0)
10259243Sobrien      return 0;
10359243Sobrien
10459243Sobrien    if ((ufile_ptr) NBPG * (UPAGES + u.u_dsize
10559243Sobrien#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
10659243Sobrien			    - u.u_tsize
10759243Sobrien#endif
10859243Sobrien			    + u.u_ssize)
10959243Sobrien	> (ufile_ptr) statbuf.st_size)
11059243Sobrien      {
11159243Sobrien	bfd_set_error (bfd_error_wrong_format);
11259243Sobrien	return 0;
11359243Sobrien      }
11459243Sobrien#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE
11559243Sobrien    if (((ufile_ptr) NBPG * (UPAGES + u.u_dsize + u.u_ssize)
11659243Sobrien#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED
11759243Sobrien	/* Some systems write the file too big.  */
11859243Sobrien	 + TRAD_CORE_EXTRA_SIZE_ALLOWED
11959243Sobrien#endif
12059243Sobrien	 )
12159243Sobrien	< (ufile_ptr) statbuf.st_size)
12259243Sobrien      {
12359243Sobrien	/* The file is too big.  Maybe it's not a core file
12459243Sobrien	   or we otherwise have bad values for u_dsize and u_ssize).  */
12559243Sobrien	bfd_set_error (bfd_error_wrong_format);
12659243Sobrien	return 0;
12759243Sobrien      }
12859243Sobrien#endif
12959243Sobrien  }
13059243Sobrien
13159243Sobrien  /* OK, we believe you.  You're a core file (sure, sure).  */
13259243Sobrien
13359243Sobrien  /* Allocate both the upage and the struct core_data at once, so
13459243Sobrien     a single free() will free them both.  */
13559243Sobrien  amt = sizeof (struct trad_core_struct);
13659243Sobrien  rawptr = (struct trad_core_struct *) bfd_zmalloc (amt);
13759243Sobrien  if (rawptr == NULL)
13859243Sobrien    return 0;
13959243Sobrien
140100616Smp  abfd->tdata.trad_core_data = rawptr;
141100616Smp
142100616Smp  rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */
143100616Smp
144100616Smp  /* Create the sections.  */
14559243Sobrien
14659243Sobrien  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
14759243Sobrien  core_stacksec(abfd) = bfd_make_section_anyway_with_flags (abfd, ".stack",
14859243Sobrien							    flags);
149167465Smp  if (core_stacksec (abfd) == NULL)
150167465Smp    goto fail;
151167465Smp  core_datasec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".data",
152167465Smp							    flags);
15359243Sobrien  if (core_datasec (abfd) == NULL)
15459243Sobrien    goto fail;
15559243Sobrien  core_regsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg",
15659243Sobrien							   SEC_HAS_CONTENTS);
15759243Sobrien  if (core_regsec (abfd) == NULL)
15859243Sobrien    goto fail;
15959243Sobrien
16059243Sobrien  core_datasec (abfd)->size =  NBPG * u.u_dsize
16159243Sobrien#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
162167465Smp    - NBPG * u.u_tsize
163100616Smp#endif
16459243Sobrien      ;
16559243Sobrien  core_stacksec (abfd)->size = NBPG * u.u_ssize;
16659243Sobrien  core_regsec (abfd)->size = NBPG * UPAGES; /* Larger than sizeof struct u */
167100616Smp
168167465Smp  /* What a hack... we'd like to steal it from the exec file,
169167465Smp     since the upage does not seem to provide it.  FIXME.  */
170167465Smp#ifdef HOST_DATA_START_ADDR
171167465Smp  core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
172167465Smp#else
173167465Smp  core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
174167465Smp#endif
17559243Sobrien
176#ifdef HOST_STACK_START_ADDR
177  core_stacksec (abfd)->vma = HOST_STACK_START_ADDR;
178#else
179  core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
180#endif
181
182  /* This is tricky.  As the "register section", we give them the entire
183     upage and stack.  u.u_ar0 points to where "register 0" is stored.
184     There are two tricks with this, though.  One is that the rest of the
185     registers might be at positive or negative (or both) displacements
186     from *u_ar0.  The other is that u_ar0 is sometimes an absolute address
187     in kernel memory, and on other systems it is an offset from the beginning
188     of the `struct user'.
189
190     As a practical matter, we don't know where the registers actually are,
191     so we have to pass the whole area to GDB.  We encode the value of u_ar0
192     by setting the .regs section up so that its virtual memory address
193     0 is at the place pointed to by u_ar0 (by setting the vma of the start
194     of the section to -u_ar0).  GDB uses this info to locate the regs,
195     using minor trickery to get around the offset-or-absolute-addr problem.  */
196  core_regsec (abfd)->vma = - (bfd_vma) (unsigned long) u.u_ar0;
197
198  core_datasec (abfd)->filepos = NBPG * UPAGES;
199  core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize
200#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
201    - NBPG * u.u_tsize
202#endif
203      ;
204  core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
205
206  /* Align to word at least */
207  core_stacksec (abfd)->alignment_power = 2;
208  core_datasec (abfd)->alignment_power = 2;
209  core_regsec (abfd)->alignment_power = 2;
210
211  return _bfd_no_cleanup;
212
213 fail:
214  bfd_release (abfd, abfd->tdata.any);
215  abfd->tdata.any = NULL;
216  bfd_section_list_clear (abfd);
217  return NULL;
218}
219
220static char *
221trad_unix_core_file_failing_command (bfd *abfd)
222{
223#ifndef NO_CORE_COMMAND
224  char *com = abfd->tdata.trad_core_data->u.u_comm;
225  if (*com)
226    return com;
227  else
228#endif
229    return 0;
230}
231
232static int
233trad_unix_core_file_failing_signal (bfd *ignore_abfd ATTRIBUTE_UNUSED)
234{
235#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL
236  return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd);
237#else
238  return -1;		/* FIXME, where is it? */
239#endif
240}
241
242/* If somebody calls any byte-swapping routines, shoot them.  */
243static void
244swap_abort (void)
245{
246  abort (); /* This way doesn't require any declaration for ANSI to fuck up */
247}
248
249#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
250#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
251#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
252#define	NO_GET64 ((uint64_t (*) (const void *)) swap_abort)
253#define	NO_PUT64 ((void (*) (uint64_t, void *)) swap_abort)
254#define	NO_GETS64 ((int64_t (*) (const void *)) swap_abort)
255
256const bfd_target core_trad_vec =
257  {
258    "trad-core",
259    bfd_target_unknown_flavour,
260    BFD_ENDIAN_UNKNOWN,		/* target byte order */
261    BFD_ENDIAN_UNKNOWN,		/* target headers byte order */
262    (HAS_RELOC | EXEC_P |	/* object flags */
263     HAS_LINENO | HAS_DEBUG |
264     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
265    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
266    0,				/* symbol prefix */
267    ' ',			/* ar_pad_char */
268    16,				/* ar_max_namelen */
269    0,				/* match priority.  */
270    TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
271    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data */
272    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data */
273    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data */
274    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs */
275    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs */
276    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs */
277
278    {				/* bfd_check_format */
279      _bfd_dummy_target,		/* unknown format */
280      _bfd_dummy_target,		/* object file */
281      _bfd_dummy_target,		/* archive */
282      trad_unix_core_file_p		/* a core file */
283    },
284    {				/* bfd_set_format */
285      _bfd_bool_bfd_false_error,
286      _bfd_bool_bfd_false_error,
287      _bfd_bool_bfd_false_error,
288      _bfd_bool_bfd_false_error
289    },
290    {				/* bfd_write_contents */
291      _bfd_bool_bfd_false_error,
292      _bfd_bool_bfd_false_error,
293      _bfd_bool_bfd_false_error,
294      _bfd_bool_bfd_false_error
295    },
296
297    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
298    BFD_JUMP_TABLE_COPY (_bfd_generic),
299    BFD_JUMP_TABLE_CORE (trad_unix),
300    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
301    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
302    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
303    BFD_JUMP_TABLE_WRITE (_bfd_generic),
304    BFD_JUMP_TABLE_LINK (_bfd_nolink),
305    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
306
307    NULL,
308
309    NULL			/* backend_data */
310  };
311