123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- /* BFD back-end for CISCO crash dumps.
- Copyright (C) 1994-2015 Free Software Foundation, Inc.
- This file is part of BFD, the Binary File Descriptor library.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- #include "sysdep.h"
- #include "bfd.h"
- #include "libbfd.h"
- /* core_file_failing_signal returns a host signal (this probably should
- be fixed). */
- #include <signal.h>
- /* for MSVC builds */
- #ifndef SIGTRAP
- # define SIGTRAP 5
- #endif
- #ifndef SIGEMT
- # define SIGEMT 6
- #endif
- #ifndef SIGBUS
- # define SIGBUS 10
- #endif
- int crash_info_locs[] =
- {
- 0x0250, /* mips, ppc, x86, i960 */
- 0x0400, /* m68k, mips, x86, i960 */
- 0x0FFC, /* m68k, mips, ppc, x86, i960 */
- 0x3000, /* ppc */
- 0x4FFC, /* m68k */
- -1
- };
- #define CRASH_MAGIC 0xdead1234
- #define MASK_ADDR(x) ((x) & 0x0fffffff) /* Mask crash info address */
- typedef enum
- {
- CRASH_REASON_NOTCRASHED = 0,
- CRASH_REASON_EXCEPTION = 1,
- CRASH_REASON_CORRUPT = 2,
- } crashreason;
- typedef struct
- {
- char magic[4]; /* Magic number */
- char version[4]; /* Version number */
- char reason[4]; /* Crash reason */
- char cpu_vector[4]; /* CPU vector for exceptions */
- char registers[4]; /* Pointer to saved registers */
- char rambase[4]; /* Base of RAM (not in V1 crash info) */
- char textbase[4]; /* Base of .text section (not in V3 crash info) */
- char database[4]; /* Base of .data section (not in V3 crash info) */
- char bssbase[4]; /* Base of .bss section (not in V3 crash info) */
- } crashinfo_external;
- struct cisco_core_struct
- {
- int sig;
- };
- #define cisco_core_file_matches_executable_p generic_core_file_matches_executable_p
- #define cisco_core_file_pid _bfd_nocore_core_file_pid
- /* Examine the file for a crash info struct at the offset given by
- CRASH_INFO_LOC. */
- static const bfd_target *
- cisco_core_file_validate (bfd *abfd, int crash_info_loc)
- {
- char buf[4];
- unsigned int crashinfo_offset;
- crashinfo_external crashinfo;
- bfd_size_type nread;
- unsigned int magic;
- unsigned int version;
- unsigned int rambase;
- sec_ptr asect;
- struct stat statbuf;
- bfd_size_type amt;
- flagword flags;
- if (bfd_seek (abfd, (file_ptr) crash_info_loc, SEEK_SET) != 0)
- return NULL;
- nread = bfd_bread (buf, (bfd_size_type) 4, abfd);
- if (nread != 4)
- {
- if (bfd_get_error () != bfd_error_system_call)
- bfd_set_error (bfd_error_wrong_format);
- return NULL;
- }
- crashinfo_offset = MASK_ADDR (bfd_get_32 (abfd, buf));
- if (bfd_seek (abfd, (file_ptr) crashinfo_offset, SEEK_SET) != 0)
- {
- /* Most likely we failed because of a bogus (huge) offset */
- bfd_set_error (bfd_error_wrong_format);
- return NULL;
- }
- nread = bfd_bread (&crashinfo, (bfd_size_type) sizeof (crashinfo), abfd);
- if (nread != sizeof (crashinfo))
- {
- if (bfd_get_error () != bfd_error_system_call)
- bfd_set_error (bfd_error_wrong_format);
- return NULL;
- }
- if (bfd_stat (abfd, &statbuf) < 0)
- {
- bfd_set_error (bfd_error_system_call);
- return NULL;
- }
- magic = bfd_get_32 (abfd, crashinfo.magic);
- if (magic != CRASH_MAGIC)
- {
- bfd_set_error (bfd_error_wrong_format);
- return NULL;
- }
- version = bfd_get_32 (abfd, crashinfo.version);
- if (version == 0)
- {
- bfd_set_error (bfd_error_wrong_format);
- return NULL;
- }
- else if (version == 1)
- {
- /* V1 core dumps don't specify the dump base, assume 0 */
- rambase = 0;
- }
- else
- {
- rambase = bfd_get_32 (abfd, crashinfo.rambase);
- }
- /* OK, we believe you. You're a core file. */
- amt = sizeof (struct cisco_core_struct);
- abfd->tdata.cisco_core_data = (struct cisco_core_struct *) bfd_zmalloc (amt);
- if (abfd->tdata.cisco_core_data == NULL)
- return NULL;
- switch ((crashreason) bfd_get_32 (abfd, crashinfo.reason))
- {
- case CRASH_REASON_NOTCRASHED:
- /* Crash file probably came from write core. */
- abfd->tdata.cisco_core_data->sig = 0;
- break;
- case CRASH_REASON_CORRUPT:
- /* The crash context area was corrupt -- proceed with caution.
- We have no way of passing this information back to the caller. */
- abfd->tdata.cisco_core_data->sig = 0;
- break;
- case CRASH_REASON_EXCEPTION:
- /* Crash occured due to CPU exception. */
- /* This is 68k-specific; for MIPS we'll need to interpret
- cpu_vector differently based on the target configuration
- (since CISCO core files don't seem to have the processor
- encoded in them). */
- switch (bfd_get_32 (abfd, crashinfo.cpu_vector))
- {
- /* bus error */
- case 2 : abfd->tdata.cisco_core_data->sig = SIGBUS; break;
- /* address error */
- case 3 : abfd->tdata.cisco_core_data->sig = SIGBUS; break;
- /* illegal instruction */
- case 4 : abfd->tdata.cisco_core_data->sig = SIGILL; break;
- /* zero divide */
- case 5 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* chk instruction */
- case 6 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* trapv instruction */
- case 7 : abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* privilege violation */
- case 8 : abfd->tdata.cisco_core_data->sig = SIGSEGV; break;
- /* trace trap */
- case 9 : abfd->tdata.cisco_core_data->sig = SIGTRAP; break;
- /* line 1010 emulator */
- case 10: abfd->tdata.cisco_core_data->sig = SIGILL; break;
- /* line 1111 emulator */
- case 11: abfd->tdata.cisco_core_data->sig = SIGILL; break;
- /* Coprocessor protocol violation. Using a standard MMU or FPU
- this cannot be triggered by software. Call it a SIGBUS. */
- case 13: abfd->tdata.cisco_core_data->sig = SIGBUS; break;
- /* interrupt */
- case 31: abfd->tdata.cisco_core_data->sig = SIGINT; break;
- /* breakpoint */
- case 33: abfd->tdata.cisco_core_data->sig = SIGTRAP; break;
- /* floating point err */
- case 48: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* floating point err */
- case 49: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* zero divide */
- case 50: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* underflow */
- case 51: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* operand error */
- case 52: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* overflow */
- case 53: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- /* NAN */
- case 54: abfd->tdata.cisco_core_data->sig = SIGFPE; break;
- default:
- #ifndef SIGEMT
- #define SIGEMT SIGTRAP
- #endif
- /* "software generated"*/
- abfd->tdata.cisco_core_data->sig = SIGEMT;
- }
- break;
- default:
- /* Unknown crash reason. */
- abfd->tdata.cisco_core_data->sig = 0;
- break;
- }
- /* Create a ".data" section that maps the entire file, which is
- essentially a dump of the target system's RAM. */
- flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
- asect = bfd_make_section_anyway_with_flags (abfd, ".data", flags);
- if (asect == NULL)
- goto error_return;
- /* The size of memory is the size of the core file itself. */
- asect->size = statbuf.st_size;
- asect->vma = rambase;
- asect->filepos = 0;
- /* Create a ".crash" section to allow access to the saved
- crash information. */
- flags = SEC_HAS_CONTENTS;
- asect = bfd_make_section_anyway_with_flags (abfd, ".crash", flags);
- if (asect == NULL)
- goto error_return;
- asect->vma = 0;
- asect->filepos = crashinfo_offset;
- asect->size = sizeof (crashinfo);
- /* Create a ".reg" section to allow access to the saved
- registers. */
- asect = bfd_make_section_anyway_with_flags (abfd, ".reg", flags);
- if (asect == NULL)
- goto error_return;
- asect->vma = 0;
- asect->filepos = bfd_get_32 (abfd, crashinfo.registers) - rambase;
- /* Since we don't know the exact size of the saved register info,
- choose a register section size that is either the remaining part
- of the file, or 1024, whichever is smaller. */
- nread = statbuf.st_size - asect->filepos;
- asect->size = (nread < 1024) ? nread : 1024;
- return abfd->xvec;
- /* Get here if we have already started filling out the BFD
- and there is an error of some kind. */
- error_return:
- bfd_release (abfd, abfd->tdata.any);
- abfd->tdata.any = NULL;
- bfd_section_list_clear (abfd);
- return NULL;
- }
- static const bfd_target *
- cisco_core_file_p (bfd *abfd)
- {
- int *crash_info_locp;
- const bfd_target *target = NULL;
- for (crash_info_locp = crash_info_locs;
- *crash_info_locp != -1 && target == NULL;
- crash_info_locp++)
- {
- target = cisco_core_file_validate (abfd, *crash_info_locp);
- }
- return (target);
- }
- static char *
- cisco_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
- {
- return NULL;
- }
- static int
- cisco_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
- {
- return abfd->tdata.cisco_core_data->sig;
- }
- extern const bfd_target core_cisco_le_vec;
- const bfd_target core_cisco_be_vec =
- {
- "cisco-ios-core-big",
- bfd_target_unknown_flavour,
- BFD_ENDIAN_BIG, /* target byte order */
- BFD_ENDIAN_BIG, /* target headers byte order */
- (HAS_RELOC | EXEC_P | /* object flags */
- HAS_LINENO | HAS_DEBUG |
- HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
- (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
- 0, /* symbol prefix */
- ' ', /* ar_pad_char */
- 16, /* ar_max_namelen */
- 0, /* match priority. */
- bfd_getb64, bfd_getb_signed_64, bfd_putb64,
- bfd_getb32, bfd_getb_signed_32, bfd_putb32,
- bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
- bfd_getb64, bfd_getb_signed_64, bfd_putb64,
- bfd_getb32, bfd_getb_signed_32, bfd_putb32,
- bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
- { /* bfd_check_format */
- _bfd_dummy_target, /* unknown format */
- _bfd_dummy_target, /* object file */
- _bfd_dummy_target, /* archive */
- cisco_core_file_p /* a core file */
- },
- { /* bfd_set_format */
- bfd_false, bfd_false,
- bfd_false, bfd_false
- },
- { /* bfd_write_contents */
- bfd_false, bfd_false,
- bfd_false, bfd_false
- },
- BFD_JUMP_TABLE_GENERIC (_bfd_generic),
- BFD_JUMP_TABLE_COPY (_bfd_generic),
- BFD_JUMP_TABLE_CORE (cisco),
- BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
- BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
- BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
- BFD_JUMP_TABLE_WRITE (_bfd_generic),
- BFD_JUMP_TABLE_LINK (_bfd_nolink),
- BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
- & core_cisco_le_vec,
- NULL /* backend_data */
- };
- const bfd_target core_cisco_le_vec =
- {
- "cisco-ios-core-little",
- bfd_target_unknown_flavour,
- BFD_ENDIAN_LITTLE, /* target byte order */
- BFD_ENDIAN_LITTLE, /* target headers byte order */
- (HAS_RELOC | EXEC_P | /* object flags */
- HAS_LINENO | HAS_DEBUG |
- HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
- (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
- 0, /* symbol prefix */
- ' ', /* ar_pad_char */
- 16, /* ar_max_namelen */
- 0, /* match_priority */
- bfd_getl64, bfd_getl_signed_64, bfd_putl64,
- bfd_getl32, bfd_getl_signed_32, bfd_putl32,
- bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
- bfd_getl64, bfd_getl_signed_64, bfd_putl64,
- bfd_getl32, bfd_getl_signed_32, bfd_putl32,
- bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
- { /* bfd_check_format */
- _bfd_dummy_target, /* unknown format */
- _bfd_dummy_target, /* object file */
- _bfd_dummy_target, /* archive */
- cisco_core_file_p /* a core file */
- },
- { /* bfd_set_format */
- bfd_false, bfd_false,
- bfd_false, bfd_false
- },
- { /* bfd_write_contents */
- bfd_false, bfd_false,
- bfd_false, bfd_false
- },
- BFD_JUMP_TABLE_GENERIC (_bfd_generic),
- BFD_JUMP_TABLE_COPY (_bfd_generic),
- BFD_JUMP_TABLE_CORE (cisco),
- BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
- BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
- BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
- BFD_JUMP_TABLE_WRITE (_bfd_generic),
- BFD_JUMP_TABLE_LINK (_bfd_nolink),
- BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
- &core_cisco_be_vec,
- NULL /* backend_data */
- };
|