1/* BFD back end for SCO5 core files (U-area and raw sections)
2   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22#include "bfd.h"
23#include "sysdep.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#include <sys/paccess.h>
35#include <sys/region.h>
36
37struct sco5_core_struct
38{
39  struct user u;
40};
41
42/* forward declarations */
43
44static asection *make_bfd_asection
45  PARAMS ((bfd *, const char *, flagword, bfd_size_type, bfd_vma, file_ptr));
46static struct user *read_uarea PARAMS ((bfd *, int));
47const bfd_target *sco5_core_file_p PARAMS ((bfd *abfd));
48char *sco5_core_file_failing_command PARAMS ((bfd *abfd));
49int sco5_core_file_failing_signal PARAMS ((bfd *abfd));
50bfd_boolean sco5_core_file_matches_executable_p
51  PARAMS ((bfd *core_bfd, bfd *exec_bfd));
52static void swap_abort PARAMS ((void));
53
54static asection *
55make_bfd_asection (abfd, name, flags, size, vma, filepos)
56     bfd *abfd;
57     const char *name;
58     flagword flags;
59     bfd_size_type size;
60     bfd_vma vma;
61     file_ptr filepos;
62{
63  asection *asect;
64
65  asect = bfd_make_section_anyway (abfd, name);
66  if (!asect)
67    return NULL;
68  asect->flags = flags;
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    FILE *stream = bfd_cache_lookup (abfd);
130    struct stat statbuf;
131
132    if (fstat (fileno (stream), &statbuf) < 0)
133      {
134	bfd_set_error (bfd_error_system_call);
135	return NULL;
136      }
137    coresize = statbuf.st_size;
138  }
139  /* Last long in core is sizeof struct coreoffsets, read it */
140  if ((bfd_seek (abfd, (file_ptr) (coresize - sizeof coffset_siz),
141		 SEEK_SET) != 0)
142      || bfd_bread ((void *) &coffset_siz, (bfd_size_type) sizeof coffset_siz,
143		   abfd) != sizeof coffset_siz)
144    {
145      bfd_set_error (bfd_error_wrong_format);
146      return NULL;
147    }
148
149  /* Use it to seek start of coreoffsets region, read it and determine
150     validity */
151  if ((bfd_seek (abfd, (file_ptr) (coresize - coffset_siz), SEEK_SET) != 0)
152      || (bfd_bread ((void *) &coffsets, (bfd_size_type) sizeof coffsets, abfd)
153	  != sizeof coffsets)
154      || ((coffsets.u_info != 1) && (coffsets.u_info != C_VERSION)))
155    {
156      bfd_set_error (bfd_error_wrong_format);
157      return NULL;
158    }
159
160  if (coffsets.u_info == 1)
161    {
162      /* Old version, no section heads, read info from user struct */
163
164      u = read_uarea (abfd, coffsets.u_user);
165      if (! u)
166	goto fail;
167
168      if (!make_bfd_asection (abfd, ".reg", SEC_HAS_CONTENTS,
169			      (bfd_size_type) coffsets.u_usize,
170			      0 - (bfd_vma) u->u_ar0,
171			      (file_ptr) coffsets.u_user))
172	goto fail;
173
174      if (!make_bfd_asection (abfd, ".data",
175			      SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
176			      ((bfd_size_type) u->u_exdata.ux_dsize
177			       + u->u_exdata.ux_bsize),
178			      (bfd_vma) u->u_exdata.ux_datorg,
179			      (file_ptr) coffsets.u_data))
180	goto fail;
181
182      if (!make_bfd_asection (abfd, ".stack",
183			      SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
184			      (bfd_size_type) u->u_ssize * NBPC,
185			      (bfd_vma) u->u_sub,
186			      (file_ptr) coffsets.u_stack))
187	goto fail;
188
189      return abfd->xvec;		/* Done for version 1 */
190    }
191
192  /* Immediately before coreoffsets region is a long with offset in core
193     to first coresecthead (CORES_OFFSETS), the long before this is the
194     number of section heads in the list. Read both longs and read the
195     coresecthead and check its validity */
196
197  if ((bfd_seek (abfd,
198		 (file_ptr) (coresize - coffset_siz - 2 * sizeof coffset_siz),
199		 SEEK_SET) != 0)
200      || (bfd_bread ((void *) &nsecs, (bfd_size_type) sizeof nsecs, abfd)
201	  != sizeof nsecs)
202      || (bfd_bread ((void *) &cheadoffs, (bfd_size_type) sizeof cheadoffs,
203		    abfd) != sizeof cheadoffs)
204      || (bfd_seek (abfd, (file_ptr) cheadoffs, SEEK_SET) != 0)
205      || (bfd_bread ((void *) &chead, (bfd_size_type) sizeof chead, abfd)
206	  != sizeof chead)
207      || (chead.cs_stype != CORES_OFFSETS)
208      || (chead.cs_x.csx_magic != COREMAGIC_NUMBER))
209    {
210      bfd_set_error (bfd_error_wrong_format);
211      goto fail;
212    }
213
214  /* OK, we believe you.  You're a core file (sure, sure).  */
215
216  /* Now loop over all regions and map them */
217  nsecs--;				/* We've seen CORES_OFFSETS already */
218  for (; nsecs; nsecs--)
219    {
220      if ((bfd_seek (abfd, (file_ptr) chead.cs_hseek, SEEK_SET) != 0)
221	  || (bfd_bread ((void *) &chead, (bfd_size_type) sizeof chead, abfd)
222	      != sizeof chead))
223	{
224	  bfd_set_error (bfd_error_wrong_format);
225	  goto fail;
226	}
227
228      switch (chead.cs_stype)
229	{
230	case CORES_MAGIC:			/* Core header, check magic */
231	  if (chead.cs_x.csx_magic != COREMAGIC_NUMBER)
232	    {
233	      bfd_set_error (bfd_error_wrong_format);
234	      goto fail;
235	    }
236	  secname = NULL;
237	  nsecs++;				/* MAGIC not in section cnt!*/
238	  break;
239	case CORES_UAREA:			/* U-area, read in tdata */
240	  u = read_uarea (abfd, chead.cs_sseek);
241	  if (! u)
242	    goto fail;
243
244	  /* This is tricky.  As the "register section", we give them
245	     the entire upage and stack.  u.u_ar0 points to where
246	     "register 0" is stored.  There are two tricks with this,
247	     though.  One is that the rest of the registers might be
248	     at positive or negative (or both) displacements from
249	     *u_ar0.  The other is that u_ar0 is sometimes an absolute
250	     address in kernel memory, and on other systems it is an
251	     offset from the beginning of the `struct user'.
252
253	     As a practical matter, we don't know where the registers
254	     actually are, so we have to pass the whole area to GDB.
255	     We encode the value of u_ar0 by setting the .regs section
256	     up so that its virtual memory address 0 is at the place
257	     pointed to by u_ar0 (by setting the vma of the start of
258	     the section to -u_ar0).  GDB uses this info to locate the
259	     regs, using minor trickery to get around the
260	     offset-or-absolute-addr problem.  */
261
262	  chead.cs_vaddr = 0 - (bfd_vma) u->u_ar0;
263
264	  secname = ".reg";
265	  flags = SEC_HAS_CONTENTS;
266
267	  break;
268	case CORES_PREGION:			/* A program region, map it */
269	  switch (chead.cs_x.csx_preg.csxp_rtyp)
270	    {
271	    case PT_DATA:
272	      secname = ".data";	/* Data region.		 */
273	      break;
274	    case PT_STACK:
275	      secname = ".stack";	/* Stack region.	 */
276	      break;
277	    case PT_SHMEM:
278	      secname = ".shmem";	/* Shared memory	 */
279	      break;
280	    case PT_LIBDAT:
281	      secname = ".libdat";	/* Shared library data	 */
282	      break;
283	    case PT_V86:
284	      secname = ".virt86";	/* Virtual 8086 mode	 */
285	      break;
286	    case PT_SHFIL:
287	      secname = ".mmfile";	/* Memory mapped file	 */
288	      break;
289	    case PT_XDATA0:
290	      secname = ".Xdat0";	/* XENIX data region, virtual 0 */
291	      break;
292	    default:
293	      secname = "";
294	    }
295	  flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS;
296	  break;
297	case CORES_PROC:			/* struct proc */
298	case CORES_ITIMER:			/* interval timers */
299	case CORES_SCOUTSNAME:			/* struct scoutsname */
300	  secname = NULL;	/* Ignore these */
301	  break;
302	default:
303	  (*_bfd_error_handler) ("Unhandled SCO core file section type %d\n",
304				 chead.cs_stype);
305	  continue;
306	}
307
308      if (secname
309	  && !make_bfd_asection (abfd, secname, flags,
310				 (bfd_size_type) chead.cs_vsize,
311				 (bfd_vma) chead.cs_vaddr,
312				 (file_ptr) chead.cs_sseek))
313	goto fail;
314
315    }
316
317  return abfd->xvec;
318
319 fail:
320  if (abfd->tdata.any)
321    {
322      bfd_release (abfd, abfd->tdata.any);
323      abfd->tdata.any = NULL;
324    }
325  bfd_section_list_clear (abfd);
326  return NULL;
327}
328
329char *
330sco5_core_file_failing_command (abfd)
331     bfd *abfd;
332{
333  char *com = abfd->tdata.sco5_core_data->u.u_comm;
334  if (*com)
335    return com;
336  else
337    return NULL;
338}
339
340int
341sco5_core_file_failing_signal (ignore_abfd)
342     bfd *ignore_abfd;
343{
344  return ((ignore_abfd->tdata.sco5_core_data->u.u_sysabort != 0)
345	  ? ignore_abfd->tdata.sco5_core_data->u.u_sysabort
346	  : -1);
347}
348
349bfd_boolean
350sco5_core_file_matches_executable_p  (core_bfd, exec_bfd)
351     bfd *core_bfd ATTRIBUTE_UNUSED;
352     bfd *exec_bfd ATTRIBUTE_UNUSED;
353{
354  return TRUE;		/* FIXME, We have no way of telling at this point */
355}
356
357/* If somebody calls any byte-swapping routines, shoot them.  */
358static void
359swap_abort ()
360{
361  abort (); /* This way doesn't require any declaration for ANSI to fuck up */
362}
363
364#define	NO_GET ((bfd_vma (*) (const void *)) swap_abort)
365#define	NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
366#define	NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
367#define	NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
368#define	NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
369#define	NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
370
371const bfd_target sco5_core_vec =
372  {
373    "sco5-core",
374    bfd_target_unknown_flavour,
375    BFD_ENDIAN_LITTLE,	       /* target byte order */
376    BFD_ENDIAN_LITTLE,	       /* target headers byte order */
377    (HAS_RELOC | EXEC_P |	/* object flags */
378     HAS_LINENO | HAS_DEBUG |
379     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
380    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
381    0,							   /* symbol prefix */
382    ' ',						   /* ar_pad_char */
383    16,							   /* ar_max_namelen */
384    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit data */
385    NO_GET, NO_GETS, NO_PUT,		/* 32 bit data */
386    NO_GET, NO_GETS, NO_PUT,		/* 16 bit data */
387    NO_GET64, NO_GETS64, NO_PUT64,	/* 64 bit hdrs */
388    NO_GET, NO_GETS, NO_PUT,		/* 32 bit hdrs */
389    NO_GET, NO_GETS, NO_PUT,		/* 16 bit hdrs */
390
391    {				/* bfd_check_format */
392      _bfd_dummy_target,		/* unknown format */
393      _bfd_dummy_target,		/* object file */
394      _bfd_dummy_target,		/* archive */
395      sco5_core_file_p			/* a core file */
396    },
397    {				/* bfd_set_format */
398      bfd_false, bfd_false,
399      bfd_false, bfd_false
400    },
401    {				/* bfd_write_contents */
402      bfd_false, bfd_false,
403      bfd_false, bfd_false
404    },
405
406    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
407    BFD_JUMP_TABLE_COPY (_bfd_generic),
408    BFD_JUMP_TABLE_CORE (sco5),
409    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
410    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
411    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
412    BFD_JUMP_TABLE_WRITE (_bfd_generic),
413    BFD_JUMP_TABLE_LINK (_bfd_nolink),
414    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
415
416    NULL,
417
418    (PTR) 0			/* backend_data */
419  };
420