133965Sjdp/* BFD back end for traditional Unix core files (U-area and raw sections)
278828Sobrien   Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
3218822Sdim   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
460484Sobrien   Free Software Foundation, Inc.
533965Sjdp   Written by John Gilmore of Cygnus Support.
633965Sjdp
733965SjdpThis file is part of BFD, the Binary File Descriptor library.
833965Sjdp
933965SjdpThis program is free software; you can redistribute it and/or modify
1033965Sjdpit under the terms of the GNU General Public License as published by
1133965Sjdpthe Free Software Foundation; either version 2 of the License, or
1233965Sjdp(at your option) any later version.
1333965Sjdp
1433965SjdpThis program is distributed in the hope that it will be useful,
1533965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1633965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1733965SjdpGNU General Public License for more details.
1833965Sjdp
1933965SjdpYou should have received a copy of the GNU General Public License
2033965Sjdpalong with this program; if not, write to the Free Software
21218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2233965Sjdp
23218822Sdim#include "sysdep.h"
2433965Sjdp#include "bfd.h"
2533965Sjdp#include "libbfd.h"
2633965Sjdp#include "libaout.h"           /* BFD a.out internal data structures */
2733965Sjdp
2833965Sjdp#include <sys/param.h>
2977298Sobrien#ifdef HAVE_DIRENT_H
3077298Sobrien# include <dirent.h>
3177298Sobrien#else
3277298Sobrien# ifdef HAVE_SYS_NDIR_H
3377298Sobrien#  include <sys/ndir.h>
3477298Sobrien# endif
3577298Sobrien# ifdef HAVE_SYS_DIR_H
3677298Sobrien#  include <sys/dir.h>
3777298Sobrien# endif
3877298Sobrien# ifdef HAVE_NDIR_H
3977298Sobrien#  include <ndir.h>
4077298Sobrien# endif
4177298Sobrien#endif
4233965Sjdp#include <signal.h>
4333965Sjdp
4433965Sjdp#include <sys/user.h>		/* After a.out.h  */
4533965Sjdp
4633965Sjdp#ifdef TRAD_HEADER
4733965Sjdp#include TRAD_HEADER
4833965Sjdp#endif
4933965Sjdp
50130561Sobrienstruct trad_core_struct
51130561Sobrien{
52130561Sobrien  asection *data_section;
53130561Sobrien  asection *stack_section;
54130561Sobrien  asection *reg_section;
55130561Sobrien  struct user u;
56130561Sobrien};
5733965Sjdp
5833965Sjdp#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u))
5933965Sjdp#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section)
6033965Sjdp#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section)
6133965Sjdp#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section)
6233965Sjdp
6333965Sjdp/* forward declarations */
6433965Sjdp
6533965Sjdpconst bfd_target *trad_unix_core_file_p PARAMS ((bfd *abfd));
66130561Sobrienchar * trad_unix_core_file_failing_command PARAMS ((bfd *abfd));
67130561Sobrienint trad_unix_core_file_failing_signal PARAMS ((bfd *abfd));
68218822Sdim#define trad_unix_core_file_matches_executable_p generic_core_file_matches_executable_p
69130561Sobrienstatic void swap_abort PARAMS ((void));
7033965Sjdp
7133965Sjdp/* Handle 4.2-style (and perhaps also sysV-style) core dump file.  */
7233965Sjdp
7333965Sjdpconst bfd_target *
7433965Sjdptrad_unix_core_file_p (abfd)
7533965Sjdp     bfd *abfd;
7633965Sjdp
7733965Sjdp{
7833965Sjdp  int val;
7933965Sjdp  struct user u;
8033965Sjdp  struct trad_core_struct *rawptr;
8189857Sobrien  bfd_size_type amt;
82218822Sdim  flagword flags;
8333965Sjdp
8433965Sjdp#ifdef TRAD_CORE_USER_OFFSET
8533965Sjdp  /* If defined, this macro is the file position of the user struct.  */
8689857Sobrien  if (bfd_seek (abfd, (file_ptr) TRAD_CORE_USER_OFFSET, SEEK_SET) != 0)
8733965Sjdp    return 0;
8833965Sjdp#endif
8977298Sobrien
9089857Sobrien  val = bfd_bread ((void *) &u, (bfd_size_type) sizeof u, abfd);
9133965Sjdp  if (val != sizeof u)
9233965Sjdp    {
9333965Sjdp      /* Too small to be a core file */
9433965Sjdp      bfd_set_error (bfd_error_wrong_format);
9533965Sjdp      return 0;
9633965Sjdp    }
9733965Sjdp
9833965Sjdp  /* Sanity check perhaps??? */
9977298Sobrien  if (u.u_dsize > 0x1000000)	/* Remember, it's in pages...  */
10033965Sjdp    {
10133965Sjdp      bfd_set_error (bfd_error_wrong_format);
10233965Sjdp      return 0;
10333965Sjdp    }
10433965Sjdp  if (u.u_ssize > 0x1000000)
10533965Sjdp    {
10633965Sjdp      bfd_set_error (bfd_error_wrong_format);
10733965Sjdp      return 0;
10833965Sjdp    }
10933965Sjdp
11033965Sjdp  /* Check that the size claimed is no greater than the file size.  */
11133965Sjdp  {
11233965Sjdp    struct stat statbuf;
113218822Sdim
114218822Sdim    if (bfd_stat (abfd, &statbuf) < 0)
11533965Sjdp      return 0;
116218822Sdim
117218822Sdim    if ((ufile_ptr) NBPG * (UPAGES + u.u_dsize
11833965Sjdp#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
119218822Sdim			    - u.u_tsize
12033965Sjdp#endif
121218822Sdim			    + u.u_ssize)
122218822Sdim	> (ufile_ptr) statbuf.st_size)
12333965Sjdp      {
12460484Sobrien	bfd_set_error (bfd_error_wrong_format);
12533965Sjdp	return 0;
12633965Sjdp      }
12733965Sjdp#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE
128218822Sdim    if (((ufile_ptr) NBPG * (UPAGES + u.u_dsize + u.u_ssize)
12933965Sjdp#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED
13033965Sjdp	/* Some systems write the file too big.  */
131218822Sdim	 + TRAD_CORE_EXTRA_SIZE_ALLOWED
13233965Sjdp#endif
133218822Sdim	 )
134218822Sdim	< (ufile_ptr) statbuf.st_size)
13533965Sjdp      {
13633965Sjdp	/* The file is too big.  Maybe it's not a core file
13733965Sjdp	   or we otherwise have bad values for u_dsize and u_ssize).  */
13833965Sjdp	bfd_set_error (bfd_error_wrong_format);
13933965Sjdp	return 0;
14033965Sjdp      }
14133965Sjdp#endif
14233965Sjdp  }
14333965Sjdp
14433965Sjdp  /* OK, we believe you.  You're a core file (sure, sure).  */
14533965Sjdp
14633965Sjdp  /* Allocate both the upage and the struct core_data at once, so
14733965Sjdp     a single free() will free them both.  */
14889857Sobrien  amt = sizeof (struct trad_core_struct);
14989857Sobrien  rawptr = (struct trad_core_struct *) bfd_zmalloc (amt);
15033965Sjdp  if (rawptr == NULL)
15133965Sjdp    return 0;
15277298Sobrien
15333965Sjdp  abfd->tdata.trad_core_data = rawptr;
15433965Sjdp
15533965Sjdp  rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */
15633965Sjdp
15789857Sobrien  /* Create the sections.  */
15833965Sjdp
159218822Sdim  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
160218822Sdim  core_stacksec(abfd) = bfd_make_section_anyway_with_flags (abfd, ".stack",
161218822Sdim							    flags);
16233965Sjdp  if (core_stacksec (abfd) == NULL)
16389857Sobrien    goto fail;
164218822Sdim  core_datasec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".data",
165218822Sdim							    flags);
16633965Sjdp  if (core_datasec (abfd) == NULL)
16789857Sobrien    goto fail;
168218822Sdim  core_regsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg",
169218822Sdim							   SEC_HAS_CONTENTS);
17033965Sjdp  if (core_regsec (abfd) == NULL)
17189857Sobrien    goto fail;
17233965Sjdp
173218822Sdim  core_datasec (abfd)->size =  NBPG * u.u_dsize
17433965Sjdp#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
17533965Sjdp    - NBPG * u.u_tsize
17633965Sjdp#endif
17733965Sjdp      ;
178218822Sdim  core_stacksec (abfd)->size = NBPG * u.u_ssize;
179218822Sdim  core_regsec (abfd)->size = NBPG * UPAGES; /* Larger than sizeof struct u */
18033965Sjdp
18133965Sjdp  /* What a hack... we'd like to steal it from the exec file,
18233965Sjdp     since the upage does not seem to provide it.  FIXME.  */
18333965Sjdp#ifdef HOST_DATA_START_ADDR
18433965Sjdp  core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
18533965Sjdp#else
18633965Sjdp  core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
18733965Sjdp#endif
18833965Sjdp
18933965Sjdp#ifdef HOST_STACK_START_ADDR
19033965Sjdp  core_stacksec (abfd)->vma = HOST_STACK_START_ADDR;
19133965Sjdp#else
19233965Sjdp  core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
19333965Sjdp#endif
19433965Sjdp
19533965Sjdp  /* This is tricky.  As the "register section", we give them the entire
19633965Sjdp     upage and stack.  u.u_ar0 points to where "register 0" is stored.
19733965Sjdp     There are two tricks with this, though.  One is that the rest of the
19833965Sjdp     registers might be at positive or negative (or both) displacements
19933965Sjdp     from *u_ar0.  The other is that u_ar0 is sometimes an absolute address
20033965Sjdp     in kernel memory, and on other systems it is an offset from the beginning
20133965Sjdp     of the `struct user'.
20277298Sobrien
20333965Sjdp     As a practical matter, we don't know where the registers actually are,
20433965Sjdp     so we have to pass the whole area to GDB.  We encode the value of u_ar0
20533965Sjdp     by setting the .regs section up so that its virtual memory address
20633965Sjdp     0 is at the place pointed to by u_ar0 (by setting the vma of the start
20733965Sjdp     of the section to -u_ar0).  GDB uses this info to locate the regs,
20877298Sobrien     using minor trickery to get around the offset-or-absolute-addr problem.  */
20991041Sobrien  core_regsec (abfd)->vma = - (bfd_vma) (unsigned long) u.u_ar0;
21033965Sjdp
21133965Sjdp  core_datasec (abfd)->filepos = NBPG * UPAGES;
21233965Sjdp  core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize
21333965Sjdp#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
21433965Sjdp    - NBPG * u.u_tsize
21533965Sjdp#endif
21633965Sjdp      ;
21733965Sjdp  core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
21833965Sjdp
21933965Sjdp  /* Align to word at least */
22033965Sjdp  core_stacksec (abfd)->alignment_power = 2;
22133965Sjdp  core_datasec (abfd)->alignment_power = 2;
22233965Sjdp  core_regsec (abfd)->alignment_power = 2;
22333965Sjdp
22489857Sobrien  return abfd->xvec;
22533965Sjdp
22689857Sobrien fail:
22789857Sobrien  bfd_release (abfd, abfd->tdata.any);
22889857Sobrien  abfd->tdata.any = NULL;
22989857Sobrien  bfd_section_list_clear (abfd);
23089857Sobrien  return NULL;
23133965Sjdp}
23233965Sjdp
23333965Sjdpchar *
23433965Sjdptrad_unix_core_file_failing_command (abfd)
23533965Sjdp     bfd *abfd;
23633965Sjdp{
23733965Sjdp#ifndef NO_CORE_COMMAND
23833965Sjdp  char *com = abfd->tdata.trad_core_data->u.u_comm;
23933965Sjdp  if (*com)
24033965Sjdp    return com;
24133965Sjdp  else
24233965Sjdp#endif
24333965Sjdp    return 0;
24433965Sjdp}
24533965Sjdp
24633965Sjdpint
24733965Sjdptrad_unix_core_file_failing_signal (ignore_abfd)
24860484Sobrien     bfd *ignore_abfd ATTRIBUTE_UNUSED;
24933965Sjdp{
25033965Sjdp#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL
25133965Sjdp  return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd);
25233965Sjdp#else
25333965Sjdp  return -1;		/* FIXME, where is it? */
25433965Sjdp#endif
25533965Sjdp}
25633965Sjdp
25733965Sjdp/* If somebody calls any byte-swapping routines, shoot them.  */
25833965Sjdpstatic void
25977298Sobrienswap_abort ()
26033965Sjdp{
26177298Sobrien  abort (); /* This way doesn't require any declaration for ANSI to fuck up */
26233965Sjdp}
26333965Sjdp
264130561Sobrien#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
265130561Sobrien#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
266130561Sobrien#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
267130561Sobrien#define	NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
268130561Sobrien#define	NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
269130561Sobrien#define	NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
270130561Sobrien
27133965Sjdpconst bfd_target trad_core_vec =
27233965Sjdp  {
27333965Sjdp    "trad-core",
27433965Sjdp    bfd_target_unknown_flavour,
27533965Sjdp    BFD_ENDIAN_UNKNOWN,		/* target byte order */
27633965Sjdp    BFD_ENDIAN_UNKNOWN,		/* target headers byte order */
27733965Sjdp    (HAS_RELOC | EXEC_P |	/* object flags */
27833965Sjdp     HAS_LINENO | HAS_DEBUG |
27933965Sjdp     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
28033965Sjdp    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
28133965Sjdp    0,			                                   /* symbol prefix */
28233965Sjdp    ' ',						   /* ar_pad_char */
28333965Sjdp    16,							   /* ar_max_namelen */
284130561Sobrien    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data */
285130561Sobrien    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data */
286130561Sobrien    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data */
287130561Sobrien    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs */
288130561Sobrien    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs */
289130561Sobrien    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs */
29033965Sjdp
29133965Sjdp    {				/* bfd_check_format */
292130561Sobrien      _bfd_dummy_target,		/* unknown format */
293130561Sobrien      _bfd_dummy_target,		/* object file */
294130561Sobrien      _bfd_dummy_target,		/* archive */
295130561Sobrien      trad_unix_core_file_p		/* a core file */
29633965Sjdp    },
29733965Sjdp    {				/* bfd_set_format */
298130561Sobrien      bfd_false, bfd_false,
299130561Sobrien      bfd_false, bfd_false
30033965Sjdp    },
30133965Sjdp    {				/* bfd_write_contents */
302130561Sobrien      bfd_false, bfd_false,
303130561Sobrien      bfd_false, bfd_false
30433965Sjdp    },
30577298Sobrien
306130561Sobrien    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
307130561Sobrien    BFD_JUMP_TABLE_COPY (_bfd_generic),
308130561Sobrien    BFD_JUMP_TABLE_CORE (trad_unix),
309130561Sobrien    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
310130561Sobrien    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
311130561Sobrien    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
312130561Sobrien    BFD_JUMP_TABLE_WRITE (_bfd_generic),
313130561Sobrien    BFD_JUMP_TABLE_LINK (_bfd_nolink),
314130561Sobrien    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
31533965Sjdp
31660484Sobrien    NULL,
31777298Sobrien
31833965Sjdp    (PTR) 0			/* backend_data */
319130561Sobrien  };
320