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