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