1/* BFD back end for SCO5 core files (U-area and raw sections)
2   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3   Free Software Foundation, Inc.
4   Written by Jouke Numan <jnuman@hiscom.nl>
5
6This file is part of BFD, the Binary File Descriptor library.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "libbfd.h"
25#include "libaout.h"		/* BFD a.out internal data structures */
26
27#include <stdio.h>
28#include <sys/types.h>
29#include <sys/param.h>
30#include <sys/dir.h>
31#include <signal.h>
32
33#include <sys/user.h>		/* After a.out.h  */
34#ifdef SCO5_CORE
35#include <sys/paccess.h>
36#include <sys/region.h>
37#endif
38
39struct sco5_core_struct
40{
41  struct user u;
42};
43
44/* forward declarations */
45
46static asection *make_bfd_asection
47  PARAMS ((bfd *, const char *, flagword, bfd_size_type, bfd_vma, file_ptr));
48static struct user *read_uarea PARAMS ((bfd *, int));
49const bfd_target *sco5_core_file_p PARAMS ((bfd *abfd));
50char *sco5_core_file_failing_command PARAMS ((bfd *abfd));
51int sco5_core_file_failing_signal PARAMS ((bfd *abfd));
52#define sco5_core_file_matches_executable_p generic_core_file_matches_executable_p
53static void swap_abort PARAMS ((void));
54
55static asection *
56make_bfd_asection (abfd, name, flags, size, vma, filepos)
57     bfd *abfd;
58     const char *name;
59     flagword flags;
60     bfd_size_type size;
61     bfd_vma vma;
62     file_ptr filepos;
63{
64  asection *asect;
65
66  asect = bfd_make_section_anyway_with_flags (abfd, name, flags);
67  if (!asect)
68    return NULL;
69  asect->size = size;
70  asect->vma = vma;
71  asect->filepos = filepos;
72  asect->alignment_power = 2;
73
74  return asect;
75}
76
77static struct user *
78read_uarea(abfd, filepos)
79     bfd *abfd;
80     int filepos;
81
82{
83  struct sco5_core_struct *rawptr;
84  bfd_size_type amt = sizeof (struct sco5_core_struct);
85
86  rawptr = (struct sco5_core_struct *) bfd_zmalloc (amt);
87  if (rawptr == NULL)
88    return NULL;
89
90  abfd->tdata.sco5_core_data = rawptr;
91
92  if (bfd_seek (abfd, (file_ptr) filepos, SEEK_SET) != 0
93      || bfd_bread ((void *) &rawptr->u, (bfd_size_type) sizeof rawptr->u,
94		   abfd) != sizeof rawptr->u)
95    {
96      bfd_set_error (bfd_error_wrong_format);
97      return NULL;
98    }
99
100  /* Sanity check perhaps??? */
101  if (rawptr->u.u_dsize > 0x1000000)    /* Remember, it's in pages...  */
102    {
103      bfd_set_error (bfd_error_wrong_format);
104      return NULL;
105    }
106  if (rawptr->u.u_ssize > 0x1000000)
107    {
108      bfd_set_error (bfd_error_wrong_format);
109      return NULL;
110    }
111  return &rawptr->u;
112}
113
114const bfd_target *
115sco5_core_file_p (abfd)
116     bfd *abfd;
117{
118  int coffset_siz, val, nsecs, cheadoffs;
119  int coresize;
120  struct user *u;
121  struct coreoffsets coffsets;
122  struct coresecthead chead;
123  char *secname;
124  flagword flags;
125
126  /* Read coreoffsets region at end of core (see core(FP)).  */
127
128  {
129    struct stat statbuf;
130
131    if (bfd_stat (abfd, &statbuf) < 0)
132      return NULL;
133
134    coresize = statbuf.st_size;
135  }
136  /* Last long in core is sizeof struct coreoffsets, read it */
137  if ((bfd_seek (abfd, (file_ptr) (coresize - sizeof coffset_siz),
138		 SEEK_SET) != 0)
139      || bfd_bread ((void *) &coffset_siz, (bfd_size_type) sizeof coffset_siz,
140		   abfd) != sizeof coffset_siz)
141    {
142      bfd_set_error (bfd_error_wrong_format);
143      return NULL;
144    }
145
146  /* Use it to seek start of coreoffsets region, read it and determine
147     validity */
148  if ((bfd_seek (abfd, (file_ptr) (coresize - coffset_siz), SEEK_SET) != 0)
149      || (bfd_bread ((void *) &coffsets, (bfd_size_type) sizeof coffsets, abfd)
150	  != sizeof coffsets)
151      || ((coffsets.u_info != 1) && (coffsets.u_info != C_VERSION)))
152    {
153      bfd_set_error (bfd_error_wrong_format);
154      return NULL;
155    }
156
157  if (coffsets.u_info == 1)
158    {
159      /* Old version, no section heads, read info from user struct */
160
161      u = read_uarea (abfd, coffsets.u_user);
162      if (! u)
163	goto fail;
164
165      if (!make_bfd_asection (abfd, ".reg", SEC_HAS_CONTENTS,
166			      (bfd_size_type) coffsets.u_usize,
167			      0 - (bfd_vma) u->u_ar0,
168			      (file_ptr) coffsets.u_user))
169	goto fail;
170
171      if (!make_bfd_asection (abfd, ".data",
172			      SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
173			      ((bfd_size_type) u->u_exdata.ux_dsize
174			       + u->u_exdata.ux_bsize),
175			      (bfd_vma) u->u_exdata.ux_datorg,
176			      (file_ptr) coffsets.u_data))
177	goto fail;
178
179      if (!make_bfd_asection (abfd, ".stack",
180			      SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
181			      (bfd_size_type) u->u_ssize * NBPC,
182			      (bfd_vma) u->u_sub,
183			      (file_ptr) coffsets.u_stack))
184	goto fail;
185
186      return abfd->xvec;		/* Done for version 1 */
187    }
188
189  /* Immediately before coreoffsets region is a long with offset in core
190     to first coresecthead (CORES_OFFSETS), the long before this is the
191     number of section heads in the list. Read both longs and read the
192     coresecthead and check its validity */
193
194  if ((bfd_seek (abfd,
195		 (file_ptr) (coresize - coffset_siz - 2 * sizeof coffset_siz),
196		 SEEK_SET) != 0)
197      || (bfd_bread ((void *) &nsecs, (bfd_size_type) sizeof nsecs, abfd)
198	  != sizeof nsecs)
199      || (bfd_bread ((void *) &cheadoffs, (bfd_size_type) sizeof cheadoffs,
200		    abfd) != sizeof cheadoffs)
201      || (bfd_seek (abfd, (file_ptr) cheadoffs, SEEK_SET) != 0)
202      || (bfd_bread ((void *) &chead, (bfd_size_type) sizeof chead, abfd)
203	  != sizeof chead)
204      || (chead.cs_stype != CORES_OFFSETS)
205      || (chead.cs_x.csx_magic != COREMAGIC_NUMBER))
206    {
207      bfd_set_error (bfd_error_wrong_format);
208      goto fail;
209    }
210
211  /* OK, we believe you.  You're a core file (sure, sure).  */
212
213  /* Now loop over all regions and map them */
214  nsecs--;				/* We've seen CORES_OFFSETS already */
215  for (; nsecs; nsecs--)
216    {
217      if ((bfd_seek (abfd, (file_ptr) chead.cs_hseek, SEEK_SET) != 0)
218	  || (bfd_bread ((void *) &chead, (bfd_size_type) sizeof chead, abfd)
219	      != sizeof chead))
220	{
221	  bfd_set_error (bfd_error_wrong_format);
222	  goto fail;
223	}
224
225      switch (chead.cs_stype)
226	{
227	case CORES_MAGIC:			/* Core header, check magic */
228	  if (chead.cs_x.csx_magic != COREMAGIC_NUMBER)
229	    {
230	      bfd_set_error (bfd_error_wrong_format);
231	      goto fail;
232	    }
233	  secname = NULL;
234	  nsecs++;				/* MAGIC not in section cnt!*/
235	  break;
236	case CORES_UAREA:			/* U-area, read in tdata */
237	  u = read_uarea (abfd, chead.cs_sseek);
238	  if (! u)
239	    goto fail;
240
241	  /* This is tricky.  As the "register section", we give them
242	     the entire upage and stack.  u.u_ar0 points to where
243	     "register 0" is stored.  There are two tricks with this,
244	     though.  One is that the rest of the registers might be
245	     at positive or negative (or both) displacements from
246	     *u_ar0.  The other is that u_ar0 is sometimes an absolute
247	     address in kernel memory, and on other systems it is an
248	     offset from the beginning of the `struct user'.
249
250	     As a practical matter, we don't know where the registers
251	     actually are, so we have to pass the whole area to GDB.
252	     We encode the value of u_ar0 by setting the .regs section
253	     up so that its virtual memory address 0 is at the place
254	     pointed to by u_ar0 (by setting the vma of the start of
255	     the section to -u_ar0).  GDB uses this info to locate the
256	     regs, using minor trickery to get around the
257	     offset-or-absolute-addr problem.  */
258
259	  chead.cs_vaddr = 0 - (bfd_vma) u->u_ar0;
260
261	  secname = ".reg";
262	  flags = SEC_HAS_CONTENTS;
263
264	  break;
265	case CORES_PREGION:			/* A program region, map it */
266	  switch (chead.cs_x.csx_preg.csxp_rtyp)
267	    {
268	    case PT_DATA:
269	      secname = ".data";	/* Data region.		 */
270	      break;
271	    case PT_STACK:
272	      secname = ".stack";	/* Stack region.	 */
273	      break;
274	    case PT_SHMEM:
275	      secname = ".shmem";	/* Shared memory	 */
276	      break;
277	    case PT_LIBDAT:
278	      secname = ".libdat";	/* Shared library data	 */
279	      break;
280	    case PT_V86:
281	      secname = ".virt86";	/* Virtual 8086 mode	 */
282	      break;
283	    case PT_SHFIL:
284	      secname = ".mmfile";	/* Memory mapped file	 */
285	      break;
286	    case PT_XDATA0:
287	      secname = ".Xdat0";	/* XENIX data region, virtual 0 */
288	      break;
289	    default:
290	      secname = "";
291	    }
292	  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
293	  break;
294	case CORES_PROC:			/* struct proc */
295	case CORES_ITIMER:			/* interval timers */
296	case CORES_SCOUTSNAME:			/* struct scoutsname */
297	  secname = NULL;	/* Ignore these */
298	  break;
299	default:
300	  (*_bfd_error_handler) ("Unhandled SCO core file section type %d\n",
301				 chead.cs_stype);
302	  continue;
303	}
304
305      if (secname
306	  && !make_bfd_asection (abfd, secname, flags,
307				 (bfd_size_type) chead.cs_vsize,
308				 (bfd_vma) chead.cs_vaddr,
309				 (file_ptr) chead.cs_sseek))
310	goto fail;
311
312    }
313
314  return abfd->xvec;
315
316 fail:
317  if (abfd->tdata.any)
318    {
319      bfd_release (abfd, abfd->tdata.any);
320      abfd->tdata.any = NULL;
321    }
322  bfd_section_list_clear (abfd);
323  return NULL;
324}
325
326char *
327sco5_core_file_failing_command (abfd)
328     bfd *abfd;
329{
330  char *com = abfd->tdata.sco5_core_data->u.u_comm;
331  if (*com)
332    return com;
333  else
334    return NULL;
335}
336
337int
338sco5_core_file_failing_signal (ignore_abfd)
339     bfd *ignore_abfd;
340{
341  return ((ignore_abfd->tdata.sco5_core_data->u.u_sysabort != 0)
342	  ? ignore_abfd->tdata.sco5_core_data->u.u_sysabort
343	  : -1);
344}
345
346/* If somebody calls any byte-swapping routines, shoot them.  */
347static void
348swap_abort ()
349{
350  abort (); /* This way doesn't require any declaration for ANSI to fuck up */
351}
352
353#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
354#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
355#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
356#define	NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
357#define	NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
358#define	NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
359
360const bfd_target sco5_core_vec =
361  {
362    "sco5-core",
363    bfd_target_unknown_flavour,
364    BFD_ENDIAN_LITTLE,	       /* target byte order */
365    BFD_ENDIAN_LITTLE,	       /* target headers byte order */
366    (HAS_RELOC | EXEC_P |	/* object flags */
367     HAS_LINENO | HAS_DEBUG |
368     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
369    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
370    0,							   /* symbol prefix */
371    ' ',						   /* ar_pad_char */
372    16,							   /* ar_max_namelen */
373    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data */
374    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data */
375    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data */
376    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs */
377    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs */
378    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs */
379
380    {				/* bfd_check_format */
381      _bfd_dummy_target,		/* unknown format */
382      _bfd_dummy_target,		/* object file */
383      _bfd_dummy_target,		/* archive */
384      sco5_core_file_p			/* a core file */
385    },
386    {				/* bfd_set_format */
387      bfd_false, bfd_false,
388      bfd_false, bfd_false
389    },
390    {				/* bfd_write_contents */
391      bfd_false, bfd_false,
392      bfd_false, bfd_false
393    },
394
395    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
396    BFD_JUMP_TABLE_COPY (_bfd_generic),
397    BFD_JUMP_TABLE_CORE (sco5),
398    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
399    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
400    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
401    BFD_JUMP_TABLE_WRITE (_bfd_generic),
402    BFD_JUMP_TABLE_LINK (_bfd_nolink),
403    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
404
405    NULL,
406
407    (PTR) 0			/* backend_data */
408  };
409