Home | History | Annotate | Download | only in bfd
      1 /* BFD back-end for CISCO crash dumps.
      2    Copyright (C) 1994-2016 Free Software Foundation, Inc.
      3 
      4    This file is part of BFD, the Binary File Descriptor library.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; if not, write to the Free Software
     18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19    MA 02110-1301, USA.  */
     20 
     21 #include "sysdep.h"
     22 #include "bfd.h"
     23 #include "libbfd.h"
     24 /* core_file_failing_signal returns a host signal (this probably should
     25    be fixed).  */
     26 #include <signal.h>
     27 
     28 /* for MSVC builds */
     29 #ifndef SIGTRAP
     30 # define SIGTRAP 5
     31 #endif
     32 #ifndef SIGEMT
     33 # define SIGEMT 6
     34 #endif
     35 #ifndef SIGBUS
     36 # define SIGBUS 10
     37 #endif
     38 
     39 int crash_info_locs[] =
     41 {
     42   0x0250,	/* mips, ppc, x86, i960 */
     43   0x0400,	/* m68k, mips, x86, i960 */
     44   0x0FFC,	/* m68k, mips, ppc, x86, i960 */
     45   0x3000,	/* ppc */
     46   0x4FFC,	/* m68k */
     47   -1
     48 };
     49 
     50 #define CRASH_MAGIC	0xdead1234
     51 #define MASK_ADDR(x)	((x) & 0x0fffffff)	/* Mask crash info address */
     52 
     53 typedef enum
     54 {
     55   CRASH_REASON_NOTCRASHED = 0,
     56   CRASH_REASON_EXCEPTION = 1,
     57   CRASH_REASON_CORRUPT = 2,
     58 } crashreason;
     59 
     60 typedef struct
     61 {
     62   char magic[4];		/* Magic number */
     63   char version[4];		/* Version number */
     64   char reason[4];		/* Crash reason */
     65   char cpu_vector[4];		/* CPU vector for exceptions */
     66   char registers[4];		/* Pointer to saved registers */
     67   char rambase[4];		/* Base of RAM (not in V1 crash info) */
     68   char textbase[4];		/* Base of .text section (not in V3 crash info) */
     69   char database[4];		/* Base of .data section (not in V3 crash info) */
     70   char bssbase[4];		/* Base of .bss section (not in V3 crash info) */
     71 } crashinfo_external;
     72 
     73 struct cisco_core_struct
     74 {
     75   int sig;
     76 };
     77 
     78 #define cisco_core_file_matches_executable_p generic_core_file_matches_executable_p
     79 #define cisco_core_file_pid _bfd_nocore_core_file_pid
     80 
     81 /* Examine the file for a crash info struct at the offset given by
     83    CRASH_INFO_LOC.  */
     84 
     85 static const bfd_target *
     86 cisco_core_file_validate (bfd *abfd, int crash_info_loc)
     87 {
     88   char buf[4];
     89   unsigned int crashinfo_offset;
     90   crashinfo_external crashinfo;
     91   bfd_size_type nread;
     92   unsigned int magic;
     93   unsigned int version;
     94   unsigned int rambase;
     95   sec_ptr asect;
     96   struct stat statbuf;
     97   bfd_size_type amt;
     98   flagword flags;
     99 
    100   if (bfd_seek (abfd, (file_ptr) crash_info_loc, SEEK_SET) != 0)
    101     return NULL;
    102 
    103   nread = bfd_bread (buf, (bfd_size_type) 4, abfd);
    104   if (nread != 4)
    105     {
    106       if (bfd_get_error () != bfd_error_system_call)
    107 	bfd_set_error (bfd_error_wrong_format);
    108       return NULL;
    109     }
    110   crashinfo_offset = MASK_ADDR (bfd_get_32 (abfd, buf));
    111 
    112   if (bfd_seek (abfd, (file_ptr) crashinfo_offset, SEEK_SET) != 0)
    113     {
    114       /* Most likely we failed because of a bogus (huge) offset */
    115       bfd_set_error (bfd_error_wrong_format);
    116       return NULL;
    117     }
    118 
    119   nread = bfd_bread (&crashinfo, (bfd_size_type) sizeof (crashinfo), abfd);
    120   if (nread != sizeof (crashinfo))
    121     {
    122       if (bfd_get_error () != bfd_error_system_call)
    123 	bfd_set_error (bfd_error_wrong_format);
    124       return NULL;
    125     }
    126 
    127   if (bfd_stat (abfd, &statbuf) < 0)
    128     {
    129       bfd_set_error (bfd_error_system_call);
    130       return NULL;
    131     }
    132 
    133   magic = bfd_get_32 (abfd, crashinfo.magic);
    134   if (magic != CRASH_MAGIC)
    135     {
    136       bfd_set_error (bfd_error_wrong_format);
    137       return NULL;
    138     }
    139 
    140   version = bfd_get_32 (abfd, crashinfo.version);
    141   if (version == 0)
    142     {
    143       bfd_set_error (bfd_error_wrong_format);
    144       return NULL;
    145     }
    146   else if (version == 1)
    147     {
    148       /* V1 core dumps don't specify the dump base, assume 0 */
    149       rambase = 0;
    150     }
    151   else
    152     {
    153       rambase = bfd_get_32 (abfd, crashinfo.rambase);
    154     }
    155 
    156   /* OK, we believe you.  You're a core file.  */
    157 
    158   amt = sizeof (struct cisco_core_struct);
    159   abfd->tdata.cisco_core_data = (struct cisco_core_struct *) bfd_zmalloc (amt);
    160   if (abfd->tdata.cisco_core_data == NULL)
    161     return NULL;
    162 
    163   switch ((crashreason) bfd_get_32 (abfd, crashinfo.reason))
    164     {
    165     case CRASH_REASON_NOTCRASHED:
    166       /* Crash file probably came from write core.  */
    167       abfd->tdata.cisco_core_data->sig = 0;
    168       break;
    169     case CRASH_REASON_CORRUPT:
    170       /* The crash context area was corrupt -- proceed with caution.
    171 	 We have no way of passing this information back to the caller.  */
    172       abfd->tdata.cisco_core_data->sig = 0;
    173       break;
    174     case CRASH_REASON_EXCEPTION:
    175       /* Crash occured due to CPU exception.  */
    176 
    177       /* This is 68k-specific; for MIPS we'll need to interpret
    178 	 cpu_vector differently based on the target configuration
    179 	 (since CISCO core files don't seem to have the processor
    180 	 encoded in them).  */
    181 
    182       switch (bfd_get_32 (abfd, crashinfo.cpu_vector))
    183 	{
    184 	   /* bus error           */
    185 	case 2 : abfd->tdata.cisco_core_data->sig = SIGBUS; break;
    186 	   /* address error       */
    187 	case 3 : abfd->tdata.cisco_core_data->sig = SIGBUS; break;
    188 	   /* illegal instruction */
    189 	case 4 : abfd->tdata.cisco_core_data->sig = SIGILL;  break;
    190 	   /* zero divide         */
    191 	case 5 : abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    192 	   /* chk instruction     */
    193 	case 6 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
    194 	   /* trapv instruction   */
    195 	case 7 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
    196 	   /* privilege violation */
    197 	case 8 : abfd->tdata.cisco_core_data->sig = SIGSEGV; break;
    198 	   /* trace trap          */
    199 	case 9 : abfd->tdata.cisco_core_data->sig = SIGTRAP;  break;
    200 	   /* line 1010 emulator  */
    201 	case 10: abfd->tdata.cisco_core_data->sig = SIGILL;  break;
    202 	   /* line 1111 emulator  */
    203 	case 11: abfd->tdata.cisco_core_data->sig = SIGILL;  break;
    204 
    205 	  /* Coprocessor protocol violation.  Using a standard MMU or FPU
    206 	     this cannot be triggered by software.  Call it a SIGBUS.  */
    207 	case 13: abfd->tdata.cisco_core_data->sig = SIGBUS;  break;
    208 
    209 	  /* interrupt           */
    210 	case 31: abfd->tdata.cisco_core_data->sig = SIGINT;  break;
    211 	  /* breakpoint          */
    212 	case 33: abfd->tdata.cisco_core_data->sig = SIGTRAP;  break;
    213 
    214 	  /* floating point err  */
    215 	case 48: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    216 	  /* floating point err  */
    217 	case 49: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    218 	  /* zero divide         */
    219 	case 50: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    220 	  /* underflow           */
    221 	case 51: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    222 	  /* operand error       */
    223 	case 52: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    224 	   /* overflow            */
    225 	case 53: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    226 	  /* NAN                 */
    227 	case 54: abfd->tdata.cisco_core_data->sig = SIGFPE;  break;
    228 	default:
    229 #ifndef SIGEMT
    230 #define SIGEMT SIGTRAP
    231 #endif
    232 	  /* "software generated"*/
    233 	  abfd->tdata.cisco_core_data->sig = SIGEMT;
    234 	}
    235       break;
    236     default:
    237       /* Unknown crash reason.  */
    238       abfd->tdata.cisco_core_data->sig = 0;
    239       break;
    240     }
    241 
    242   /* Create a ".data" section that maps the entire file, which is
    243      essentially a dump of the target system's RAM.  */
    244 
    245   flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
    246   asect = bfd_make_section_anyway_with_flags (abfd, ".data", flags);
    247   if (asect == NULL)
    248     goto error_return;
    249   /* The size of memory is the size of the core file itself.  */
    250   asect->size = statbuf.st_size;
    251   asect->vma = rambase;
    252   asect->filepos = 0;
    253 
    254   /* Create a ".crash" section to allow access to the saved
    255      crash information.  */
    256 
    257   flags = SEC_HAS_CONTENTS;
    258   asect = bfd_make_section_anyway_with_flags (abfd, ".crash", flags);
    259   if (asect == NULL)
    260     goto error_return;
    261   asect->vma = 0;
    262   asect->filepos = crashinfo_offset;
    263   asect->size = sizeof (crashinfo);
    264 
    265   /* Create a ".reg" section to allow access to the saved
    266      registers.  */
    267 
    268   asect = bfd_make_section_anyway_with_flags (abfd, ".reg", flags);
    269   if (asect == NULL)
    270     goto error_return;
    271   asect->vma = 0;
    272   asect->filepos = bfd_get_32 (abfd, crashinfo.registers) - rambase;
    273   /* Since we don't know the exact size of the saved register info,
    274      choose a register section size that is either the remaining part
    275      of the file, or 1024, whichever is smaller.  */
    276   nread = statbuf.st_size - asect->filepos;
    277   asect->size = (nread < 1024) ? nread : 1024;
    278 
    279   return abfd->xvec;
    280 
    281   /* Get here if we have already started filling out the BFD
    282      and there is an error of some kind.  */
    283 
    284  error_return:
    285   bfd_release (abfd, abfd->tdata.any);
    286   abfd->tdata.any = NULL;
    287   bfd_section_list_clear (abfd);
    288   return NULL;
    289 }
    290 
    291 static const bfd_target *
    292 cisco_core_file_p (bfd *abfd)
    293 {
    294   int *crash_info_locp;
    295   const bfd_target *target = NULL;
    296 
    297   for (crash_info_locp = crash_info_locs;
    298        *crash_info_locp != -1  &&  target == NULL;
    299        crash_info_locp++)
    300     {
    301       target = cisco_core_file_validate (abfd, *crash_info_locp);
    302     }
    303   return (target);
    304 }
    305 
    306 static char *
    307 cisco_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
    308 {
    309   return NULL;
    310 }
    311 
    312 static int
    313 cisco_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
    314 {
    315   return abfd->tdata.cisco_core_data->sig;
    316 }
    317 
    318 extern const bfd_target core_cisco_le_vec;
    320 
    321 const bfd_target core_cisco_be_vec =
    322 {
    323     "cisco-ios-core-big",
    324     bfd_target_unknown_flavour,
    325     BFD_ENDIAN_BIG,		/* target byte order */
    326     BFD_ENDIAN_BIG,		/* target headers byte order */
    327     (HAS_RELOC | EXEC_P |	/* object flags */
    328      HAS_LINENO | HAS_DEBUG |
    329      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
    330     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
    331     0,				/* symbol prefix */
    332     ' ',			/* ar_pad_char */
    333     16,				/* ar_max_namelen */
    334     0,				/* match priority.  */
    335     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    336     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    337     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
    338     bfd_getb64, bfd_getb_signed_64, bfd_putb64,
    339     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
    340     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
    341 
    342     {				/* bfd_check_format */
    343      _bfd_dummy_target,		/* unknown format */
    344      _bfd_dummy_target,		/* object file */
    345      _bfd_dummy_target,		/* archive */
    346      cisco_core_file_p	/* a core file */
    347     },
    348     {				/* bfd_set_format */
    349      bfd_false, bfd_false,
    350      bfd_false, bfd_false
    351     },
    352     {				/* bfd_write_contents */
    353      bfd_false, bfd_false,
    354      bfd_false, bfd_false
    355     },
    356 
    357        BFD_JUMP_TABLE_GENERIC (_bfd_generic),
    358        BFD_JUMP_TABLE_COPY (_bfd_generic),
    359        BFD_JUMP_TABLE_CORE (cisco),
    360        BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
    361        BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
    362        BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
    363        BFD_JUMP_TABLE_WRITE (_bfd_generic),
    364        BFD_JUMP_TABLE_LINK (_bfd_nolink),
    365        BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    366 
    367     & core_cisco_le_vec,
    368 
    369     NULL	/* backend_data */
    370 };
    371 
    372 const bfd_target core_cisco_le_vec =
    373 {
    374     "cisco-ios-core-little",
    375     bfd_target_unknown_flavour,
    376     BFD_ENDIAN_LITTLE,		/* target byte order */
    377     BFD_ENDIAN_LITTLE,		/* target headers byte order */
    378     (HAS_RELOC | EXEC_P |	/* object flags */
    379      HAS_LINENO | HAS_DEBUG |
    380      HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
    381     (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
    382     0,			                                   /* symbol prefix */
    383     ' ',						   /* ar_pad_char */
    384     16,							   /* ar_max_namelen */
    385     0,				/* match_priority */
    386     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    387     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    388     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
    389     bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    390     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    391     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
    392 
    393     {				/* bfd_check_format */
    394      _bfd_dummy_target,		/* unknown format */
    395      _bfd_dummy_target,		/* object file */
    396      _bfd_dummy_target,		/* archive */
    397      cisco_core_file_p	/* a core file */
    398     },
    399     {				/* bfd_set_format */
    400      bfd_false, bfd_false,
    401      bfd_false, bfd_false
    402     },
    403     {				/* bfd_write_contents */
    404      bfd_false, bfd_false,
    405      bfd_false, bfd_false
    406     },
    407 
    408        BFD_JUMP_TABLE_GENERIC (_bfd_generic),
    409        BFD_JUMP_TABLE_COPY (_bfd_generic),
    410        BFD_JUMP_TABLE_CORE (cisco),
    411        BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
    412        BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
    413        BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
    414        BFD_JUMP_TABLE_WRITE (_bfd_generic),
    415        BFD_JUMP_TABLE_LINK (_bfd_nolink),
    416        BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    417 
    418     &core_cisco_be_vec,
    419 
    420     NULL			/* backend_data */
    421 };
    422