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