1/* BFD back-end for Irix core files.
2   Copyright 1993, 1994, 1996, 1999, 2001, 2002, 2004
3   Free Software Foundation, Inc.
4   Written by Stu Grossman, Cygnus Support.
5   Converted to back-end form by Ian Lance Taylor, Cygnus Support
6
7   This file is part of BFD, the Binary File Descriptor library.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
22
23/* This file can only be compiled on systems which use Irix style core
24   files (namely, Irix 4 and Irix 5, so far).  */
25
26#include "bfd.h"
27#include "sysdep.h"
28#include "libbfd.h"
29
30#ifdef IRIX_CORE
31
32#include <core.out.h>
33
34struct sgi_core_struct
35{
36  int sig;
37  char cmd[CORE_NAMESIZE];
38};
39
40#define core_hdr(bfd) ((bfd)->tdata.sgi_core_data)
41#define core_signal(bfd) (core_hdr(bfd)->sig)
42#define core_command(bfd) (core_hdr(bfd)->cmd)
43
44static asection *make_bfd_asection
45  PARAMS ((bfd *, const char *, flagword, bfd_size_type, bfd_vma, file_ptr));
46static const bfd_target *irix_core_core_file_p
47  PARAMS ((bfd *));
48static char *irix_core_core_file_failing_command
49  PARAMS ((bfd *));
50static int irix_core_core_file_failing_signal
51  PARAMS ((bfd *));
52static bfd_boolean irix_core_core_file_matches_executable_p
53  PARAMS ((bfd *, bfd *));
54static void swap_abort
55  PARAMS ((void));
56#ifdef CORE_MAGIC64
57static int do_sections64
58  PARAMS ((bfd *, struct coreout *));
59#endif
60static int do_sections
61  PARAMS ((bfd *, struct coreout *));
62
63/* Helper function for irix_core_core_file_p:
64   32-bit and 64-bit versions.  */
65
66#ifdef CORE_MAGIC64
67static int
68do_sections64 (abfd, coreout)
69     bfd * abfd;
70     struct coreout * coreout;
71{
72  struct vmap64 vmap;
73  char *secname;
74  int i, val;
75
76  for (i = 0; i < coreout->c_nvmap; i++)
77    {
78      val = bfd_bread ((PTR) &vmap, (bfd_size_type) sizeof vmap, abfd);
79      if (val != sizeof vmap)
80	break;
81
82      switch (vmap.v_type)
83	{
84	case VDATA:
85	  secname = ".data";
86	  break;
87	case VSTACK:
88	  secname = ".stack";
89	  break;
90#ifdef VMAPFILE
91	case VMAPFILE:
92	  secname = ".mapfile";
93	  break;
94#endif
95	default:
96	  continue;
97	}
98
99      /* A file offset of zero means that the
100	 section is not contained in the corefile.  */
101      if (vmap.v_offset == 0)
102	continue;
103
104      if (!make_bfd_asection (abfd, secname,
105			      SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS,
106			      vmap.v_len, vmap.v_vaddr, vmap.v_offset))
107	/* Fail.  */
108	return 0;
109    }
110
111  return 1;
112}
113#endif
114
115/* 32-bit version.  */
116
117static int
118do_sections (abfd, coreout)
119     bfd * abfd;
120     struct coreout *coreout;
121{
122  struct vmap vmap;
123  char *secname;
124  int i, val;
125
126  for (i = 0; i < coreout->c_nvmap; i++)
127    {
128      val = bfd_bread ((PTR) &vmap, (bfd_size_type) sizeof vmap, abfd);
129      if (val != sizeof vmap)
130	break;
131
132      switch (vmap.v_type)
133	{
134	case VDATA:
135	  secname = ".data";
136	  break;
137	case VSTACK:
138	  secname = ".stack";
139	  break;
140#ifdef VMAPFILE
141	case VMAPFILE:
142	  secname = ".mapfile";
143	  break;
144#endif
145	default:
146	  continue;
147	}
148
149      /* A file offset of zero means that the
150	 section is not contained in the corefile.  */
151      if (vmap.v_offset == 0)
152	continue;
153
154      if (!make_bfd_asection (abfd, secname,
155			      SEC_ALLOC | SEC_LOAD+SEC_HAS_CONTENTS,
156			      vmap.v_len, vmap.v_vaddr, vmap.v_offset))
157	/* Fail.  */
158	return 0;
159    }
160  return 1;
161}
162
163static asection *
164make_bfd_asection (abfd, name, flags, size, vma, filepos)
165     bfd *abfd;
166     const char *name;
167     flagword flags;
168     bfd_size_type size;
169     bfd_vma vma;
170     file_ptr filepos;
171{
172  asection *asect;
173
174  asect = bfd_make_section_anyway (abfd, name);
175  if (!asect)
176    return NULL;
177
178  asect->flags = flags;
179  asect->size = size;
180  asect->vma = vma;
181  asect->filepos = filepos;
182  asect->alignment_power = 4;
183
184  return asect;
185}
186
187static const bfd_target *
188irix_core_core_file_p (abfd)
189     bfd *abfd;
190{
191  int val;
192  struct coreout coreout;
193  struct idesc *idg, *idf, *ids;
194  bfd_size_type amt;
195
196  val = bfd_bread ((PTR) &coreout, (bfd_size_type) sizeof coreout, abfd);
197  if (val != sizeof coreout)
198    {
199      if (bfd_get_error () != bfd_error_system_call)
200	bfd_set_error (bfd_error_wrong_format);
201      return 0;
202    }
203
204  if (coreout.c_version != CORE_VERSION1)
205    return 0;
206
207  /* Have we got a corefile?  */
208  switch (coreout.c_magic)
209    {
210    case CORE_MAGIC:	break;
211#ifdef CORE_MAGIC64
212    case CORE_MAGIC64:	break;
213#endif
214#ifdef CORE_MAGICN32
215    case CORE_MAGICN32:	break;
216#endif
217    default:		return 0;	/* Un-identifiable or not corefile.  */
218    }
219
220  amt = sizeof (struct sgi_core_struct);
221  core_hdr (abfd) = (struct sgi_core_struct *) bfd_zalloc (abfd, amt);
222  if (!core_hdr (abfd))
223    return NULL;
224
225  strncpy (core_command (abfd), coreout.c_name, CORE_NAMESIZE);
226  core_signal (abfd) = coreout.c_sigcause;
227
228  if (bfd_seek (abfd, coreout.c_vmapoffset, SEEK_SET) != 0)
229    goto fail;
230
231  /* Process corefile sections.  */
232#ifdef CORE_MAGIC64
233  if (coreout.c_magic == (int) CORE_MAGIC64)
234    {
235      if (! do_sections64 (abfd, & coreout))
236	goto fail;
237    }
238  else
239#endif
240    if (! do_sections (abfd, & coreout))
241      goto fail;
242
243  /* Make sure that the regs are contiguous within the core file.  */
244
245  idg = &coreout.c_idesc[I_GPREGS];
246  idf = &coreout.c_idesc[I_FPREGS];
247  ids = &coreout.c_idesc[I_SPECREGS];
248
249  if (idg->i_offset + idg->i_len != idf->i_offset
250      || idf->i_offset + idf->i_len != ids->i_offset)
251    goto fail;			/* Can't deal with non-contig regs */
252
253  if (bfd_seek (abfd, idg->i_offset, SEEK_SET) != 0)
254    goto fail;
255
256  if (!make_bfd_asection (abfd, ".reg",
257			  SEC_HAS_CONTENTS,
258			  idg->i_len + idf->i_len + ids->i_len,
259			  0,
260			  idg->i_offset))
261    goto fail;
262
263  /* OK, we believe you.  You're a core file (sure, sure).  */
264  bfd_default_set_arch_mach (abfd, bfd_arch_mips, 0);
265
266  return abfd->xvec;
267
268 fail:
269  bfd_release (abfd, core_hdr (abfd));
270  core_hdr (abfd) = NULL;
271  bfd_section_list_clear (abfd);
272  return NULL;
273}
274
275static char *
276irix_core_core_file_failing_command (abfd)
277     bfd *abfd;
278{
279  return core_command (abfd);
280}
281
282static int
283irix_core_core_file_failing_signal (abfd)
284     bfd *abfd;
285{
286  return core_signal (abfd);
287}
288
289static bfd_boolean
290irix_core_core_file_matches_executable_p (core_bfd, exec_bfd)
291     bfd *core_bfd, *exec_bfd;
292{
293  return TRUE;			/* XXX - FIXME */
294}
295
296/* If somebody calls any byte-swapping routines, shoot them.  */
297static void
298swap_abort()
299{
300  abort(); /* This way doesn't require any declaration for ANSI to fuck up */
301}
302
303#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
304#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
305#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
306#define	NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
307#define	NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
308#define	NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
309
310const bfd_target irix_core_vec =
311  {
312    "irix-core",
313    bfd_target_unknown_flavour,
314    BFD_ENDIAN_BIG,		/* target byte order */
315    BFD_ENDIAN_BIG,		/* target headers byte order */
316    (HAS_RELOC | EXEC_P |	/* object flags */
317     HAS_LINENO | HAS_DEBUG |
318     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
319    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
320    0,			                                   /* symbol prefix */
321    ' ',						   /* ar_pad_char */
322    16,							   /* ar_max_namelen */
323    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data */
324    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data */
325    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data */
326    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs */
327    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs */
328    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs */
329
330    {				/* bfd_check_format */
331      _bfd_dummy_target,		/* unknown format */
332      _bfd_dummy_target,		/* object file */
333      _bfd_dummy_target,		/* archive */
334      irix_core_core_file_p		/* a core file */
335    },
336    {				/* bfd_set_format */
337      bfd_false, bfd_false,
338      bfd_false, bfd_false
339    },
340    {				/* bfd_write_contents */
341      bfd_false, bfd_false,
342      bfd_false, bfd_false
343    },
344
345    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
346    BFD_JUMP_TABLE_COPY (_bfd_generic),
347    BFD_JUMP_TABLE_CORE (irix_core),
348    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
349    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
350    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
351    BFD_JUMP_TABLE_WRITE (_bfd_generic),
352    BFD_JUMP_TABLE_LINK (_bfd_nolink),
353    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
354
355    NULL,
356
357    (PTR) 0			/* backend_data */
358  };
359
360#endif /* IRIX_CORE */
361