1/* BFD back end for NetBSD style core files
2   Copyright 1988, 1989, 1991, 1992, 1993, 1996, 1998, 1999, 2000, 2001,
3   2002, 2003, 2004
4   Free Software Foundation, Inc.
5   Written by Paul Kranenburg, EUR
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#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#include <sys/dir.h>
30#include <signal.h>
31#include <sys/core.h>
32
33/* The machine ID for OpenBSD/sparc64 and older versions of
34   NetBSD/sparc64 overlaps with M_MIPS1.  */
35#define M_SPARC64_OPENBSD	M_MIPS1
36
37/* Offset of StackGhost cookie within `struct md_coredump' on
38   OpenBSD/sparc.  */
39#define CORE_WCOOKIE_OFFSET	344
40
41struct netbsd_core_struct
42{
43  struct core core;
44} *rawptr;
45
46/* Forward declarations.  */
47
48static const bfd_target *netbsd_core_file_p
49  PARAMS ((bfd *abfd));
50static char *netbsd_core_file_failing_command
51  PARAMS ((bfd *abfd));
52static int netbsd_core_file_failing_signal
53  PARAMS ((bfd *abfd));
54static bfd_boolean netbsd_core_file_matches_executable_p
55  PARAMS ((bfd *core_bfd, bfd *exec_bfd));
56static void swap_abort
57  PARAMS ((void));
58
59/* Handle NetBSD-style core dump file.  */
60
61static const bfd_target *
62netbsd_core_file_p (abfd)
63     bfd *abfd;
64
65{
66  int i, val;
67  file_ptr offset;
68  asection *asect;
69  struct core core;
70  struct coreseg coreseg;
71  bfd_size_type amt = sizeof core;
72
73  val = bfd_bread ((void *) &core, amt, abfd);
74  if (val != sizeof core)
75    {
76      /* Too small to be a core file.  */
77      bfd_set_error (bfd_error_wrong_format);
78      return 0;
79    }
80
81  if (CORE_GETMAGIC (core) != COREMAGIC)
82    {
83      bfd_set_error (bfd_error_wrong_format);
84      return 0;
85    }
86
87  amt = sizeof (struct netbsd_core_struct);
88  rawptr = (struct netbsd_core_struct *) bfd_zalloc (abfd, amt);
89  if (rawptr == NULL)
90    return 0;
91
92  rawptr->core = core;
93  abfd->tdata.netbsd_core_data = rawptr;
94
95  offset = core.c_hdrsize;
96  for (i = 0; i < core.c_nseg; i++)
97    {
98      const char *sname;
99      flagword flags;
100
101      if (bfd_seek (abfd, offset, SEEK_SET) != 0)
102	goto punt;
103
104      val = bfd_bread ((void *) &coreseg, (bfd_size_type) sizeof coreseg, abfd);
105      if (val != sizeof coreseg)
106	{
107	  bfd_set_error (bfd_error_file_truncated);
108	  goto punt;
109	}
110      if (CORE_GETMAGIC (coreseg) != CORESEGMAGIC)
111	{
112	  bfd_set_error (bfd_error_wrong_format);
113	  goto punt;
114	}
115
116      offset += core.c_seghdrsize;
117
118      switch (CORE_GETFLAG (coreseg))
119	{
120	case CORE_CPU:
121	  sname = ".reg";
122	  flags = SEC_ALLOC + SEC_HAS_CONTENTS;
123	  break;
124	case CORE_DATA:
125	  sname = ".data";
126	  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
127	  break;
128	case CORE_STACK:
129	  sname = ".stack";
130	  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
131	  break;
132	default:
133	  sname = ".unknown";
134	  flags = SEC_ALLOC + SEC_HAS_CONTENTS;
135	  break;
136	}
137      asect = bfd_make_section_anyway (abfd, sname);
138      if (asect == NULL)
139	goto punt;
140
141      asect->flags = flags;
142      asect->size = coreseg.c_size;
143      asect->vma = coreseg.c_addr;
144      asect->filepos = offset;
145      asect->alignment_power = 2;
146
147      if (CORE_GETMID (core) == M_SPARC_NETBSD
148	  && CORE_GETFLAG (coreseg) == CORE_CPU
149	  && coreseg.c_size > CORE_WCOOKIE_OFFSET)
150	{
151	  /* Truncate the .reg section.  */
152	  asect->size = CORE_WCOOKIE_OFFSET;
153
154	  /* And create the .wcookie section.  */
155	  asect = bfd_make_section_anyway (abfd, ".wcookie");
156	  if (asect == NULL)
157	    goto punt;
158
159	  asect->flags = SEC_ALLOC + SEC_HAS_CONTENTS;
160	  asect->size = 4;
161	  asect->vma = 0;
162	  asect->filepos = offset + CORE_WCOOKIE_OFFSET;
163	  asect->alignment_power = 2;
164	}
165
166      offset += coreseg.c_size;
167    }
168
169  /* Set architecture from machine ID.  */
170  switch (CORE_GETMID (core))
171    {
172    case M_ALPHA_NETBSD:
173      bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0);
174      break;
175
176    case M_ARM6_NETBSD:
177      bfd_default_set_arch_mach (abfd, bfd_arch_arm, bfd_mach_arm_3);
178      break;
179
180    case M_X86_64_NETBSD:
181      bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64);
182      break;
183
184    case M_386_NETBSD:
185      bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i386);
186      break;
187
188    case M_68K_NETBSD:
189    case M_68K4K_NETBSD:
190      bfd_default_set_arch_mach (abfd, bfd_arch_m68k, 0);
191      break;
192
193    case M_88K_OPENBSD:
194      bfd_default_set_arch_mach (abfd, bfd_arch_m88k, 0);
195      break;
196
197    case M_HPPA_OPENBSD:
198      bfd_default_set_arch_mach (abfd, bfd_arch_hppa, bfd_mach_hppa11);
199      break;
200
201    case M_POWERPC_NETBSD:
202      bfd_default_set_arch_mach (abfd, bfd_arch_powerpc, bfd_mach_ppc);
203      break;
204
205    case M_SPARC_NETBSD:
206      bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc);
207      break;
208
209    case M_SPARC64_NETBSD:
210    case M_SPARC64_OPENBSD:
211      bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc_v9);
212      break;
213
214    case M_VAX_NETBSD:
215    case M_VAX4K_NETBSD:
216      bfd_default_set_arch_mach (abfd, bfd_arch_vax, 0);
217      break;
218    }
219
220  /* OK, we believe you.  You're a core file (sure, sure).  */
221  return abfd->xvec;
222
223 punt:
224  bfd_release (abfd, abfd->tdata.any);
225  abfd->tdata.any = NULL;
226  bfd_section_list_clear (abfd);
227  return 0;
228}
229
230static char*
231netbsd_core_file_failing_command (abfd)
232	bfd *abfd;
233{
234 /*return core_command (abfd);*/
235  return abfd->tdata.netbsd_core_data->core.c_name;
236}
237
238static int
239netbsd_core_file_failing_signal (abfd)
240	bfd *abfd;
241{
242  /*return core_signal (abfd);*/
243  return abfd->tdata.netbsd_core_data->core.c_signo;
244}
245
246static bfd_boolean
247netbsd_core_file_matches_executable_p  (core_bfd, exec_bfd)
248     bfd *core_bfd ATTRIBUTE_UNUSED;
249     bfd *exec_bfd ATTRIBUTE_UNUSED;
250{
251  /* FIXME, We have no way of telling at this point.  */
252  return TRUE;
253}
254
255/* If somebody calls any byte-swapping routines, shoot them.  */
256
257static void
258swap_abort ()
259{
260 /* This way doesn't require any declaration for ANSI to fuck up.  */
261  abort ();
262}
263
264#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
265#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
266#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
267#define	NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
268#define	NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
269#define	NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
270
271const bfd_target netbsd_core_vec =
272  {
273    "netbsd-core",
274    bfd_target_unknown_flavour,
275    BFD_ENDIAN_UNKNOWN,		/* Target byte order.  */
276    BFD_ENDIAN_UNKNOWN,		/* Target headers byte order.  */
277    (HAS_RELOC | EXEC_P |	/* Object flags.  */
278     HAS_LINENO | HAS_DEBUG |
279     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
280    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags.  */
281    0,			                                   /* Symbol prefix.  */
282    ' ',						   /* ar_pad_char.  */
283    16,							   /* ar_max_namelen.  */
284    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data.  */
285    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data.  */
286    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data.  */
287    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs.  */
288    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs.  */
289    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs.  */
290
291    {					/* bfd_check_format.  */
292      _bfd_dummy_target,		/* Unknown format.  */
293      _bfd_dummy_target,		/* Object file.  */
294      _bfd_dummy_target,		/* Archive.  */
295      netbsd_core_file_p		/* A core file.  */
296    },
297    {					/* bfd_set_format.  */
298      bfd_false, bfd_false,
299      bfd_false, bfd_false
300    },
301    {					/* bfd_write_contents.  */
302      bfd_false, bfd_false,
303      bfd_false, bfd_false
304    },
305
306    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
307    BFD_JUMP_TABLE_COPY (_bfd_generic),
308    BFD_JUMP_TABLE_CORE (netbsd),
309    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
310    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
311    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
312    BFD_JUMP_TABLE_WRITE (_bfd_generic),
313    BFD_JUMP_TABLE_LINK (_bfd_nolink),
314    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
315
316    NULL,
317
318    (PTR) 0			        /* Backend_data.  */
319  };
320