/* IBM RS/6000 "XCOFF" back-end for BFD.
- Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+ Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+ 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
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. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This port currently only handles reading object files, except when
compiled on an RS/6000 host. -- no archive support, no core files.
/* Internalcoff.h and coffcode.h modify themselves based on this flag. */
#define RS6000COFF_C 1
+/* The AIX 4.1 kernel is obviously compiled with -D_LONG_LONG, so
+ we have to define _LONG_LONG for older versions of gcc to get the
+ proper alignments in the user structure. */
+#if defined(_AIX41) && !defined(_LONG_LONG)
+#define _LONG_LONG
+#endif
+
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
-#ifdef COREFILES_PLEASE
+#ifdef AIX_CORE
/* 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
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)
+
+/* AIX 4.1 Changed the names and locations of a few items in the core file,
+ this seems to be the quickest easiet way to deal with it.
+
+ Note however that encoding magic addresses (STACK_END_ADDR) is going
+ to be _very_ fragile. But I don't see any easy way to get that info
+ right now. */
+#ifdef CORE_VERSION_1
+#define CORE_DATA_SIZE_FIELD c_u.U_dsize
+#define CORE_COMM_FIELD c_u.U_comm
+#define SAVE_FIELD c_mst
+#define STACK_END_ADDR 0x2ff23000
+#else
+#define CORE_DATA_SIZE_FIELD c_u.u_dsize
+#define CORE_COMM_FIELD c_u.u_comm
+#define SAVE_FIELD c_u.u_save
+#define STACK_END_ADDR 0x2ff80000
+#endif
/* 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)
+ struct core_dump hdr; /* core file header */
} Rs6kCorData;
+static asection *make_bfd_asection PARAMS ((bfd *, CONST char *, flagword,
+ bfd_size_type, bfd_vma, file_ptr));
+
+static asection *
+make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos)
+ bfd *abfd;
+ CONST char *name;
+ flagword flags;
+ bfd_size_type _raw_size;
+ bfd_vma vma;
+ file_ptr filepos;
+{
+ asection *asect;
+
+ asect = bfd_make_section_anyway (abfd, name);
+ if (!asect)
+ return NULL;
+
+ asect->flags = flags;
+ asect->_raw_size = _raw_size;
+ asect->vma = vma;
+ asect->filepos = filepos;
+ asect->alignment_power = 8;
+
+ return asect;
+}
/* Decide if a given bfd represents a `core' file or not. There really is no
magic number or anything like, in rs6000coff. */
-bfd_target *
+const bfd_target *
rs6000coff_core_p (abfd)
bfd *abfd;
{
- int fd;
struct core_dump coredata;
struct stat statbuf;
+ bfd_size_type nread;
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 (bfd_seek (abfd, 0, SEEK_SET) != 0)
+ 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))
+ nread = bfd_read (&coredata, 1, sizeof (struct core_dump), abfd);
+ if (nread != sizeof (struct core_dump))
{
- bfd_error = wrong_format;
- close (fd);
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
return NULL;
}
- if (close (fd) < 0)
+ if (bfd_stat (abfd, &statbuf) < 0)
{
- bfd_error = system_call_error;
+ bfd_set_error (bfd_error_system_call);
return NULL;
}
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).
+ think to check "info files", I don't know).
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
if (!(coredata.c_flag & UBLOCK_VALID)
|| !(coredata.c_flag & LE_VALID))
{
- bfd_error = wrong_format;
+ bfd_set_error (bfd_error_wrong_format);
return NULL;
}
- if ((coredata.c_flag & CORE_TRUNC)
- || !(coredata.c_flag & USTACK_VALID))
+ if (!(coredata.c_flag & USTACK_VALID))
{
- bfd_error = file_truncated;
+ bfd_set_error (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)
+ /* Don't check the core file size for a full core, AIX 4.1 includes
+ additional shared library sections in a full core. */
+ if (!(coredata.c_flag & (FULL_CORE | CORE_TRUNC))
+ && ((bfd_vma)coredata.c_stack + coredata.c_size) != statbuf.st_size)
{
/* If the size is wrong, it means we're misinterpreting something. */
- bfd_error = wrong_format;
+ bfd_set_error (bfd_error_wrong_format);
return NULL;
}
(u_long) coredata.c_tab >= statbuf.st_size ||
(long) coredata.c_tab >= (long)coredata.c_stack)
{
- bfd_error = wrong_format;
+ bfd_set_error (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));
+ /* Issue warning if the core file was truncated during writing. */
+ if (coredata.c_flag & CORE_TRUNC)
+ (*_bfd_error_handler) (_("%s: warning core file truncated"),
+ bfd_get_filename (abfd));
+
+ /* Allocate core file header. */
+ tmpptr = (char*) bfd_zalloc (abfd, sizeof (Rs6kCorData));
if (!tmpptr)
- {
- bfd_error = no_memory;
- return NULL;
- }
+ return NULL;
set_tdata (abfd, tmpptr);
+ /* Copy core file header. */
+ core_hdr (abfd) = coredata;
+
/* .stack section. */
- if ((core_stacksec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection)))
- == NULL) {
- bfd_error = no_memory;
- /* bfd_release (abfd, ???? ) */
+ if (!make_bfd_asection (abfd, ".stack",
+ SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS,
+ (bfd_size_type) coredata.c_size,
+ (bfd_vma) (STACK_END_ADDR - coredata.c_size),
+ (file_ptr) coredata.c_stack))
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, ???? ) */
+ if (!make_bfd_asection (abfd, ".reg",
+ SEC_HAS_CONTENTS,
+ (bfd_size_type) ((32 + NUM_OF_SPEC_REGS) * 4),
+ (bfd_vma) 0,
+ (file_ptr) ((char *) &coredata.SAVE_FIELD
+ - (char *) &coredata)))
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, ???? ) */
+ if (!make_bfd_asection (abfd, ".reg2",
+ SEC_HAS_CONTENTS,
+ (bfd_size_type) 8 * 32, /* 32 FPRs. */
+ (bfd_vma) 0,
+ (file_ptr) ((char *) &coredata.SAVE_FIELD.fpr[0]
+ - (char *) &coredata)))
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
+
+ /* .ldinfo section.
+ 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 (!make_bfd_asection (abfd, ".ldinfo",
+ SEC_HAS_CONTENTS,
+ (bfd_size_type) 0x7fffffff,
+ (bfd_vma) 0,
+ (file_ptr) coredata.c_tab))
+ return NULL;
+#ifndef CORE_VERSION_1
+ /* .data section if present.
+ AIX 3 dumps the complete data section and sets FULL_CORE if the
+ ulimit is large enough, otherwise the data section is omitted.
+ AIX 4 sets FULL_CORE even if the core file is truncated, we have
+ to examine coredata.c_datasize below to find out the actual size of
+ the .data section. */
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;
+ if (!make_bfd_asection (abfd, ".data",
+ SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS,
+ (bfd_size_type) coredata.CORE_DATA_SIZE_FIELD,
+ (bfd_vma)
+ CDATA_ADDR (coredata.CORE_DATA_SIZE_FIELD),
+ (file_ptr) coredata.c_stack + coredata.c_size))
+ return NULL;
}
+#endif
+
+#ifdef CORE_VERSION_1
+ /* AIX 4 adds data sections from loaded objects to the core file,
+ which can be found by examining ldinfo, and anonymously mmapped
+ regions. */
+ {
+ struct ld_info ldinfo;
+ bfd_size_type ldinfo_size;
+ file_ptr ldinfo_offset = (file_ptr) coredata.c_tab;
+
+ /* .data section from executable. */
+ if (coredata.c_datasize)
+ {
+ if (!make_bfd_asection (abfd, ".data",
+ SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS,
+ (bfd_size_type) coredata.c_datasize,
+ (bfd_vma)
+ CDATA_ADDR (coredata.CORE_DATA_SIZE_FIELD),
+ (file_ptr) coredata.c_data))
+ return NULL;
+ }
+
+ /* .data sections from loaded objects. */
+ ldinfo_size = (char *) &ldinfo.ldinfo_filename[0]
+ - (char *) &ldinfo.ldinfo_next;
+ while (1)
+ {
+ if (bfd_seek (abfd, ldinfo_offset, SEEK_SET) != 0)
+ return NULL;
+ if (bfd_read (&ldinfo, ldinfo_size, 1, abfd) != ldinfo_size)
+ return NULL;
+ if (ldinfo.ldinfo_core)
+ {
+ if (!make_bfd_asection (abfd, ".data",
+ SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS,
+ (bfd_size_type) ldinfo.ldinfo_datasize,
+ (bfd_vma) ldinfo.ldinfo_dataorg,
+ (file_ptr) ldinfo.ldinfo_core))
+ return NULL;
+ }
+ if (ldinfo.ldinfo_next == 0)
+ break;
+ ldinfo_offset += ldinfo.ldinfo_next;
+ }
+
+ /* .vmdata sections from anonymously mmapped regions. */
+ if (coredata.c_vmregions)
+ {
+ int i;
+
+ if (bfd_seek (abfd, (file_ptr) coredata.c_vmm, SEEK_SET) != 0)
+ return NULL;
+
+ for (i = 0; i < coredata.c_vmregions; i++)
+ {
+ struct vm_info vminfo;
+
+ if (bfd_read (&vminfo, sizeof (vminfo), 1, abfd) != sizeof (vminfo))
+ return NULL;
+ if (vminfo.vminfo_offset)
+ {
+ if (!make_bfd_asection (abfd, ".vmdata",
+ SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS,
+ (bfd_size_type) vminfo.vminfo_size,
+ (bfd_vma) vminfo.vminfo_addr,
+ (file_ptr) vminfo.vminfo_offset))
+ return NULL;
+ }
+ }
+ }
+ }
+#endif
return abfd->xvec; /* this is garbage for now. */
}
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);
+ bfd_size_type size;
+ char *path, *s;
+ size_t alloc;
+ const char *str1, *str2;
+ boolean ret;
+
+ if (bfd_seek (core_bfd, 0, SEEK_SET) != 0
+ || bfd_read (&coredata, sizeof coredata, 1, core_bfd) != sizeof coredata)
+ return false;
+
+ if (bfd_seek (core_bfd, (long) coredata.c_tab, SEEK_SET) != 0)
+ return false;
+
+ size = (char *) &ldinfo.ldinfo_filename[0] - (char *) &ldinfo.ldinfo_next;
+ if (bfd_read (&ldinfo, size, 1, core_bfd) != size)
+ return false;
+
+ alloc = 100;
+ path = bfd_malloc (alloc);
+ if (path == NULL)
+ return false;
+ s = path;
+
+ while (1)
+ {
+ if (bfd_read (s, 1, 1, core_bfd) != 1)
+ {
+ free (path);
+ return false;
+ }
+ if (*s == '\0')
+ break;
+ ++s;
+ if (s == path + alloc)
+ {
+ char *n;
+
+ alloc *= 2;
+ n = bfd_realloc (path, alloc);
+ if (n == NULL)
+ {
+ free (path);
+ return false;
+ }
+ s = n + (path - s);
+ path = n;
+ }
+ }
- str1 = strrchr (pathname, '/');
+ str1 = strrchr (path, '/');
str2 = strrchr (exec_bfd->filename, '/');
/* step over character '/' */
- str1 = str1 ? str1+1 : &pathname[0];
- str2 = str2 ? str2+1 : exec_bfd->filename;
+ str1 = str1 != NULL ? str1 + 1 : path;
+ str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename;
+
+ if (strcmp (str1, str2) == 0)
+ ret = true;
+ else
+ ret = false;
- fclose (fd);
- return strcmp (str1, str2) == 0;
+ free (path);
+
+ return ret;
+}
+
+char *
+rs6000coff_core_file_failing_command (abfd)
+ bfd *abfd;
+{
+ char *com = core_hdr (abfd).CORE_COMM_FIELD;
+ if (*com)
+ return com;
+ else
+ return 0;
+}
+
+int
+rs6000coff_core_file_failing_signal (abfd)
+ bfd *abfd;
+{
+ return core_hdr (abfd).c_signo;
}
sec_ptr section;
PTR location;
file_ptr offset;
- int count;
+ bfd_size_type count;
{
if (count == 0)
return true;
/* 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");
+ (*_bfd_error_handler)
+ (_("ERROR! in rs6000coff_get_section_contents()\n"));
/* for `.reg' section, `filepos' is a pointer to the `mstsave' structure
in the core file. */
/* else, use default bfd section content transfer. */
else
- return bfd_generic_get_section_contents
+ return _bfd_generic_get_section_contents
(abfd, section, location, offset, count);
}
-#endif /* COREFILES_PLEASE */
+#endif /* AIX_CORE */