diff options
Diffstat (limited to 'bfd/rs6000-core.c')
-rw-r--r-- | bfd/rs6000-core.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/bfd/rs6000-core.c b/bfd/rs6000-core.c new file mode 100644 index 0000000..880cd91 --- /dev/null +++ b/bfd/rs6000-core.c @@ -0,0 +1,374 @@ +/* IBM RS/6000 "XCOFF" back-end for BFD. + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + FIXME: Can someone provide a transliteration of this name into ASCII? + Using the following chars caused a compiler warning on HIUX (so I replaced + them with octal escapes), and isn't useful without an understanding of what + character set it is. + Written by Metin G. Ozisik, Mimi Ph\373\364ng-Th\345o V\365, + and John Gilmore. + Archive support from Damon A. Permezel. + Contributed by IBM Corporation and Cygnus Support. + +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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This port currently only handles reading object files, except when + compiled on an RS/6000 host. -- no archive support, no core files. + In all cases, it does not support writing. + + FIXMEmgo comments are left from Metin Ozisik's original port. + + This is in a separate file from coff-rs6000.c, because it includes + system include files that conflict with coff/rs6000.h. + */ + +/* Internalcoff.h and coffcode.h modify themselves based on this flag. */ +#define RS6000COFF_C 1 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifdef COREFILES_PLEASE + +/* AOUTHDR is defined by the above. We need another defn of it, from the + system include files. Punt the old one and get us a new name for the + typedef in the system include files. */ +#ifdef AOUTHDR +#undef AOUTHDR +#endif +#define AOUTHDR second_AOUTHDR + +#undef SCNHDR + + +/* ------------------------------------------------------------------------ */ +/* Support for core file stuff.. */ +/* ------------------------------------------------------------------------ */ + +#include <sys/user.h> +#include <sys/ldr.h> +#include <sys/core.h> + + +/* Number of special purpose registers supported by gdb. This value + should match `tm.h' in gdb directory. Clean this mess up and use + the macros in sys/reg.h. FIXMEmgo. */ + +#define NUM_OF_SPEC_REGS 7 +#define STACK_END_ADDR 0x2ff80000 + +#define core_hdr(bfd) (((Rs6kCorData*)(bfd->tdata.any))->hdr) +#define core_datasec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->data_section) +#define core_stacksec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->stack_section) +#define core_regsec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->reg_section) +#define core_reg2sec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->reg2_section) + +/* These are stored in the bfd's tdata */ +typedef struct { + struct core *hdr; /* core file header */ + asection *data_section, + *stack_section, + *reg_section, /* section for GPRs and special registers. */ + *reg2_section; /* section for FPRs. */ + + /* This tells us where everything is mapped (shared libraries and so on). + GDB needs it. */ + asection *ldinfo_section; +#define core_ldinfosec(bfd) (((Rs6kCorData *)(bfd->tdata.any))->ldinfo_section) +} Rs6kCorData; + + +/* Decide if a given bfd represents a `core' file or not. There really is no + magic number or anything like, in rs6000coff. */ + +bfd_target * +rs6000coff_core_p (abfd) + bfd *abfd; +{ + int fd; + struct core_dump coredata; + struct stat statbuf; + char *tmpptr; + + /* Use bfd_xxx routines, rather than O/S primitives to read coredata. FIXMEmgo */ + fd = open (abfd->filename, O_RDONLY); + if (fd < 0) + { + bfd_error = system_call_error; + return NULL; + } + + if (fstat (fd, &statbuf) < 0) + { + bfd_error = system_call_error; + close (fd); + return NULL; + } + if (read (fd, &coredata, sizeof (struct core_dump)) + != sizeof (struct core_dump)) + { + bfd_error = wrong_format; + close (fd); + return NULL; + } + + if (close (fd) < 0) + { + bfd_error = system_call_error; + return NULL; + } + + /* If the core file ulimit is too small, the system will first + omit the data segment, then omit the stack, then decline to + dump core altogether (as far as I know UBLOCK_VALID and LE_VALID + are always set) (this is based on experimentation on AIX 3.2). + Now, the thing is that GDB users will be surprised + if segments just silently don't appear (well, maybe they would + think to check "info files", I don't know), but we have no way of + returning warnings (as opposed to errors). + + For the data segment, we have no choice but to keep going if it's + not there, since the default behavior is not to dump it (regardless + of the ulimit, it's based on SA_FULLDUMP). But for the stack segment, + if it's not there, we refuse to have anything to do with this core + file. The usefulness of a core dump without a stack segment is pretty + limited anyway. */ + + if (!(coredata.c_flag & UBLOCK_VALID) + || !(coredata.c_flag & LE_VALID)) + { + bfd_error = wrong_format; + return NULL; + } + + if ((coredata.c_flag & CORE_TRUNC) + || !(coredata.c_flag & USTACK_VALID)) + { + bfd_error = file_truncated; + return NULL; + } + + if (((bfd_vma)coredata.c_stack + coredata.c_size + + ((coredata.c_flag & FULL_CORE) ? coredata.c_u.u_dsize : 0)) + != statbuf.st_size) + { + /* If the size is wrong, it means we're misinterpreting something. */ + bfd_error = wrong_format; + return NULL; + } + + /* Sanity check on the c_tab field. */ + if ((u_long) coredata.c_tab < sizeof coredata || + (u_long) coredata.c_tab >= statbuf.st_size || + (long) coredata.c_tab >= (long)coredata.c_stack) + { + bfd_error = wrong_format; + return NULL; + } + + /* maybe you should alloc space for the whole core chunk over here!! FIXMEmgo */ + tmpptr = (char*)bfd_zalloc (abfd, sizeof (Rs6kCorData)); + if (!tmpptr) + { + bfd_error = no_memory; + return NULL; + } + + set_tdata (abfd, tmpptr); + + /* .stack section. */ + if ((core_stacksec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) { + bfd_error = no_memory; + /* bfd_release (abfd, ???? ) */ + return NULL; + } + core_stacksec (abfd)->name = ".stack"; + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD; + core_stacksec (abfd)->_raw_size = coredata.c_size; + core_stacksec (abfd)->vma = STACK_END_ADDR - coredata.c_size; + core_stacksec (abfd)->filepos = (int)coredata.c_stack; /*???? */ + + /* .reg section for GPRs and special registers. */ + if ((core_regsec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) { + bfd_error = no_memory; + /* bfd_release (abfd, ???? ) */ + return NULL; + } + core_regsec (abfd)->name = ".reg"; + core_regsec (abfd)->flags = SEC_ALLOC; + core_regsec (abfd)->_raw_size = (32 + NUM_OF_SPEC_REGS) * 4; + core_regsec (abfd)->vma = 0; /* not used?? */ + core_regsec (abfd)->filepos = + (char*)&coredata.c_u.u_save - (char*)&coredata; + + /* .reg2 section for FPRs (floating point registers). */ + if ((core_reg2sec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) { + bfd_error = no_memory; + /* bfd_release (abfd, ???? ) */ + return NULL; + } + core_reg2sec (abfd)->name = ".reg2"; + core_reg2sec (abfd)->flags = SEC_ALLOC; + core_reg2sec (abfd)->_raw_size = 8 * 32; /* 32 FPRs. */ + core_reg2sec (abfd)->vma = 0; /* not used?? */ + core_reg2sec (abfd)->filepos = + (char*)&coredata.c_u.u_save.fpr[0] - (char*)&coredata; + + if ((core_ldinfosec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) { + bfd_error = no_memory; + /* bfd_release (abfd, ???? ) */ + return NULL; + } + core_ldinfosec (abfd)->name = ".ldinfo"; + core_ldinfosec (abfd)->flags = SEC_ALLOC + SEC_LOAD; + /* To actually find out how long this section is in this particular + core dump would require going down the whole list of struct ld_info's. + See if we can just fake it. */ + core_ldinfosec (abfd)->_raw_size = 0x7fffffff; + /* Not relevant for ldinfo section. */ + core_ldinfosec (abfd)->vma = 0; + core_ldinfosec (abfd)->filepos = coredata.c_tab; + + /* set up section chain here. */ + abfd->section_count = 4; + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_regsec(abfd); + core_regsec (abfd)->next = core_reg2sec (abfd); + core_reg2sec (abfd)->next = core_ldinfosec (abfd); + core_ldinfosec (abfd)->next = NULL; + + if (coredata.c_flag & FULL_CORE) + { + asection *sec = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (sec == NULL) + { + bfd_error = no_memory; + return NULL; + } + sec->name = ".data"; + sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; + sec->_raw_size = coredata.c_u.u_dsize; + sec->vma = CDATA_ADDR (coredata.c_u.u_dsize); + sec->filepos = (int)coredata.c_stack + coredata.c_size; + + sec->next = abfd->sections; + abfd->sections = sec; + ++abfd->section_count; + } + + return abfd->xvec; /* this is garbage for now. */ +} + + + +/* return `true' if given core is from the given executable.. */ +boolean +rs6000coff_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ + FILE *fd; + struct core_dump coredata; + struct ld_info ldinfo; + char pathname [1024]; + char *str1, *str2; + + /* Use bfd_xxx routines, rather than O/S primitives, do error checking!! + FIXMEmgo */ + /* Actually should be able to use bfd_get_section_contents now that + we have a .ldinfo section. */ + fd = fopen (core_bfd->filename, FOPEN_RB); + + fread (&coredata, sizeof (struct core_dump), 1, fd); + fseek (fd, (long)coredata.c_tab, 0); + fread (&ldinfo, (char*)&ldinfo.ldinfo_filename[0] - (char*)&ldinfo.ldinfo_next, + 1, fd); + fscanf (fd, "%s", pathname); + + str1 = strrchr (pathname, '/'); + str2 = strrchr (exec_bfd->filename, '/'); + + /* step over character '/' */ + str1 = str1 ? str1+1 : &pathname[0]; + str2 = str2 ? str2+1 : exec_bfd->filename; + + fclose (fd); + return strcmp (str1, str2) == 0; +} + + +boolean +rs6000coff_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + int count; +{ + if (count == 0) + return true; + + /* Reading a core file's sections will be slightly different. For the + rest of them we can use bfd_generic_get_section_contents () I suppose. */ + /* Make sure this routine works for any bfd and any section. FIXMEmgo. */ + + if (abfd->format == bfd_core && strcmp (section->name, ".reg") == 0) { + + struct mstsave mstatus; + int regoffset = (char*)&mstatus.gpr[0] - (char*)&mstatus; + + /* Assert that the only way this code will be executed is reading the + whole section. */ + if (offset || count != (sizeof(mstatus.gpr) + (4 * NUM_OF_SPEC_REGS))) + fprintf (stderr, "ERROR! in rs6000coff_get_section_contents()\n"); + + /* for `.reg' section, `filepos' is a pointer to the `mstsave' structure + in the core file. */ + + /* read GPR's into the location. */ + if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 + || bfd_read(location, sizeof (mstatus.gpr), 1, abfd) != sizeof (mstatus.gpr)) + return (false); /* on error */ + + /* increment location to the beginning of special registers in the section, + reset register offset value to the beginning of first special register + in mstsave structure, and read special registers. */ + + location = (PTR) ((char*)location + sizeof (mstatus.gpr)); + regoffset = (char*)&mstatus.iar - (char*)&mstatus; + + if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 + || bfd_read(location, 4 * NUM_OF_SPEC_REGS, 1, abfd) != + 4 * NUM_OF_SPEC_REGS) + return (false); /* on error */ + + /* increment location address, and read the special registers.. */ + /* FIXMEmgo */ + return (true); + } + + /* else, use default bfd section content transfer. */ + else + return bfd_generic_get_section_contents + (abfd, section, location, offset, count); +} + +#endif /* COREFILES_PLEASE */ |