133965Sjdp/* BFD back end for traditional Unix core files (U-area and raw sections) 278828Sobrien Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 3218822Sdim 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 460484Sobrien Free Software Foundation, Inc. 533965Sjdp Written by John Gilmore of Cygnus Support. 633965Sjdp 733965SjdpThis file is part of BFD, the Binary File Descriptor library. 833965Sjdp 933965SjdpThis program is free software; you can redistribute it and/or modify 1033965Sjdpit under the terms of the GNU General Public License as published by 1133965Sjdpthe Free Software Foundation; either version 2 of the License, or 1233965Sjdp(at your option) any later version. 1333965Sjdp 1433965SjdpThis program is distributed in the hope that it will be useful, 1533965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1633965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1733965SjdpGNU General Public License for more details. 1833965Sjdp 1933965SjdpYou should have received a copy of the GNU General Public License 2033965Sjdpalong with this program; if not, write to the Free Software 21218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2233965Sjdp 23218822Sdim#include "sysdep.h" 2433965Sjdp#include "bfd.h" 2533965Sjdp#include "libbfd.h" 2633965Sjdp#include "libaout.h" /* BFD a.out internal data structures */ 2733965Sjdp 2833965Sjdp#include <sys/param.h> 2977298Sobrien#ifdef HAVE_DIRENT_H 3077298Sobrien# include <dirent.h> 3177298Sobrien#else 3277298Sobrien# ifdef HAVE_SYS_NDIR_H 3377298Sobrien# include <sys/ndir.h> 3477298Sobrien# endif 3577298Sobrien# ifdef HAVE_SYS_DIR_H 3677298Sobrien# include <sys/dir.h> 3777298Sobrien# endif 3877298Sobrien# ifdef HAVE_NDIR_H 3977298Sobrien# include <ndir.h> 4077298Sobrien# endif 4177298Sobrien#endif 4233965Sjdp#include <signal.h> 4333965Sjdp 4433965Sjdp#include <sys/user.h> /* After a.out.h */ 4533965Sjdp 4633965Sjdp#ifdef TRAD_HEADER 4733965Sjdp#include TRAD_HEADER 4833965Sjdp#endif 4933965Sjdp 50130561Sobrienstruct trad_core_struct 51130561Sobrien{ 52130561Sobrien asection *data_section; 53130561Sobrien asection *stack_section; 54130561Sobrien asection *reg_section; 55130561Sobrien struct user u; 56130561Sobrien}; 5733965Sjdp 5833965Sjdp#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u)) 5933965Sjdp#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section) 6033965Sjdp#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section) 6133965Sjdp#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section) 6233965Sjdp 6333965Sjdp/* forward declarations */ 6433965Sjdp 6533965Sjdpconst bfd_target *trad_unix_core_file_p PARAMS ((bfd *abfd)); 66130561Sobrienchar * trad_unix_core_file_failing_command PARAMS ((bfd *abfd)); 67130561Sobrienint trad_unix_core_file_failing_signal PARAMS ((bfd *abfd)); 68218822Sdim#define trad_unix_core_file_matches_executable_p generic_core_file_matches_executable_p 69130561Sobrienstatic void swap_abort PARAMS ((void)); 7033965Sjdp 7133965Sjdp/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */ 7233965Sjdp 7333965Sjdpconst bfd_target * 7433965Sjdptrad_unix_core_file_p (abfd) 7533965Sjdp bfd *abfd; 7633965Sjdp 7733965Sjdp{ 7833965Sjdp int val; 7933965Sjdp struct user u; 8033965Sjdp struct trad_core_struct *rawptr; 8189857Sobrien bfd_size_type amt; 82218822Sdim flagword flags; 8333965Sjdp 8433965Sjdp#ifdef TRAD_CORE_USER_OFFSET 8533965Sjdp /* If defined, this macro is the file position of the user struct. */ 8689857Sobrien if (bfd_seek (abfd, (file_ptr) TRAD_CORE_USER_OFFSET, SEEK_SET) != 0) 8733965Sjdp return 0; 8833965Sjdp#endif 8977298Sobrien 9089857Sobrien val = bfd_bread ((void *) &u, (bfd_size_type) sizeof u, abfd); 9133965Sjdp if (val != sizeof u) 9233965Sjdp { 9333965Sjdp /* Too small to be a core file */ 9433965Sjdp bfd_set_error (bfd_error_wrong_format); 9533965Sjdp return 0; 9633965Sjdp } 9733965Sjdp 9833965Sjdp /* Sanity check perhaps??? */ 9977298Sobrien if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */ 10033965Sjdp { 10133965Sjdp bfd_set_error (bfd_error_wrong_format); 10233965Sjdp return 0; 10333965Sjdp } 10433965Sjdp if (u.u_ssize > 0x1000000) 10533965Sjdp { 10633965Sjdp bfd_set_error (bfd_error_wrong_format); 10733965Sjdp return 0; 10833965Sjdp } 10933965Sjdp 11033965Sjdp /* Check that the size claimed is no greater than the file size. */ 11133965Sjdp { 11233965Sjdp struct stat statbuf; 113218822Sdim 114218822Sdim if (bfd_stat (abfd, &statbuf) < 0) 11533965Sjdp return 0; 116218822Sdim 117218822Sdim if ((ufile_ptr) NBPG * (UPAGES + u.u_dsize 11833965Sjdp#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE 119218822Sdim - u.u_tsize 12033965Sjdp#endif 121218822Sdim + u.u_ssize) 122218822Sdim > (ufile_ptr) statbuf.st_size) 12333965Sjdp { 12460484Sobrien bfd_set_error (bfd_error_wrong_format); 12533965Sjdp return 0; 12633965Sjdp } 12733965Sjdp#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE 128218822Sdim if (((ufile_ptr) NBPG * (UPAGES + u.u_dsize + u.u_ssize) 12933965Sjdp#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED 13033965Sjdp /* Some systems write the file too big. */ 131218822Sdim + TRAD_CORE_EXTRA_SIZE_ALLOWED 13233965Sjdp#endif 133218822Sdim ) 134218822Sdim < (ufile_ptr) statbuf.st_size) 13533965Sjdp { 13633965Sjdp /* The file is too big. Maybe it's not a core file 13733965Sjdp or we otherwise have bad values for u_dsize and u_ssize). */ 13833965Sjdp bfd_set_error (bfd_error_wrong_format); 13933965Sjdp return 0; 14033965Sjdp } 14133965Sjdp#endif 14233965Sjdp } 14333965Sjdp 14433965Sjdp /* OK, we believe you. You're a core file (sure, sure). */ 14533965Sjdp 14633965Sjdp /* Allocate both the upage and the struct core_data at once, so 14733965Sjdp a single free() will free them both. */ 14889857Sobrien amt = sizeof (struct trad_core_struct); 14989857Sobrien rawptr = (struct trad_core_struct *) bfd_zmalloc (amt); 15033965Sjdp if (rawptr == NULL) 15133965Sjdp return 0; 15277298Sobrien 15333965Sjdp abfd->tdata.trad_core_data = rawptr; 15433965Sjdp 15533965Sjdp rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */ 15633965Sjdp 15789857Sobrien /* Create the sections. */ 15833965Sjdp 159218822Sdim flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; 160218822Sdim core_stacksec(abfd) = bfd_make_section_anyway_with_flags (abfd, ".stack", 161218822Sdim flags); 16233965Sjdp if (core_stacksec (abfd) == NULL) 16389857Sobrien goto fail; 164218822Sdim core_datasec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".data", 165218822Sdim flags); 16633965Sjdp if (core_datasec (abfd) == NULL) 16789857Sobrien goto fail; 168218822Sdim core_regsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg", 169218822Sdim SEC_HAS_CONTENTS); 17033965Sjdp if (core_regsec (abfd) == NULL) 17189857Sobrien goto fail; 17233965Sjdp 173218822Sdim core_datasec (abfd)->size = NBPG * u.u_dsize 17433965Sjdp#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE 17533965Sjdp - NBPG * u.u_tsize 17633965Sjdp#endif 17733965Sjdp ; 178218822Sdim core_stacksec (abfd)->size = NBPG * u.u_ssize; 179218822Sdim core_regsec (abfd)->size = NBPG * UPAGES; /* Larger than sizeof struct u */ 18033965Sjdp 18133965Sjdp /* What a hack... we'd like to steal it from the exec file, 18233965Sjdp since the upage does not seem to provide it. FIXME. */ 18333965Sjdp#ifdef HOST_DATA_START_ADDR 18433965Sjdp core_datasec (abfd)->vma = HOST_DATA_START_ADDR; 18533965Sjdp#else 18633965Sjdp core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize); 18733965Sjdp#endif 18833965Sjdp 18933965Sjdp#ifdef HOST_STACK_START_ADDR 19033965Sjdp core_stacksec (abfd)->vma = HOST_STACK_START_ADDR; 19133965Sjdp#else 19233965Sjdp core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize); 19333965Sjdp#endif 19433965Sjdp 19533965Sjdp /* This is tricky. As the "register section", we give them the entire 19633965Sjdp upage and stack. u.u_ar0 points to where "register 0" is stored. 19733965Sjdp There are two tricks with this, though. One is that the rest of the 19833965Sjdp registers might be at positive or negative (or both) displacements 19933965Sjdp from *u_ar0. The other is that u_ar0 is sometimes an absolute address 20033965Sjdp in kernel memory, and on other systems it is an offset from the beginning 20133965Sjdp of the `struct user'. 20277298Sobrien 20333965Sjdp As a practical matter, we don't know where the registers actually are, 20433965Sjdp so we have to pass the whole area to GDB. We encode the value of u_ar0 20533965Sjdp by setting the .regs section up so that its virtual memory address 20633965Sjdp 0 is at the place pointed to by u_ar0 (by setting the vma of the start 20733965Sjdp of the section to -u_ar0). GDB uses this info to locate the regs, 20877298Sobrien using minor trickery to get around the offset-or-absolute-addr problem. */ 20991041Sobrien core_regsec (abfd)->vma = - (bfd_vma) (unsigned long) u.u_ar0; 21033965Sjdp 21133965Sjdp core_datasec (abfd)->filepos = NBPG * UPAGES; 21233965Sjdp core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize 21333965Sjdp#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE 21433965Sjdp - NBPG * u.u_tsize 21533965Sjdp#endif 21633965Sjdp ; 21733965Sjdp core_regsec (abfd)->filepos = 0; /* Register segment is the upage */ 21833965Sjdp 21933965Sjdp /* Align to word at least */ 22033965Sjdp core_stacksec (abfd)->alignment_power = 2; 22133965Sjdp core_datasec (abfd)->alignment_power = 2; 22233965Sjdp core_regsec (abfd)->alignment_power = 2; 22333965Sjdp 22489857Sobrien return abfd->xvec; 22533965Sjdp 22689857Sobrien fail: 22789857Sobrien bfd_release (abfd, abfd->tdata.any); 22889857Sobrien abfd->tdata.any = NULL; 22989857Sobrien bfd_section_list_clear (abfd); 23089857Sobrien return NULL; 23133965Sjdp} 23233965Sjdp 23333965Sjdpchar * 23433965Sjdptrad_unix_core_file_failing_command (abfd) 23533965Sjdp bfd *abfd; 23633965Sjdp{ 23733965Sjdp#ifndef NO_CORE_COMMAND 23833965Sjdp char *com = abfd->tdata.trad_core_data->u.u_comm; 23933965Sjdp if (*com) 24033965Sjdp return com; 24133965Sjdp else 24233965Sjdp#endif 24333965Sjdp return 0; 24433965Sjdp} 24533965Sjdp 24633965Sjdpint 24733965Sjdptrad_unix_core_file_failing_signal (ignore_abfd) 24860484Sobrien bfd *ignore_abfd ATTRIBUTE_UNUSED; 24933965Sjdp{ 25033965Sjdp#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL 25133965Sjdp return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd); 25233965Sjdp#else 25333965Sjdp return -1; /* FIXME, where is it? */ 25433965Sjdp#endif 25533965Sjdp} 25633965Sjdp 25733965Sjdp/* If somebody calls any byte-swapping routines, shoot them. */ 25833965Sjdpstatic void 25977298Sobrienswap_abort () 26033965Sjdp{ 26177298Sobrien abort (); /* This way doesn't require any declaration for ANSI to fuck up */ 26233965Sjdp} 26333965Sjdp 264130561Sobrien#define NO_GET ((bfd_vma (*) (const void *)) swap_abort) 265130561Sobrien#define NO_PUT ((void (*) (bfd_vma, void *)) swap_abort) 266130561Sobrien#define NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort) 267130561Sobrien#define NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort) 268130561Sobrien#define NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort) 269130561Sobrien#define NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort) 270130561Sobrien 27133965Sjdpconst bfd_target trad_core_vec = 27233965Sjdp { 27333965Sjdp "trad-core", 27433965Sjdp bfd_target_unknown_flavour, 27533965Sjdp BFD_ENDIAN_UNKNOWN, /* target byte order */ 27633965Sjdp BFD_ENDIAN_UNKNOWN, /* target headers byte order */ 27733965Sjdp (HAS_RELOC | EXEC_P | /* object flags */ 27833965Sjdp HAS_LINENO | HAS_DEBUG | 27933965Sjdp HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 28033965Sjdp (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ 28133965Sjdp 0, /* symbol prefix */ 28233965Sjdp ' ', /* ar_pad_char */ 28333965Sjdp 16, /* ar_max_namelen */ 284130561Sobrien NO_GET64, NO_GETS64, NO_PUT64, /* 64 bit data */ 285130561Sobrien NO_GET, NO_GETS, NO_PUT, /* 32 bit data */ 286130561Sobrien NO_GET, NO_GETS, NO_PUT, /* 16 bit data */ 287130561Sobrien NO_GET64, NO_GETS64, NO_PUT64, /* 64 bit hdrs */ 288130561Sobrien NO_GET, NO_GETS, NO_PUT, /* 32 bit hdrs */ 289130561Sobrien NO_GET, NO_GETS, NO_PUT, /* 16 bit hdrs */ 29033965Sjdp 29133965Sjdp { /* bfd_check_format */ 292130561Sobrien _bfd_dummy_target, /* unknown format */ 293130561Sobrien _bfd_dummy_target, /* object file */ 294130561Sobrien _bfd_dummy_target, /* archive */ 295130561Sobrien trad_unix_core_file_p /* a core file */ 29633965Sjdp }, 29733965Sjdp { /* bfd_set_format */ 298130561Sobrien bfd_false, bfd_false, 299130561Sobrien bfd_false, bfd_false 30033965Sjdp }, 30133965Sjdp { /* bfd_write_contents */ 302130561Sobrien bfd_false, bfd_false, 303130561Sobrien bfd_false, bfd_false 30433965Sjdp }, 30577298Sobrien 306130561Sobrien BFD_JUMP_TABLE_GENERIC (_bfd_generic), 307130561Sobrien BFD_JUMP_TABLE_COPY (_bfd_generic), 308130561Sobrien BFD_JUMP_TABLE_CORE (trad_unix), 309130561Sobrien BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 310130561Sobrien BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), 311130561Sobrien BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 312130561Sobrien BFD_JUMP_TABLE_WRITE (_bfd_generic), 313130561Sobrien BFD_JUMP_TABLE_LINK (_bfd_nolink), 314130561Sobrien BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 31533965Sjdp 31660484Sobrien NULL, 31777298Sobrien 31833965Sjdp (PTR) 0 /* backend_data */ 319130561Sobrien }; 320