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