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