1/* BFD back end for Lynx core files
2   Copyright 1993, 1994, 1995, 2001, 2002, 2004, 2005, 2006, 2007
3   Free Software Foundation, Inc.
4   Written by Stu Grossman of Cygnus Support.
5
6   This file is part of BFD, the Binary File Descriptor library.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21   MA 02110-1301, USA.  */
22
23#include "sysdep.h"
24#include "bfd.h"
25#include "libbfd.h"
26
27#ifdef LYNX_CORE
28
29#include <sys/conf.h>
30#include <sys/kernel.h>
31/* sys/kernel.h should define this, but doesn't always, sigh.  */
32#ifndef __LYNXOS
33#define __LYNXOS
34#endif
35#include <sys/mem.h>
36#include <sys/signal.h>
37#include <sys/time.h>
38#include <sys/resource.h>
39#include <sys/itimer.h>
40#include <sys/file.h>
41#include <sys/proc.h>
42
43/* These are stored in the bfd's tdata */
44
45struct lynx_core_struct
46{
47  int sig;
48  char cmd[PNMLEN + 1];
49};
50
51#define core_hdr(bfd) ((bfd)->tdata.lynx_core_data)
52#define core_signal(bfd) (core_hdr(bfd)->sig)
53#define core_command(bfd) (core_hdr(bfd)->cmd)
54
55#define lynx_core_file_matches_executable_p generic_core_file_matches_executable_p
56#define lynx_core_file_pid _bfd_nocore_core_file_pid
57
58/* Handle Lynx core dump file.  */
59
60static asection *
61make_bfd_asection (abfd, name, flags, size, vma, filepos)
62     bfd *abfd;
63     const char *name;
64     flagword flags;
65     bfd_size_type size;
66     bfd_vma vma;
67     file_ptr filepos;
68{
69  asection *asect;
70  char *newname;
71
72  newname = bfd_alloc (abfd, (bfd_size_type) strlen (name) + 1);
73  if (!newname)
74    return NULL;
75
76  strcpy (newname, name);
77
78  asect = bfd_make_section_with_flags (abfd, newname, flags);
79  if (!asect)
80    return NULL;
81
82  asect->size = size;
83  asect->vma = vma;
84  asect->filepos = filepos;
85  asect->alignment_power = 2;
86
87  return asect;
88}
89
90const bfd_target *
91lynx_core_file_p (abfd)
92     bfd *abfd;
93{
94  int secnum;
95  struct pssentry pss;
96  bfd_size_type tcontext_size;
97  core_st_t *threadp;
98  int pagesize;
99  asection *newsect;
100  bfd_size_type amt;
101
102  pagesize = getpagesize ();	/* Serious cross-target issue here...  This
103				   really needs to come from a system-specific
104				   header file.  */
105
106  /* Get the pss entry from the core file */
107
108  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
109    return NULL;
110
111  amt = sizeof pss;
112  if (bfd_bread ((void *) &pss, amt, abfd) != amt)
113    {
114      /* Too small to be a core file */
115      if (bfd_get_error () != bfd_error_system_call)
116	bfd_set_error (bfd_error_wrong_format);
117      return NULL;
118    }
119
120  amt = sizeof (struct lynx_core_struct);
121  core_hdr (abfd) = (struct lynx_core_struct *) bfd_zalloc (abfd, amt);
122
123  if (!core_hdr (abfd))
124    return NULL;
125
126  strncpy (core_command (abfd), pss.pname, PNMLEN + 1);
127
128  /* Compute the size of the thread contexts */
129
130  tcontext_size = pss.threadcnt * sizeof (core_st_t);
131
132  /* Allocate space for the thread contexts */
133
134  threadp = (core_st_t *) bfd_alloc (abfd, tcontext_size);
135  if (!threadp)
136    goto fail;
137
138  /* Save thread contexts */
139
140  if (bfd_seek (abfd, (file_ptr) pagesize, SEEK_SET) != 0)
141    goto fail;
142
143  if (bfd_bread ((void *) threadp, tcontext_size, abfd) != tcontext_size)
144    {
145      /* Probably too small to be a core file */
146      if (bfd_get_error () != bfd_error_system_call)
147	bfd_set_error (bfd_error_wrong_format);
148      goto fail;
149    }
150
151  core_signal (abfd) = threadp->currsig;
152
153  newsect = make_bfd_asection (abfd, ".stack",
154			       SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
155			       pss.ssize,
156			       pss.slimit,
157			       pagesize + tcontext_size);
158  if (!newsect)
159    goto fail;
160
161  newsect = make_bfd_asection (abfd, ".data",
162			       SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
163			       pss.data_len + pss.bss_len,
164			       pss.data_start,
165			       pagesize + tcontext_size + pss.ssize
166#if defined (SPARC) || defined (__SPARC__)
167			       /* SPARC Lynx seems to start dumping
168                                  the .data section at a page
169                                  boundary.  It's OK to check a
170                                  #define like SPARC here because this
171                                  file can only be compiled on a Lynx
172                                  host.  */
173			       + pss.data_start % pagesize
174#endif
175			       );
176  if (!newsect)
177    goto fail;
178
179/* And, now for the .reg/XXX pseudo sections.  Each thread has it's own
180   .reg/XXX section, where XXX is the thread id (without leading zeros).  The
181   currently running thread (at the time of the core dump) also has an alias
182   called `.reg' (just to keep GDB happy).  Note that we use `.reg/XXX' as
183   opposed to `.regXXX' because GDB expects that .reg2 will be the floating-
184   point registers.  */
185
186  newsect = make_bfd_asection (abfd, ".reg",
187			       SEC_HAS_CONTENTS,
188			       sizeof (core_st_t),
189			       0,
190			       pagesize);
191  if (!newsect)
192    goto fail;
193
194  for (secnum = 0; secnum < pss.threadcnt; secnum++)
195    {
196      char secname[100];
197
198      sprintf (secname, ".reg/%d", BUILDPID (0, threadp[secnum].tid));
199      newsect = make_bfd_asection (abfd, secname,
200				   SEC_HAS_CONTENTS,
201				   sizeof (core_st_t),
202				   0,
203				   pagesize + secnum * sizeof (core_st_t));
204      if (!newsect)
205	goto fail;
206    }
207
208  return abfd->xvec;
209
210 fail:
211  bfd_release (abfd, core_hdr (abfd));
212  core_hdr (abfd) = NULL;
213  bfd_section_list_clear (abfd);
214  return NULL;
215}
216
217char *
218lynx_core_file_failing_command (abfd)
219     bfd *abfd;
220{
221  return core_command (abfd);
222}
223
224int
225lynx_core_file_failing_signal (abfd)
226     bfd *abfd;
227{
228  return core_signal (abfd);
229}
230
231#endif /* LYNX_CORE */
232