155682Smarkm/* BFD back-end for CISCO crash dumps. 2102644Snectar Copyright 1994, 1997, 1999, 2000, 2001, 2002, 2004 355682Smarkm Free Software Foundation, Inc. 455682Smarkm 555682SmarkmThis file is part of BFD, the Binary File Descriptor library. 655682Smarkm 755682SmarkmThis program is free software; you can redistribute it and/or modify 855682Smarkmit under the terms of the GNU General Public License as published by 955682Smarkmthe Free Software Foundation; either version 2 of the License, or 1055682Smarkm(at your option) any later version. 1155682Smarkm 1255682SmarkmThis program is distributed in the hope that it will be useful, 1355682Smarkmbut WITHOUT ANY WARRANTY; without even the implied warranty of 1455682SmarkmMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1555682SmarkmGNU General Public License for more details. 1655682Smarkm 1755682SmarkmYou should have received a copy of the GNU General Public License 1855682Smarkmalong with this program; if not, write to the Free Software 1955682SmarkmFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2055682Smarkm 2155682Smarkm#include "bfd.h" 2255682Smarkm#include "sysdep.h" 2355682Smarkm#include "libbfd.h" 2455682Smarkm/* core_file_failing_signal returns a host signal (this probably should 2555682Smarkm be fixed). */ 2655682Smarkm#include <signal.h> 2755682Smarkm 2855682Smarkm/* for MSVC builds */ 2955682Smarkm#ifndef SIGTRAP 3055682Smarkm# define SIGTRAP 5 3155682Smarkm#endif 3255682Smarkm#ifndef SIGEMT 3355682Smarkm# define SIGEMT 6 3455682Smarkm#endif 3555682Smarkm#ifndef SIGBUS 36178825Sdfr# define SIGBUS 10 37178825Sdfr#endif 38178825Sdfr 3955682Smarkmint crash_info_locs[] = { 4055682Smarkm 0x0250, /* mips, ppc, x86, i960 */ 41178825Sdfr 0x0400, /* m68k, mips, x86, i960 */ 4255682Smarkm 0x0FFC, /* m68k, mips, ppc, x86, i960 */ 4355682Smarkm 0x3000, /* ppc */ 4455682Smarkm 0x4FFC, /* m68k */ 4555682Smarkm -1 4655682Smarkm}; 4755682Smarkm 4855682Smarkm#define CRASH_MAGIC 0xdead1234 4955682Smarkm#define MASK_ADDR(x) ((x) & 0x0fffffff) /* Mask crash info address */ 5055682Smarkm 5155682Smarkmtypedef enum { 5255682Smarkm CRASH_REASON_NOTCRASHED = 0, 5355682Smarkm CRASH_REASON_EXCEPTION = 1, 5455682Smarkm CRASH_REASON_CORRUPT = 2, 5555682Smarkm} crashreason; 5655682Smarkm 5755682Smarkmtypedef struct { 5855682Smarkm char magic[4]; /* Magic number */ 5955682Smarkm char version[4]; /* Version number */ 6055682Smarkm char reason[4]; /* Crash reason */ 6155682Smarkm char cpu_vector[4]; /* CPU vector for exceptions */ 6255682Smarkm char registers[4]; /* Pointer to saved registers */ 6355682Smarkm char rambase[4]; /* Base of RAM (not in V1 crash info) */ 6455682Smarkm char textbase[4]; /* Base of .text section (not in V3 crash info) */ 6555682Smarkm char database[4]; /* Base of .data section (not in V3 crash info) */ 6655682Smarkm char bssbase[4]; /* Base of .bss section (not in V3 crash info) */ 6755682Smarkm} crashinfo_external; 6855682Smarkm 6955682Smarkmstruct cisco_core_struct 7055682Smarkm{ 7155682Smarkm int sig; 7255682Smarkm}; 7355682Smarkm 7455682Smarkmstatic const bfd_target *cisco_core_file_validate PARAMS ((bfd *, int)); 7555682Smarkmstatic const bfd_target *cisco_core_file_p PARAMS ((bfd *)); 7655682Smarkmchar *cisco_core_file_failing_command PARAMS ((bfd *)); 7755682Smarkmint cisco_core_file_failing_signal PARAMS ((bfd *)); 7855682Smarkmbfd_boolean cisco_core_file_matches_executable_p PARAMS ((bfd *, bfd *)); 7955682Smarkm 8055682Smarkm/* Examine the file for a crash info struct at the offset given by 8155682Smarkm CRASH_INFO_LOC. */ 8255682Smarkm 8355682Smarkmstatic const bfd_target * 8455682Smarkmcisco_core_file_validate (abfd, crash_info_loc) 8555682Smarkm bfd *abfd; 8655682Smarkm int crash_info_loc; 8755682Smarkm{ 8855682Smarkm char buf[4]; 8955682Smarkm unsigned int crashinfo_offset; 9055682Smarkm crashinfo_external crashinfo; 9155682Smarkm int nread; 9255682Smarkm unsigned int magic; 9355682Smarkm unsigned int version; 9455682Smarkm unsigned int rambase; 9555682Smarkm sec_ptr asect; 9655682Smarkm struct stat statbuf; 9755682Smarkm bfd_size_type amt; 9855682Smarkm 9955682Smarkm if (bfd_seek (abfd, (file_ptr) crash_info_loc, SEEK_SET) != 0) 10055682Smarkm return NULL; 10155682Smarkm 10255682Smarkm nread = bfd_bread (buf, (bfd_size_type) 4, abfd); 10355682Smarkm if (nread != 4) 10455682Smarkm { 10555682Smarkm if (bfd_get_error () != bfd_error_system_call) 10655682Smarkm bfd_set_error (bfd_error_wrong_format); 10755682Smarkm return NULL; 10855682Smarkm } 10955682Smarkm crashinfo_offset = MASK_ADDR (bfd_get_32 (abfd, buf)); 11055682Smarkm 11155682Smarkm if (bfd_seek (abfd, (file_ptr) crashinfo_offset, SEEK_SET) != 0) 11255682Smarkm { 11355682Smarkm /* Most likely we failed because of a bogus (huge) offset */ 11455682Smarkm bfd_set_error (bfd_error_wrong_format); 11555682Smarkm return NULL; 11655682Smarkm } 11755682Smarkm 11855682Smarkm nread = bfd_bread (&crashinfo, (bfd_size_type) sizeof (crashinfo), abfd); 11955682Smarkm if (nread != sizeof (crashinfo)) 12055682Smarkm { 12155682Smarkm if (bfd_get_error () != bfd_error_system_call) 12255682Smarkm bfd_set_error (bfd_error_wrong_format); 12355682Smarkm return NULL; 12455682Smarkm } 12555682Smarkm 12655682Smarkm if (bfd_stat (abfd, &statbuf) < 0) 12755682Smarkm { 12855682Smarkm bfd_set_error (bfd_error_system_call); 12955682Smarkm return NULL; 13055682Smarkm } 13155682Smarkm 13255682Smarkm magic = bfd_get_32 (abfd, crashinfo.magic); 13355682Smarkm if (magic != CRASH_MAGIC) 13455682Smarkm { 13555682Smarkm bfd_set_error (bfd_error_wrong_format); 13655682Smarkm return NULL; 13755682Smarkm } 13855682Smarkm 13955682Smarkm version = bfd_get_32 (abfd, crashinfo.version); 14055682Smarkm if (version == 0) 14155682Smarkm { 14255682Smarkm bfd_set_error (bfd_error_wrong_format); 14355682Smarkm return NULL; 14455682Smarkm } 14555682Smarkm else if (version == 1) 14655682Smarkm { 14755682Smarkm /* V1 core dumps don't specify the dump base, assume 0 */ 14855682Smarkm rambase = 0; 14955682Smarkm } 15055682Smarkm else 15155682Smarkm { 15255682Smarkm rambase = bfd_get_32 (abfd, crashinfo.rambase); 15355682Smarkm } 15455682Smarkm 15555682Smarkm /* OK, we believe you. You're a core file. */ 15655682Smarkm 15755682Smarkm amt = sizeof (struct cisco_core_struct); 15855682Smarkm abfd->tdata.cisco_core_data = (struct cisco_core_struct *) bfd_zmalloc (amt); 15955682Smarkm if (abfd->tdata.cisco_core_data == NULL) 16055682Smarkm return NULL; 16155682Smarkm 16255682Smarkm switch ((crashreason) bfd_get_32 (abfd, crashinfo.reason)) 16355682Smarkm { 16455682Smarkm case CRASH_REASON_NOTCRASHED: 16555682Smarkm /* Crash file probably came from write core. */ 16655682Smarkm abfd->tdata.cisco_core_data->sig = 0; 16755682Smarkm break; 16855682Smarkm case CRASH_REASON_CORRUPT: 16955682Smarkm /* The crash context area was corrupt -- proceed with caution. 17055682Smarkm We have no way of passing this information back to the caller. */ 17155682Smarkm abfd->tdata.cisco_core_data->sig = 0; 17255682Smarkm break; 173178825Sdfr case CRASH_REASON_EXCEPTION: 17455682Smarkm /* Crash occured due to CPU exception. */ 17555682Smarkm 17655682Smarkm /* This is 68k-specific; for MIPS we'll need to interpret 17755682Smarkm cpu_vector differently based on the target configuration 17890926Snectar (since CISCO core files don't seem to have the processor 17955682Smarkm encoded in them). */ 18055682Smarkm 18155682Smarkm switch (bfd_get_32 (abfd, crashinfo.cpu_vector)) 18255682Smarkm { 18355682Smarkm /* bus error */ 18455682Smarkm case 2 : abfd->tdata.cisco_core_data->sig = SIGBUS; break; 18555682Smarkm /* address error */ 18655682Smarkm case 3 : abfd->tdata.cisco_core_data->sig = SIGBUS; break; 18755682Smarkm /* illegal instruction */ 18855682Smarkm case 4 : abfd->tdata.cisco_core_data->sig = SIGILL; break; 18955682Smarkm /* zero divide */ 19055682Smarkm case 5 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; 19155682Smarkm /* chk instruction */ 19255682Smarkm case 6 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; 19355682Smarkm /* trapv instruction */ 19455682Smarkm case 7 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; 19555682Smarkm /* privilege violation */ 19655682Smarkm case 8 : abfd->tdata.cisco_core_data->sig = SIGSEGV; break; 19755682Smarkm /* trace trap */ 19855682Smarkm case 9 : abfd->tdata.cisco_core_data->sig = SIGTRAP; break; 19955682Smarkm /* line 1010 emulator */ 20055682Smarkm case 10: abfd->tdata.cisco_core_data->sig = SIGILL; break; 20155682Smarkm /* line 1111 emulator */ 20255682Smarkm case 11: abfd->tdata.cisco_core_data->sig = SIGILL; break; 20355682Smarkm 20455682Smarkm /* Coprocessor protocol violation. Using a standard MMU or FPU 20555682Smarkm this cannot be triggered by software. Call it a SIGBUS. */ 20655682Smarkm case 13: abfd->tdata.cisco_core_data->sig = SIGBUS; break; 20755682Smarkm 20855682Smarkm /* interrupt */ 20955682Smarkm case 31: abfd->tdata.cisco_core_data->sig = SIGINT; break; 21055682Smarkm /* breakpoint */ 21155682Smarkm case 33: abfd->tdata.cisco_core_data->sig = SIGTRAP; break; 21255682Smarkm 21355682Smarkm /* floating point err */ 21455682Smarkm case 48: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 21555682Smarkm /* floating point err */ 21655682Smarkm case 49: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 21755682Smarkm /* zero divide */ 21855682Smarkm case 50: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 21955682Smarkm /* underflow */ 22055682Smarkm case 51: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 22155682Smarkm /* operand error */ 22255682Smarkm case 52: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 22355682Smarkm /* overflow */ 22455682Smarkm case 53: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 22555682Smarkm /* NAN */ 22655682Smarkm case 54: abfd->tdata.cisco_core_data->sig = SIGFPE; break; 22755682Smarkm default: 22855682Smarkm#ifndef SIGEMT 22955682Smarkm#define SIGEMT SIGTRAP 23055682Smarkm#endif 23155682Smarkm /* "software generated"*/ 23255682Smarkm abfd->tdata.cisco_core_data->sig = SIGEMT; 23355682Smarkm } 23455682Smarkm break; 23555682Smarkm default: 23655682Smarkm /* Unknown crash reason. */ 23755682Smarkm abfd->tdata.cisco_core_data->sig = 0; 23855682Smarkm break; 23955682Smarkm } 24055682Smarkm 24155682Smarkm /* Create a ".data" section that maps the entire file, which is 24255682Smarkm essentially a dump of the target system's RAM. */ 24355682Smarkm 24455682Smarkm asect = bfd_make_section_anyway (abfd, ".data"); 24555682Smarkm if (asect == NULL) 24655682Smarkm goto error_return; 24755682Smarkm asect->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; 24855682Smarkm /* The size of memory is the size of the core file itself. */ 24955682Smarkm asect->size = statbuf.st_size; 25055682Smarkm asect->vma = rambase; 25155682Smarkm asect->filepos = 0; 25255682Smarkm 25355682Smarkm /* Create a ".crash" section to allow access to the saved 25455682Smarkm crash information. */ 25555682Smarkm 25655682Smarkm asect = bfd_make_section_anyway (abfd, ".crash"); 25755682Smarkm if (asect == NULL) 25855682Smarkm goto error_return; 25955682Smarkm asect->flags = SEC_HAS_CONTENTS; 26055682Smarkm asect->vma = 0; 26155682Smarkm asect->filepos = crashinfo_offset; 26255682Smarkm asect->size = sizeof (crashinfo); 26355682Smarkm 26455682Smarkm /* Create a ".reg" section to allow access to the saved 26555682Smarkm registers. */ 26655682Smarkm 26755682Smarkm asect = bfd_make_section_anyway (abfd, ".reg"); 26855682Smarkm if (asect == NULL) 26955682Smarkm goto error_return; 27055682Smarkm asect->flags = SEC_HAS_CONTENTS; 27155682Smarkm asect->vma = 0; 27255682Smarkm asect->filepos = bfd_get_32 (abfd, crashinfo.registers) - rambase; 27355682Smarkm /* Since we don't know the exact size of the saved register info, 27455682Smarkm choose a register section size that is either the remaining part 27555682Smarkm of the file, or 1024, whichever is smaller. */ 27655682Smarkm nread = statbuf.st_size - asect->filepos; 27755682Smarkm asect->size = (nread < 1024) ? nread : 1024; 27855682Smarkm 27955682Smarkm return abfd->xvec; 28055682Smarkm 28155682Smarkm /* Get here if we have already started filling out the BFD 28255682Smarkm and there is an error of some kind. */ 28355682Smarkm 28455682Smarkm error_return: 28555682Smarkm bfd_release (abfd, abfd->tdata.any); 28655682Smarkm abfd->tdata.any = NULL; 28755682Smarkm bfd_section_list_clear (abfd); 28855682Smarkm return NULL; 28955682Smarkm} 29055682Smarkm 29155682Smarkmstatic const bfd_target * 29255682Smarkmcisco_core_file_p (abfd) 29355682Smarkm bfd *abfd; 29455682Smarkm{ 29555682Smarkm int *crash_info_locp; 296178825Sdfr const bfd_target *target = NULL; 29755682Smarkm 29855682Smarkm for (crash_info_locp = crash_info_locs; 29955682Smarkm *crash_info_locp != -1 && target == NULL; 30055682Smarkm crash_info_locp++) 30155682Smarkm { 30255682Smarkm target = cisco_core_file_validate (abfd, *crash_info_locp); 30355682Smarkm } 30455682Smarkm return (target); 30555682Smarkm} 30655682Smarkm 30755682Smarkmchar * 30855682Smarkmcisco_core_file_failing_command (abfd) 30955682Smarkm bfd *abfd ATTRIBUTE_UNUSED; 31055682Smarkm{ 31155682Smarkm return NULL; 31255682Smarkm} 31355682Smarkm 31455682Smarkmint 31555682Smarkmcisco_core_file_failing_signal (abfd) 31655682Smarkm bfd *abfd ATTRIBUTE_UNUSED; 31755682Smarkm{ 31855682Smarkm return abfd->tdata.cisco_core_data->sig; 31955682Smarkm} 32055682Smarkm 32155682Smarkmbfd_boolean 32255682Smarkmcisco_core_file_matches_executable_p (core_bfd, exec_bfd) 32355682Smarkm bfd *core_bfd ATTRIBUTE_UNUSED; 32455682Smarkm bfd *exec_bfd ATTRIBUTE_UNUSED; 32555682Smarkm{ 32655682Smarkm return TRUE; 32755682Smarkm} 32855682Smarkm 32955682Smarkmextern const bfd_target cisco_core_little_vec; 33055682Smarkm 33155682Smarkmconst bfd_target cisco_core_big_vec = 33255682Smarkm { 33355682Smarkm "cisco-ios-core-big", 33455682Smarkm bfd_target_unknown_flavour, 33555682Smarkm BFD_ENDIAN_BIG, /* target byte order */ 33655682Smarkm BFD_ENDIAN_BIG, /* target headers byte order */ 33755682Smarkm (HAS_RELOC | EXEC_P | /* object flags */ 33855682Smarkm HAS_LINENO | HAS_DEBUG | 33955682Smarkm HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 34055682Smarkm (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ 34155682Smarkm 0, /* symbol prefix */ 34255682Smarkm ' ', /* ar_pad_char */ 34355682Smarkm 16, /* ar_max_namelen */ 34455682Smarkm bfd_getb64, bfd_getb_signed_64, bfd_putb64, 34555682Smarkm bfd_getb32, bfd_getb_signed_32, bfd_putb32, 34655682Smarkm bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ 34755682Smarkm bfd_getb64, bfd_getb_signed_64, bfd_putb64, 34855682Smarkm bfd_getb32, bfd_getb_signed_32, bfd_putb32, 34955682Smarkm bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ 35055682Smarkm 35155682Smarkm { /* bfd_check_format */ 35255682Smarkm _bfd_dummy_target, /* unknown format */ 35355682Smarkm _bfd_dummy_target, /* object file */ 354102644Snectar _bfd_dummy_target, /* archive */ 35555682Smarkm cisco_core_file_p /* a core file */ 35655682Smarkm }, 357102644Snectar { /* bfd_set_format */ 35855682Smarkm bfd_false, bfd_false, 35955682Smarkm bfd_false, bfd_false 36055682Smarkm }, 36155682Smarkm { /* bfd_write_contents */ 36255682Smarkm bfd_false, bfd_false, 36355682Smarkm bfd_false, bfd_false 36455682Smarkm }, 36555682Smarkm 36655682Smarkm BFD_JUMP_TABLE_GENERIC (_bfd_generic), 36755682Smarkm BFD_JUMP_TABLE_COPY (_bfd_generic), 36855682Smarkm BFD_JUMP_TABLE_CORE (cisco), 36955682Smarkm BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 37055682Smarkm BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), 37155682Smarkm BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 37255682Smarkm BFD_JUMP_TABLE_WRITE (_bfd_generic), 37355682Smarkm BFD_JUMP_TABLE_LINK (_bfd_nolink), 37455682Smarkm BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 37555682Smarkm 37655682Smarkm & cisco_core_little_vec, 37755682Smarkm 37855682Smarkm (PTR) 0 /* backend_data */ 37955682Smarkm}; 38055682Smarkm 38155682Smarkmconst bfd_target cisco_core_little_vec = 38255682Smarkm { 38355682Smarkm "cisco-ios-core-little", 38455682Smarkm bfd_target_unknown_flavour, 38555682Smarkm BFD_ENDIAN_LITTLE, /* target byte order */ 38655682Smarkm BFD_ENDIAN_LITTLE, /* target headers byte order */ 38755682Smarkm (HAS_RELOC | EXEC_P | /* object flags */ 38855682Smarkm HAS_LINENO | HAS_DEBUG | 38990926Snectar HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 39055682Smarkm (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ 39155682Smarkm 0, /* symbol prefix */ 39255682Smarkm ' ', /* ar_pad_char */ 39355682Smarkm 16, /* ar_max_namelen */ 39455682Smarkm bfd_getl64, bfd_getl_signed_64, bfd_putl64, 39555682Smarkm bfd_getl32, bfd_getl_signed_32, bfd_putl32, 39655682Smarkm bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 39755682Smarkm bfd_getl64, bfd_getl_signed_64, bfd_putl64, 39855682Smarkm bfd_getl32, bfd_getl_signed_32, bfd_putl32, 39955682Smarkm bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ 40055682Smarkm 40155682Smarkm { /* bfd_check_format */ 402 _bfd_dummy_target, /* unknown format */ 403 _bfd_dummy_target, /* object file */ 404 _bfd_dummy_target, /* archive */ 405 cisco_core_file_p /* a core file */ 406 }, 407 { /* bfd_set_format */ 408 bfd_false, bfd_false, 409 bfd_false, bfd_false 410 }, 411 { /* bfd_write_contents */ 412 bfd_false, bfd_false, 413 bfd_false, bfd_false 414 }, 415 416 BFD_JUMP_TABLE_GENERIC (_bfd_generic), 417 BFD_JUMP_TABLE_COPY (_bfd_generic), 418 BFD_JUMP_TABLE_CORE (cisco), 419 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 420 BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), 421 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 422 BFD_JUMP_TABLE_WRITE (_bfd_generic), 423 BFD_JUMP_TABLE_LINK (_bfd_nolink), 424 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 425 426 &cisco_core_big_vec, 427 428 (PTR) 0 /* backend_data */ 429}; 430