trad-core.c revision 78828
1233294Sstas/* BFD back end for traditional Unix core files (U-area and raw sections) 2178825Sdfr Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 3178825Sdfr 2000 4178825Sdfr Free Software Foundation, Inc. 5233294Sstas Written by John Gilmore of Cygnus Support. 6233294Sstas 7178825SdfrThis file is part of BFD, the Binary File Descriptor library. 8178825Sdfr 9178825SdfrThis program is free software; you can redistribute it and/or modify 10178825Sdfrit under the terms of the GNU General Public License as published by 11178825Sdfrthe Free Software Foundation; either version 2 of the License, or 12178825Sdfr(at your option) any later version. 13178825Sdfr 14178825SdfrThis program is distributed in the hope that it will be useful, 15178825Sdfrbut WITHOUT ANY WARRANTY; without even the implied warranty of 16178825SdfrMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17178825SdfrGNU General Public License for more details. 18233294Sstas 19178825SdfrYou should have received a copy of the GNU General Public License 20233294Sstasalong with this program; if not, write to the Free Software 21178825SdfrFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 22233294Sstas 23178825Sdfr#include "bfd.h" 24178825Sdfr#include "sysdep.h" 25233294Sstas#include "libbfd.h" 26178825Sdfr#include "libaout.h" /* BFD a.out internal data structures */ 27233294Sstas 28178825Sdfr#include <sys/param.h> 29178825Sdfr#ifdef HAVE_DIRENT_H 30178825Sdfr# include <dirent.h> 31178825Sdfr#else 32178825Sdfr# ifdef HAVE_SYS_NDIR_H 33178825Sdfr# include <sys/ndir.h> 34178825Sdfr# endif 35178825Sdfr# ifdef HAVE_SYS_DIR_H 36178825Sdfr# include <sys/dir.h> 37178825Sdfr# endif 38178825Sdfr# ifdef HAVE_NDIR_H 39178825Sdfr# include <ndir.h> 40178825Sdfr# endif 41178825Sdfr#endif 42178825Sdfr#include <signal.h> 43178825Sdfr 44178825Sdfr#include <sys/user.h> /* After a.out.h */ 45178825Sdfr 46178825Sdfr#ifdef TRAD_HEADER 47178825Sdfr#include TRAD_HEADER 48233294Sstas#endif 49178825Sdfr 50178825Sdfr struct trad_core_struct 51178825Sdfr { 52178825Sdfr asection *data_section; 53178825Sdfr asection *stack_section; 54178825Sdfr asection *reg_section; 55178825Sdfr struct user u; 56178825Sdfr }; 57178825Sdfr 58178825Sdfr#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u)) 59178825Sdfr#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section) 60178825Sdfr#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section) 61178825Sdfr#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section) 62178825Sdfr 63233294Sstas/* forward declarations */ 64178825Sdfr 65178825Sdfrconst bfd_target *trad_unix_core_file_p PARAMS ((bfd *abfd)); 66178825Sdfrchar * trad_unix_core_file_failing_command PARAMS ((bfd *abfd)); 67178825Sdfrint trad_unix_core_file_failing_signal PARAMS ((bfd *abfd)); 68178825Sdfrboolean trad_unix_core_file_matches_executable_p 69178825Sdfr PARAMS ((bfd *core_bfd, bfd *exec_bfd)); 70178825Sdfrstatic void swap_abort PARAMS ((void)); 71178825Sdfr 72178825Sdfr/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */ 73178825Sdfr 74178825Sdfr/* ARGSUSED */ 75178825Sdfrconst bfd_target * 76178825Sdfrtrad_unix_core_file_p (abfd) 77233294Sstas bfd *abfd; 78233294Sstas 79233294Sstas{ 80233294Sstas int val; 81233294Sstas struct user u; 82233294Sstas struct trad_core_struct *rawptr; 83178825Sdfr 84178825Sdfr#ifdef TRAD_CORE_USER_OFFSET 85178825Sdfr /* If defined, this macro is the file position of the user struct. */ 86178825Sdfr if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) != 0) 87178825Sdfr return 0; 88178825Sdfr#endif 89178825Sdfr 90233294Sstas val = bfd_read ((void *)&u, 1, sizeof u, abfd); 91178825Sdfr if (val != sizeof u) 92178825Sdfr { 93178825Sdfr /* Too small to be a core file */ 94178825Sdfr bfd_set_error (bfd_error_wrong_format); 95178825Sdfr return 0; 96233294Sstas } 97178825Sdfr 98178825Sdfr /* Sanity check perhaps??? */ 99178825Sdfr if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */ 100178825Sdfr { 101178825Sdfr bfd_set_error (bfd_error_wrong_format); 102178825Sdfr return 0; 103178825Sdfr } 104233294Sstas if (u.u_ssize > 0x1000000) 105233294Sstas { 106178825Sdfr bfd_set_error (bfd_error_wrong_format); 107178825Sdfr return 0; 108178825Sdfr } 109178825Sdfr 110178825Sdfr /* Check that the size claimed is no greater than the file size. */ 111233294Sstas { 112233294Sstas FILE *stream = bfd_cache_lookup (abfd); 113178825Sdfr struct stat statbuf; 114178825Sdfr if (stream == NULL) 115178825Sdfr return 0; 116233294Sstas if (fstat (fileno (stream), &statbuf) < 0) 117178825Sdfr { 118178825Sdfr bfd_set_error (bfd_error_system_call); 119178825Sdfr return 0; 120178825Sdfr } 121178825Sdfr if ((unsigned long) (NBPG * (UPAGES + u.u_dsize 122233294Sstas#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE 123178825Sdfr - u.u_tsize 124178825Sdfr#endif 125233294Sstas + u.u_ssize)) 126178825Sdfr > (unsigned long) statbuf.st_size) 127178825Sdfr { 128178825Sdfr bfd_set_error (bfd_error_wrong_format); 129178825Sdfr return 0; 130233294Sstas } 131233294Sstas#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE 132233294Sstas if ((unsigned long) (NBPG * (UPAGES + u.u_dsize + u.u_ssize) 133178825Sdfr#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED 134178825Sdfr /* Some systems write the file too big. */ 135178825Sdfr + TRAD_CORE_EXTRA_SIZE_ALLOWED 136178825Sdfr#endif 137178825Sdfr ) 138233294Sstas < (unsigned long) statbuf.st_size) 139178825Sdfr { 140178825Sdfr /* The file is too big. Maybe it's not a core file 141178825Sdfr or we otherwise have bad values for u_dsize and u_ssize). */ 142178825Sdfr bfd_set_error (bfd_error_wrong_format); 143178825Sdfr return 0; 144178825Sdfr } 145233294Sstas#endif 146233294Sstas } 147178825Sdfr 148178825Sdfr /* OK, we believe you. You're a core file (sure, sure). */ 149233294Sstas 150178825Sdfr /* Allocate both the upage and the struct core_data at once, so 151178825Sdfr a single free() will free them both. */ 152178825Sdfr rawptr = (struct trad_core_struct *) 153178825Sdfr bfd_zmalloc (sizeof (struct trad_core_struct)); 154178825Sdfr if (rawptr == NULL) 155233294Sstas return 0; 156178825Sdfr 157178825Sdfr abfd->tdata.trad_core_data = rawptr; 158178825Sdfr 159178825Sdfr rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */ 160178825Sdfr 161178825Sdfr /* Create the sections. This is raunchy, but bfd_close wants to free 162178825Sdfr them separately. */ 163178825Sdfr 164178825Sdfr core_stacksec(abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); 165178825Sdfr if (core_stacksec (abfd) == NULL) 166178825Sdfr return NULL; 167178825Sdfr core_datasec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); 168178825Sdfr if (core_datasec (abfd) == NULL) 169178825Sdfr return NULL; 170178825Sdfr core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); 171178825Sdfr if (core_regsec (abfd) == NULL) 172178825Sdfr return NULL; 173178825Sdfr 174178825Sdfr core_stacksec (abfd)->name = ".stack"; 175178825Sdfr core_datasec (abfd)->name = ".data"; 176178825Sdfr core_regsec (abfd)->name = ".reg"; 177178825Sdfr 178178825Sdfr core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; 179233294Sstas core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; 180178825Sdfr core_regsec (abfd)->flags = SEC_HAS_CONTENTS; 181178825Sdfr 182233294Sstas core_datasec (abfd)->_raw_size = NBPG * u.u_dsize 183178825Sdfr#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE 184178825Sdfr - NBPG * u.u_tsize 185178825Sdfr#endif 186178825Sdfr ; 187178825Sdfr core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize; 188178825Sdfr core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */ 189178825Sdfr 190178825Sdfr /* What a hack... we'd like to steal it from the exec file, 191178825Sdfr since the upage does not seem to provide it. FIXME. */ 192178825Sdfr#ifdef HOST_DATA_START_ADDR 193178825Sdfr core_datasec (abfd)->vma = HOST_DATA_START_ADDR; 194178825Sdfr#else 195178825Sdfr core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize); 196178825Sdfr#endif 197178825Sdfr 198178825Sdfr#ifdef HOST_STACK_START_ADDR 199178825Sdfr core_stacksec (abfd)->vma = HOST_STACK_START_ADDR; 200233294Sstas#else 201233294Sstas core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize); 202178825Sdfr#endif 203178825Sdfr 204178825Sdfr /* This is tricky. As the "register section", we give them the entire 205178825Sdfr upage and stack. u.u_ar0 points to where "register 0" is stored. 206178825Sdfr There are two tricks with this, though. One is that the rest of the 207178825Sdfr registers might be at positive or negative (or both) displacements 208178825Sdfr from *u_ar0. The other is that u_ar0 is sometimes an absolute address 209178825Sdfr in kernel memory, and on other systems it is an offset from the beginning 210178825Sdfr of the `struct user'. 211178825Sdfr 212178825Sdfr As a practical matter, we don't know where the registers actually are, 213178825Sdfr so we have to pass the whole area to GDB. We encode the value of u_ar0 214178825Sdfr by setting the .regs section up so that its virtual memory address 215178825Sdfr 0 is at the place pointed to by u_ar0 (by setting the vma of the start 216178825Sdfr of the section to -u_ar0). GDB uses this info to locate the regs, 217233294Sstas using minor trickery to get around the offset-or-absolute-addr problem. */ 218178825Sdfr core_regsec (abfd)->vma = - (bfd_vma) u.u_ar0; 219178825Sdfr 220233294Sstas core_datasec (abfd)->filepos = NBPG * UPAGES; 221178825Sdfr core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize 222178825Sdfr#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE 223178825Sdfr - NBPG * u.u_tsize 224178825Sdfr#endif 225233294Sstas ; 226178825Sdfr core_regsec (abfd)->filepos = 0; /* Register segment is the upage */ 227233294Sstas 228233294Sstas /* Align to word at least */ 229233294Sstas core_stacksec (abfd)->alignment_power = 2; 230178825Sdfr core_datasec (abfd)->alignment_power = 2; 231233294Sstas core_regsec (abfd)->alignment_power = 2; 232178825Sdfr 233233294Sstas abfd->sections = core_stacksec (abfd); 234233294Sstas core_stacksec (abfd)->next = core_datasec (abfd); 235178825Sdfr core_datasec (abfd)->next = core_regsec (abfd); 236178825Sdfr abfd->section_count = 3; 237178825Sdfr 238178825Sdfr return abfd->xvec; 239178825Sdfr} 240233294Sstas 241178825Sdfrchar * 242178825Sdfrtrad_unix_core_file_failing_command (abfd) 243233294Sstas bfd *abfd; 244233294Sstas{ 245233294Sstas#ifndef NO_CORE_COMMAND 246233294Sstas char *com = abfd->tdata.trad_core_data->u.u_comm; 247178825Sdfr if (*com) 248233294Sstas return com; 249178825Sdfr else 250178825Sdfr#endif 251233294Sstas return 0; 252233294Sstas} 253178825Sdfr 254178825Sdfr/* ARGSUSED */ 255178825Sdfrint 256178825Sdfrtrad_unix_core_file_failing_signal (ignore_abfd) 257178825Sdfr bfd *ignore_abfd ATTRIBUTE_UNUSED; 258178825Sdfr{ 259178825Sdfr#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL 260178825Sdfr return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd); 261178825Sdfr#else 262178825Sdfr return -1; /* FIXME, where is it? */ 263178825Sdfr#endif 264178825Sdfr} 265178825Sdfr 266178825Sdfr/* ARGSUSED */ 267178825Sdfrboolean 268178825Sdfrtrad_unix_core_file_matches_executable_p (core_bfd, exec_bfd) 269178825Sdfr bfd *core_bfd ATTRIBUTE_UNUSED; 270233294Sstas bfd *exec_bfd ATTRIBUTE_UNUSED; 271178825Sdfr{ 272233294Sstas return true; /* FIXME, We have no way of telling at this point */ 273233294Sstas} 274178825Sdfr 275233294Sstas/* If somebody calls any byte-swapping routines, shoot them. */ 276178825Sdfrstatic void 277178825Sdfrswap_abort () 278178825Sdfr{ 279178825Sdfr abort (); /* This way doesn't require any declaration for ANSI to fuck up */ 280178825Sdfr} 281178825Sdfr#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) 282178825Sdfr#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) 283178825Sdfr#define NO_SIGNED_GET \ 284178825Sdfr ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) 285178825Sdfr 286178825Sdfrconst bfd_target trad_core_vec = 287178825Sdfr { 288178825Sdfr "trad-core", 289178825Sdfr bfd_target_unknown_flavour, 290178825Sdfr BFD_ENDIAN_UNKNOWN, /* target byte order */ 291178825Sdfr BFD_ENDIAN_UNKNOWN, /* target headers byte order */ 292178825Sdfr (HAS_RELOC | EXEC_P | /* object flags */ 293178825Sdfr HAS_LINENO | HAS_DEBUG | 294178825Sdfr HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 295178825Sdfr (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ 296178825Sdfr 0, /* symbol prefix */ 297178825Sdfr ' ', /* ar_pad_char */ 298178825Sdfr 16, /* ar_max_namelen */ 299178825Sdfr NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ 300178825Sdfr NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ 301178825Sdfr NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ 302178825Sdfr NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ 303178825Sdfr NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ 304178825Sdfr NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ 305178825Sdfr 306178825Sdfr { /* bfd_check_format */ 307178825Sdfr _bfd_dummy_target, /* unknown format */ 308178825Sdfr _bfd_dummy_target, /* object file */ 309178825Sdfr _bfd_dummy_target, /* archive */ 310178825Sdfr trad_unix_core_file_p /* a core file */ 311178825Sdfr }, 312178825Sdfr { /* bfd_set_format */ 313178825Sdfr bfd_false, bfd_false, 314178825Sdfr bfd_false, bfd_false 315178825Sdfr }, 316233294Sstas { /* bfd_write_contents */ 317178825Sdfr bfd_false, bfd_false, 318178825Sdfr bfd_false, bfd_false 319233294Sstas }, 320178825Sdfr 321178825Sdfr BFD_JUMP_TABLE_GENERIC (_bfd_generic), 322233294Sstas BFD_JUMP_TABLE_COPY (_bfd_generic), 323233294Sstas BFD_JUMP_TABLE_CORE (trad_unix), 324233294Sstas BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 325178825Sdfr BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), 326178825Sdfr BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 327178825Sdfr BFD_JUMP_TABLE_WRITE (_bfd_generic), 328178825Sdfr BFD_JUMP_TABLE_LINK (_bfd_nolink), 329233294Sstas BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 330178825Sdfr 331178825Sdfr NULL, 332178825Sdfr 333178825Sdfr (PTR) 0 /* backend_data */ 334178825Sdfr}; 335178825Sdfr