trad-core.c revision 78828
1233294Sstas/* BFD back end for traditional Unix core files (U-area and raw sections)
2178825Sdfr   Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
3178825Sdfr   2000
4178825Sdfr   Free Software Foundation, Inc.
5233294Sstas   Written by John Gilmore of Cygnus Support.
6233294Sstas
7178825SdfrThis file is part of BFD, the Binary File Descriptor library.
8178825Sdfr
9178825SdfrThis program is free software; you can redistribute it and/or modify
10178825Sdfrit under the terms of the GNU General Public License as published by
11178825Sdfrthe Free Software Foundation; either version 2 of the License, or
12178825Sdfr(at your option) any later version.
13178825Sdfr
14178825SdfrThis program is distributed in the hope that it will be useful,
15178825Sdfrbut WITHOUT ANY WARRANTY; without even the implied warranty of
16178825SdfrMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17178825SdfrGNU General Public License for more details.
18233294Sstas
19178825SdfrYou should have received a copy of the GNU General Public License
20233294Sstasalong with this program; if not, write to the Free Software
21178825SdfrFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
22233294Sstas
23178825Sdfr#include "bfd.h"
24178825Sdfr#include "sysdep.h"
25233294Sstas#include "libbfd.h"
26178825Sdfr#include "libaout.h"           /* BFD a.out internal data structures */
27233294Sstas
28178825Sdfr#include <sys/param.h>
29178825Sdfr#ifdef HAVE_DIRENT_H
30178825Sdfr# include <dirent.h>
31178825Sdfr#else
32178825Sdfr# ifdef HAVE_SYS_NDIR_H
33178825Sdfr#  include <sys/ndir.h>
34178825Sdfr# endif
35178825Sdfr# ifdef HAVE_SYS_DIR_H
36178825Sdfr#  include <sys/dir.h>
37178825Sdfr# endif
38178825Sdfr# ifdef HAVE_NDIR_H
39178825Sdfr#  include <ndir.h>
40178825Sdfr# endif
41178825Sdfr#endif
42178825Sdfr#include <signal.h>
43178825Sdfr
44178825Sdfr#include <sys/user.h>		/* After a.out.h  */
45178825Sdfr
46178825Sdfr#ifdef TRAD_HEADER
47178825Sdfr#include TRAD_HEADER
48233294Sstas#endif
49178825Sdfr
50178825Sdfr  struct trad_core_struct
51178825Sdfr    {
52178825Sdfr      asection *data_section;
53178825Sdfr      asection *stack_section;
54178825Sdfr      asection *reg_section;
55178825Sdfr      struct user u;
56178825Sdfr    };
57178825Sdfr
58178825Sdfr#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u))
59178825Sdfr#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section)
60178825Sdfr#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section)
61178825Sdfr#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section)
62178825Sdfr
63233294Sstas/* forward declarations */
64178825Sdfr
65178825Sdfrconst bfd_target *trad_unix_core_file_p PARAMS ((bfd *abfd));
66178825Sdfrchar *		trad_unix_core_file_failing_command PARAMS ((bfd *abfd));
67178825Sdfrint		trad_unix_core_file_failing_signal PARAMS ((bfd *abfd));
68178825Sdfrboolean		trad_unix_core_file_matches_executable_p
69178825Sdfr			 PARAMS ((bfd *core_bfd, bfd *exec_bfd));
70178825Sdfrstatic void	swap_abort PARAMS ((void));
71178825Sdfr
72178825Sdfr/* Handle 4.2-style (and perhaps also sysV-style) core dump file.  */
73178825Sdfr
74178825Sdfr/* ARGSUSED */
75178825Sdfrconst bfd_target *
76178825Sdfrtrad_unix_core_file_p (abfd)
77233294Sstas     bfd *abfd;
78233294Sstas
79233294Sstas{
80233294Sstas  int val;
81233294Sstas  struct user u;
82233294Sstas  struct trad_core_struct *rawptr;
83178825Sdfr
84178825Sdfr#ifdef TRAD_CORE_USER_OFFSET
85178825Sdfr  /* If defined, this macro is the file position of the user struct.  */
86178825Sdfr  if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) != 0)
87178825Sdfr    return 0;
88178825Sdfr#endif
89178825Sdfr
90233294Sstas  val = bfd_read ((void *)&u, 1, sizeof u, abfd);
91178825Sdfr  if (val != sizeof u)
92178825Sdfr    {
93178825Sdfr      /* Too small to be a core file */
94178825Sdfr      bfd_set_error (bfd_error_wrong_format);
95178825Sdfr      return 0;
96233294Sstas    }
97178825Sdfr
98178825Sdfr  /* Sanity check perhaps??? */
99178825Sdfr  if (u.u_dsize > 0x1000000)	/* Remember, it's in pages...  */
100178825Sdfr    {
101178825Sdfr      bfd_set_error (bfd_error_wrong_format);
102178825Sdfr      return 0;
103178825Sdfr    }
104233294Sstas  if (u.u_ssize > 0x1000000)
105233294Sstas    {
106178825Sdfr      bfd_set_error (bfd_error_wrong_format);
107178825Sdfr      return 0;
108178825Sdfr    }
109178825Sdfr
110178825Sdfr  /* Check that the size claimed is no greater than the file size.  */
111233294Sstas  {
112233294Sstas    FILE *stream = bfd_cache_lookup (abfd);
113178825Sdfr    struct stat statbuf;
114178825Sdfr    if (stream == NULL)
115178825Sdfr      return 0;
116233294Sstas    if (fstat (fileno (stream), &statbuf) < 0)
117178825Sdfr      {
118178825Sdfr	bfd_set_error (bfd_error_system_call);
119178825Sdfr	return 0;
120178825Sdfr      }
121178825Sdfr    if ((unsigned long) (NBPG * (UPAGES + u.u_dsize
122233294Sstas#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
123178825Sdfr				 - u.u_tsize
124178825Sdfr#endif
125233294Sstas				 + u.u_ssize))
126178825Sdfr	> (unsigned long) statbuf.st_size)
127178825Sdfr      {
128178825Sdfr	bfd_set_error (bfd_error_wrong_format);
129178825Sdfr	return 0;
130233294Sstas      }
131233294Sstas#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE
132233294Sstas    if ((unsigned long) (NBPG * (UPAGES + u.u_dsize + u.u_ssize)
133178825Sdfr#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED
134178825Sdfr	/* Some systems write the file too big.  */
135178825Sdfr			 + TRAD_CORE_EXTRA_SIZE_ALLOWED
136178825Sdfr#endif
137178825Sdfr			 )
138233294Sstas	< (unsigned long) statbuf.st_size)
139178825Sdfr      {
140178825Sdfr	/* The file is too big.  Maybe it's not a core file
141178825Sdfr	   or we otherwise have bad values for u_dsize and u_ssize).  */
142178825Sdfr	bfd_set_error (bfd_error_wrong_format);
143178825Sdfr	return 0;
144178825Sdfr      }
145233294Sstas#endif
146233294Sstas  }
147178825Sdfr
148178825Sdfr  /* OK, we believe you.  You're a core file (sure, sure).  */
149233294Sstas
150178825Sdfr  /* Allocate both the upage and the struct core_data at once, so
151178825Sdfr     a single free() will free them both.  */
152178825Sdfr  rawptr = (struct trad_core_struct *)
153178825Sdfr		bfd_zmalloc (sizeof (struct trad_core_struct));
154178825Sdfr  if (rawptr == NULL)
155233294Sstas    return 0;
156178825Sdfr
157178825Sdfr  abfd->tdata.trad_core_data = rawptr;
158178825Sdfr
159178825Sdfr  rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */
160178825Sdfr
161178825Sdfr  /* Create the sections.  This is raunchy, but bfd_close wants to free
162178825Sdfr     them separately.  */
163178825Sdfr
164178825Sdfr  core_stacksec(abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
165178825Sdfr  if (core_stacksec (abfd) == NULL)
166178825Sdfr    return NULL;
167178825Sdfr  core_datasec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
168178825Sdfr  if (core_datasec (abfd) == NULL)
169178825Sdfr    return NULL;
170178825Sdfr  core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection));
171178825Sdfr  if (core_regsec (abfd) == NULL)
172178825Sdfr    return NULL;
173178825Sdfr
174178825Sdfr  core_stacksec (abfd)->name = ".stack";
175178825Sdfr  core_datasec (abfd)->name = ".data";
176178825Sdfr  core_regsec (abfd)->name = ".reg";
177178825Sdfr
178178825Sdfr  core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
179233294Sstas  core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
180178825Sdfr  core_regsec (abfd)->flags = SEC_HAS_CONTENTS;
181178825Sdfr
182233294Sstas  core_datasec (abfd)->_raw_size =  NBPG * u.u_dsize
183178825Sdfr#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
184178825Sdfr    - NBPG * u.u_tsize
185178825Sdfr#endif
186178825Sdfr      ;
187178825Sdfr  core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize;
188178825Sdfr  core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */
189178825Sdfr
190178825Sdfr  /* What a hack... we'd like to steal it from the exec file,
191178825Sdfr     since the upage does not seem to provide it.  FIXME.  */
192178825Sdfr#ifdef HOST_DATA_START_ADDR
193178825Sdfr  core_datasec (abfd)->vma = HOST_DATA_START_ADDR;
194178825Sdfr#else
195178825Sdfr  core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize);
196178825Sdfr#endif
197178825Sdfr
198178825Sdfr#ifdef HOST_STACK_START_ADDR
199178825Sdfr  core_stacksec (abfd)->vma = HOST_STACK_START_ADDR;
200233294Sstas#else
201233294Sstas  core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize);
202178825Sdfr#endif
203178825Sdfr
204178825Sdfr  /* This is tricky.  As the "register section", we give them the entire
205178825Sdfr     upage and stack.  u.u_ar0 points to where "register 0" is stored.
206178825Sdfr     There are two tricks with this, though.  One is that the rest of the
207178825Sdfr     registers might be at positive or negative (or both) displacements
208178825Sdfr     from *u_ar0.  The other is that u_ar0 is sometimes an absolute address
209178825Sdfr     in kernel memory, and on other systems it is an offset from the beginning
210178825Sdfr     of the `struct user'.
211178825Sdfr
212178825Sdfr     As a practical matter, we don't know where the registers actually are,
213178825Sdfr     so we have to pass the whole area to GDB.  We encode the value of u_ar0
214178825Sdfr     by setting the .regs section up so that its virtual memory address
215178825Sdfr     0 is at the place pointed to by u_ar0 (by setting the vma of the start
216178825Sdfr     of the section to -u_ar0).  GDB uses this info to locate the regs,
217233294Sstas     using minor trickery to get around the offset-or-absolute-addr problem.  */
218178825Sdfr  core_regsec (abfd)->vma = - (bfd_vma) u.u_ar0;
219178825Sdfr
220233294Sstas  core_datasec (abfd)->filepos = NBPG * UPAGES;
221178825Sdfr  core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize
222178825Sdfr#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE
223178825Sdfr    - NBPG * u.u_tsize
224178825Sdfr#endif
225233294Sstas      ;
226178825Sdfr  core_regsec (abfd)->filepos = 0; /* Register segment is the upage */
227233294Sstas
228233294Sstas  /* Align to word at least */
229233294Sstas  core_stacksec (abfd)->alignment_power = 2;
230178825Sdfr  core_datasec (abfd)->alignment_power = 2;
231233294Sstas  core_regsec (abfd)->alignment_power = 2;
232178825Sdfr
233233294Sstas  abfd->sections = core_stacksec (abfd);
234233294Sstas  core_stacksec (abfd)->next = core_datasec (abfd);
235178825Sdfr  core_datasec (abfd)->next = core_regsec (abfd);
236178825Sdfr  abfd->section_count = 3;
237178825Sdfr
238178825Sdfr  return abfd->xvec;
239178825Sdfr}
240233294Sstas
241178825Sdfrchar *
242178825Sdfrtrad_unix_core_file_failing_command (abfd)
243233294Sstas     bfd *abfd;
244233294Sstas{
245233294Sstas#ifndef NO_CORE_COMMAND
246233294Sstas  char *com = abfd->tdata.trad_core_data->u.u_comm;
247178825Sdfr  if (*com)
248233294Sstas    return com;
249178825Sdfr  else
250178825Sdfr#endif
251233294Sstas    return 0;
252233294Sstas}
253178825Sdfr
254178825Sdfr/* ARGSUSED */
255178825Sdfrint
256178825Sdfrtrad_unix_core_file_failing_signal (ignore_abfd)
257178825Sdfr     bfd *ignore_abfd ATTRIBUTE_UNUSED;
258178825Sdfr{
259178825Sdfr#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL
260178825Sdfr  return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd);
261178825Sdfr#else
262178825Sdfr  return -1;		/* FIXME, where is it? */
263178825Sdfr#endif
264178825Sdfr}
265178825Sdfr
266178825Sdfr/* ARGSUSED */
267178825Sdfrboolean
268178825Sdfrtrad_unix_core_file_matches_executable_p  (core_bfd, exec_bfd)
269178825Sdfr     bfd *core_bfd ATTRIBUTE_UNUSED;
270233294Sstas     bfd *exec_bfd ATTRIBUTE_UNUSED;
271178825Sdfr{
272233294Sstas  return true;		/* FIXME, We have no way of telling at this point */
273233294Sstas}
274178825Sdfr
275233294Sstas/* If somebody calls any byte-swapping routines, shoot them.  */
276178825Sdfrstatic void
277178825Sdfrswap_abort ()
278178825Sdfr{
279178825Sdfr  abort (); /* This way doesn't require any declaration for ANSI to fuck up */
280178825Sdfr}
281178825Sdfr#define	NO_GET	((bfd_vma (*) PARAMS ((   const bfd_byte *))) swap_abort )
282178825Sdfr#define	NO_PUT	((void    (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort )
283178825Sdfr#define	NO_SIGNED_GET \
284178825Sdfr  ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort )
285178825Sdfr
286178825Sdfrconst bfd_target trad_core_vec =
287178825Sdfr  {
288178825Sdfr    "trad-core",
289178825Sdfr    bfd_target_unknown_flavour,
290178825Sdfr    BFD_ENDIAN_UNKNOWN,		/* target byte order */
291178825Sdfr    BFD_ENDIAN_UNKNOWN,		/* target headers byte order */
292178825Sdfr    (HAS_RELOC | EXEC_P |	/* object flags */
293178825Sdfr     HAS_LINENO | HAS_DEBUG |
294178825Sdfr     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
295178825Sdfr    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
296178825Sdfr    0,			                                   /* symbol prefix */
297178825Sdfr    ' ',						   /* ar_pad_char */
298178825Sdfr    16,							   /* ar_max_namelen */
299178825Sdfr    NO_GET, NO_SIGNED_GET, NO_PUT,	/* 64 bit data */
300178825Sdfr    NO_GET, NO_SIGNED_GET, NO_PUT,	/* 32 bit data */
301178825Sdfr    NO_GET, NO_SIGNED_GET, NO_PUT,	/* 16 bit data */
302178825Sdfr    NO_GET, NO_SIGNED_GET, NO_PUT,	/* 64 bit hdrs */
303178825Sdfr    NO_GET, NO_SIGNED_GET, NO_PUT,	/* 32 bit hdrs */
304178825Sdfr    NO_GET, NO_SIGNED_GET, NO_PUT,	/* 16 bit hdrs */
305178825Sdfr
306178825Sdfr    {				/* bfd_check_format */
307178825Sdfr     _bfd_dummy_target,		/* unknown format */
308178825Sdfr     _bfd_dummy_target,		/* object file */
309178825Sdfr     _bfd_dummy_target,		/* archive */
310178825Sdfr     trad_unix_core_file_p	/* a core file */
311178825Sdfr    },
312178825Sdfr    {				/* bfd_set_format */
313178825Sdfr     bfd_false, bfd_false,
314178825Sdfr     bfd_false, bfd_false
315178825Sdfr    },
316233294Sstas    {				/* bfd_write_contents */
317178825Sdfr     bfd_false, bfd_false,
318178825Sdfr     bfd_false, bfd_false
319233294Sstas    },
320178825Sdfr
321178825Sdfr       BFD_JUMP_TABLE_GENERIC (_bfd_generic),
322233294Sstas       BFD_JUMP_TABLE_COPY (_bfd_generic),
323233294Sstas       BFD_JUMP_TABLE_CORE (trad_unix),
324233294Sstas       BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
325178825Sdfr       BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
326178825Sdfr       BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
327178825Sdfr       BFD_JUMP_TABLE_WRITE (_bfd_generic),
328178825Sdfr       BFD_JUMP_TABLE_LINK (_bfd_nolink),
329233294Sstas       BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
330178825Sdfr
331178825Sdfr    NULL,
332178825Sdfr
333178825Sdfr    (PTR) 0			/* backend_data */
334178825Sdfr};
335178825Sdfr