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