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 45 struct 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 60 static asection * 61 make_bfd_asection (bfd *abfd, 62 const char *name, 63 flagword flags, 64 bfd_size_type size, 65 bfd_vma vma, 66 file_ptr filepos) 67 { 68 asection *asect; 69 char *newname; 70 71 newname = bfd_alloc (abfd, (bfd_size_type) strlen (name) + 1); 72 if (!newname) 73 return NULL; 74 75 strcpy (newname, name); 76 77 asect = bfd_make_section_with_flags (abfd, newname, flags); 78 if (!asect) 79 return NULL; 80 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 (bfd *abfd) 91 { 92 int secnum; 93 struct pssentry pss; 94 bfd_size_type tcontext_size; 95 core_st_t *threadp; 96 int pagesize; 97 asection *newsect; 98 bfd_size_type amt; 99 100 pagesize = getpagesize (); /* Serious cross-target issue here... This 101 really needs to come from a system-specific 102 header file. */ 103 104 /* Get the pss entry from the core file */ 105 106 if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) 107 return NULL; 108 109 amt = sizeof pss; 110 if (bfd_bread ((void *) &pss, amt, abfd) != amt) 111 { 112 /* Too small to be a core file */ 113 if (bfd_get_error () != bfd_error_system_call) 114 bfd_set_error (bfd_error_wrong_format); 115 return NULL; 116 } 117 118 amt = sizeof (struct lynx_core_struct); 119 core_hdr (abfd) = (struct lynx_core_struct *) bfd_zalloc (abfd, amt); 120 121 if (!core_hdr (abfd)) 122 return NULL; 123 124 strncpy (core_command (abfd), pss.pname, PNMLEN + 1); 125 126 /* Compute the size of the thread contexts */ 127 128 tcontext_size = pss.threadcnt * sizeof (core_st_t); 129 130 /* Allocate space for the thread contexts */ 131 132 threadp = (core_st_t *) bfd_alloc (abfd, tcontext_size); 133 if (!threadp) 134 goto fail; 135 136 /* Save thread contexts */ 137 138 if (bfd_seek (abfd, (file_ptr) pagesize, SEEK_SET) != 0) 139 goto fail; 140 141 if (bfd_bread ((void *) threadp, tcontext_size, abfd) != tcontext_size) 142 { 143 /* Probably too small to be a core file */ 144 if (bfd_get_error () != bfd_error_system_call) 145 bfd_set_error (bfd_error_wrong_format); 146 goto fail; 147 } 148 149 core_signal (abfd) = threadp->currsig; 150 151 newsect = make_bfd_asection (abfd, ".stack", 152 SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS, 153 pss.ssize, 154 pss.slimit, 155 pagesize + tcontext_size); 156 if (!newsect) 157 goto fail; 158 159 newsect = make_bfd_asection (abfd, ".data", 160 SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS, 161 pss.data_len + pss.bss_len, 162 pss.data_start, 163 pagesize + tcontext_size + pss.ssize 164 #if defined (SPARC) || defined (__SPARC__) 165 /* SPARC Lynx seems to start dumping 166 the .data section at a page 167 boundary. It's OK to check a 168 #define like SPARC here because this 169 file can only be compiled on a Lynx 170 host. */ 171 + pss.data_start % pagesize 172 #endif 173 ); 174 if (!newsect) 175 goto fail; 176 177 /* And, now for the .reg/XXX pseudo sections. Each thread has it's own 178 .reg/XXX section, where XXX is the thread id (without leading zeros). The 179 currently running thread (at the time of the core dump) also has an alias 180 called `.reg' (just to keep GDB happy). Note that we use `.reg/XXX' as 181 opposed to `.regXXX' because GDB expects that .reg2 will be the floating- 182 point registers. */ 183 184 newsect = make_bfd_asection (abfd, ".reg", 185 SEC_HAS_CONTENTS, 186 sizeof (core_st_t), 187 0, 188 pagesize); 189 if (!newsect) 190 goto fail; 191 192 for (secnum = 0; secnum < pss.threadcnt; secnum++) 193 { 194 char secname[100]; 195 196 sprintf (secname, ".reg/%d", BUILDPID (0, threadp[secnum].tid)); 197 newsect = make_bfd_asection (abfd, secname, 198 SEC_HAS_CONTENTS, 199 sizeof (core_st_t), 200 0, 201 pagesize + secnum * sizeof (core_st_t)); 202 if (!newsect) 203 goto fail; 204 } 205 206 return abfd->xvec; 207 208 fail: 209 bfd_release (abfd, core_hdr (abfd)); 210 core_hdr (abfd) = NULL; 211 bfd_section_list_clear (abfd); 212 return NULL; 213 } 214 215 char * 216 lynx_core_file_failing_command (bfd *abfd) 217 { 218 return core_command (abfd); 219 } 220 221 int 222 lynx_core_file_failing_signal (bfd *abfd) 223 { 224 return core_signal (abfd); 225 } 226 227 #endif /* LYNX_CORE */ 228