|  | /* IBM RS/6000 "XCOFF" back-end for BFD. | 
|  | Copyright (C) 1990-2025 Free Software Foundation, Inc. | 
|  | Written by Metin G. Ozisik, Mimi Phuong-Thao Vo, 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 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.  */ | 
|  |  | 
|  |  | 
|  | /* 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. | 
|  |  | 
|  | 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 | 
|  |  | 
|  | /* 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 "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "libbfd.h" | 
|  |  | 
|  | #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 | 
|  | 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> | 
|  | #define __LDINFO_PTRACE32__	/* for __ld_info32 */ | 
|  | #define __LDINFO_PTRACE64__	/* for __ld_info64 */ | 
|  | #include <sys/ldr.h> | 
|  | #include <sys/core.h> | 
|  | #include <sys/systemcfg.h> | 
|  |  | 
|  | /* Borrowed from <sys/inttypes.h> on recent AIX versions.  */ | 
|  | typedef unsigned long ptr_to_uint; | 
|  |  | 
|  | #define	core_hdr(bfd)		((CoreHdr *) bfd->tdata.any) | 
|  |  | 
|  | /* AIX 4.1 changed the names and locations of a few items in the core file. | 
|  | AIX 4.3 defined an entirely new structure, core_dumpx, but kept support for | 
|  | the previous 4.1 structure, core_dump. | 
|  |  | 
|  | AIX_CORE_DUMPX_CORE is defined (by configure) on AIX 4.3+, and | 
|  | CORE_VERSION_1 is defined (by AIX core.h) as 2 on AIX 4.3+ and as 1 on AIX | 
|  | 4.1 and 4.2.  AIX pre-4.1 (aka 3.x) either doesn't define CORE_VERSION_1 | 
|  | or else defines it as 0.  */ | 
|  |  | 
|  | #if defined(CORE_VERSION_1) && !CORE_VERSION_1 | 
|  | # undef CORE_VERSION_1 | 
|  | #endif | 
|  |  | 
|  | /* The following union and macros allow this module to compile on all AIX | 
|  | versions and to handle both core_dumpx and core_dump on 4.3+.  CNEW_*() | 
|  | and COLD_*() macros respectively retrieve core_dumpx and core_dump | 
|  | values.  */ | 
|  |  | 
|  | /* Union of 32-bit and 64-bit versions of ld_info.  */ | 
|  |  | 
|  | typedef union | 
|  | { | 
|  | #if defined (__ld_info32) || defined (__ld_info64) | 
|  | struct __ld_info32 l32; | 
|  | struct __ld_info64 l64; | 
|  | #else | 
|  | struct ld_info l32; | 
|  | struct ld_info l64; | 
|  | #endif | 
|  | } LdInfo; | 
|  |  | 
|  | /* Union of old and new core dump structures.  */ | 
|  |  | 
|  | typedef union | 
|  | { | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | struct core_dumpx new_dump;	/* New AIX 4.3+ core dump.  */ | 
|  | #else | 
|  | struct core_dump new_dump;	/* For simpler coding.  */ | 
|  | #endif | 
|  | #ifndef BFD64			/* Use old only if gdb is 32-bit.  */ | 
|  | struct core_dump old;		/* Old AIX 4.2- core dump, still used on | 
|  | 4.3+ with appropriate SMIT config.  */ | 
|  | #endif | 
|  | } CoreHdr; | 
|  |  | 
|  | /* Union of old and new vm_info structures.  */ | 
|  |  | 
|  | #ifdef CORE_VERSION_1 | 
|  | typedef union | 
|  | { | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | struct vm_infox new_dump; | 
|  | #else | 
|  | struct vm_info new_dump; | 
|  | #endif | 
|  | #ifndef BFD64 | 
|  | struct vm_info old; | 
|  | #endif | 
|  | } VmInfo; | 
|  | #endif | 
|  |  | 
|  | /* Return whether CoreHdr C is in new or old format.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # ifndef BFD64 | 
|  | #  define CORE_NEW(c)	(!(c).old.c_entries) | 
|  | # else | 
|  | #  define CORE_NEW(c)	1 | 
|  | # endif | 
|  | #else | 
|  | # define CORE_NEW(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return whether CoreHdr C usese core_dumpxx structure. | 
|  |  | 
|  | FIXME: the core file format version number used here definitely indicates | 
|  | that struct core_dumpxx should be used to represent the core file header, | 
|  | but that may not be the only such format version number.  */ | 
|  |  | 
|  | #ifdef AIX_5_CORE | 
|  | # define CORE_DUMPXX_VERSION	267312562 | 
|  | # define CNEW_IS_CORE_DUMPXX(c) ((c).new_dump.c_version == CORE_DUMPXX_VERSION) | 
|  | #else | 
|  | # define CNEW_IS_CORE_DUMPXX(c) 0 | 
|  | #endif | 
|  |  | 
|  | /* Return the c_stackorg field from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_STACKORG(c)	(c).c_stackorg | 
|  | #else | 
|  | # define CNEW_STACKORG(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the offset to the loader region from struct core_dump C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_LOADER(c)	(c).c_loader | 
|  | #else | 
|  | # define CNEW_LOADER(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the offset to the loader region from struct core_dump C.  */ | 
|  |  | 
|  | #define COLD_LOADER(c)	(c).c_tab | 
|  |  | 
|  | /* Return the c_lsize field from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_LSIZE(c)	(c).c_lsize | 
|  | #else | 
|  | # define CNEW_LSIZE(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the c_dataorg field from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_DATAORG(c)	(c).c_dataorg | 
|  | #else | 
|  | # define CNEW_DATAORG(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the c_datasize field from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_DATASIZE(c)	(c).c_datasize | 
|  | #else | 
|  | # define CNEW_DATASIZE(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the c_impl field from struct core_dumpx C.  */ | 
|  |  | 
|  | #if defined (HAVE_ST_C_IMPL) || defined (AIX_5_CORE) | 
|  | # define CNEW_IMPL(c)	(c).c_impl | 
|  | #else | 
|  | # define CNEW_IMPL(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the command string from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_COMM(c)	(c).c_u.U_proc.pi_comm | 
|  | #else | 
|  | # define CNEW_COMM(c)	0 | 
|  | #endif | 
|  |  | 
|  | /* Return the command string from struct core_dump C.  */ | 
|  |  | 
|  | #ifdef CORE_VERSION_1 | 
|  | # define COLD_COMM(c)	(c).c_u.U_comm | 
|  | #else | 
|  | # define COLD_COMM(c)	(c).c_u.u_comm | 
|  | #endif | 
|  |  | 
|  | /* Return the struct __context64 pointer from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_CONTEXT64(c)	(c).c_flt.hctx.r64 | 
|  | #else | 
|  | # define CNEW_CONTEXT64(c)	c | 
|  | #endif | 
|  |  | 
|  | /* Return the struct mstsave pointer from struct core_dumpx C.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_MSTSAVE(c)	(c).c_flt.hctx.r32 | 
|  | #else | 
|  | # define CNEW_MSTSAVE(c)	c | 
|  | #endif | 
|  |  | 
|  | /* Return the struct mstsave pointer from struct core_dump C.  */ | 
|  |  | 
|  | #ifdef CORE_VERSION_1 | 
|  | # define COLD_MSTSAVE(c)	(c).c_mst | 
|  | #else | 
|  | # define COLD_MSTSAVE(c)	(c).c_u.u_save | 
|  | #endif | 
|  |  | 
|  | /* Return whether struct core_dumpx is from a 64-bit process.  */ | 
|  |  | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | # define CNEW_PROC64(c)		IS_PROC64(&(c).c_u.U_proc) | 
|  | #else | 
|  | # define CNEW_PROC64(c)		0 | 
|  | #endif | 
|  |  | 
|  | /* Magic end-of-stack addresses for old core dumps.  This is _very_ fragile, | 
|  | but I don't see any easy way to get that info right now.  */ | 
|  |  | 
|  | #ifdef CORE_VERSION_1 | 
|  | # define COLD_STACKEND	0x2ff23000 | 
|  | #else | 
|  | # define COLD_STACKEND	0x2ff80000 | 
|  | #endif | 
|  |  | 
|  | /* Size of the leading portion that old and new core dump structures have in | 
|  | common.  */ | 
|  | #ifdef AIX_CORE_DUMPX_CORE | 
|  | #define CORE_COMMONSZ  ((long) &((struct core_dumpx *) 0)->c_entries \ | 
|  | + sizeof (((struct core_dumpx *) 0)->c_entries)) | 
|  | #else | 
|  | #define CORE_COMMONSZ  ((int) &((struct core_dump *) 0)->c_entries \ | 
|  | + sizeof (((struct core_dump *) 0)->c_entries)) | 
|  | #endif | 
|  | /* Define prototypes for certain functions, to avoid a compiler warning | 
|  | saying that they are missing.  */ | 
|  |  | 
|  | bfd_cleanup rs6000coff_core_p (bfd *abfd); | 
|  | bool rs6000coff_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd); | 
|  | char * rs6000coff_core_file_failing_command (bfd *abfd); | 
|  | int rs6000coff_core_file_failing_signal (bfd *abfd); | 
|  |  | 
|  | /* Try to read into CORE the header from the core file associated with ABFD. | 
|  | Return success.  */ | 
|  |  | 
|  | static bool | 
|  | read_hdr (bfd *abfd, CoreHdr *core) | 
|  | { | 
|  | bfd_size_type size; | 
|  |  | 
|  | if (bfd_seek (abfd, 0, SEEK_SET) != 0) | 
|  | return false; | 
|  |  | 
|  | /* Read the leading portion that old and new core dump structures have in | 
|  | common.  */ | 
|  | size = CORE_COMMONSZ; | 
|  | if (bfd_read (core, size, abfd) != size) | 
|  | return false; | 
|  |  | 
|  | /* Read the trailing portion of the structure.  */ | 
|  | if (CORE_NEW (*core)) | 
|  | size = sizeof (core->new_dump); | 
|  | #ifndef BFD64 | 
|  | else | 
|  | size = sizeof (core->old); | 
|  | #endif | 
|  | size -= CORE_COMMONSZ; | 
|  | return bfd_read ((char *) core + CORE_COMMONSZ, size, abfd) == size; | 
|  | } | 
|  |  | 
|  | static asection * | 
|  | make_bfd_asection (bfd *abfd, const char *name, flagword flags, | 
|  | bfd_size_type size, bfd_vma vma, file_ptr filepos) | 
|  | { | 
|  | asection *asect; | 
|  |  | 
|  | asect = bfd_make_section_anyway_with_flags (abfd, name, flags); | 
|  | if (!asect) | 
|  | return NULL; | 
|  |  | 
|  | asect->size = 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_cleanup | 
|  | rs6000coff_core_p (bfd *abfd) | 
|  | { | 
|  | CoreHdr core; | 
|  | struct stat statbuf; | 
|  | bfd_size_type size; | 
|  | char *tmpptr; | 
|  |  | 
|  | /* Values from new and old core structures.  */ | 
|  | int c_flag; | 
|  | file_ptr c_stack, c_regoff, c_loader; | 
|  | bfd_size_type c_size, c_regsize, c_lsize, c_extoff; | 
|  | bfd_vma c_stackend; | 
|  | void *c_regptr; | 
|  | int proc64; | 
|  |  | 
|  | if (!read_hdr (abfd, &core)) | 
|  | { | 
|  | if (bfd_get_error () != bfd_error_system_call) | 
|  | bfd_set_error (bfd_error_wrong_format); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* This isn't the right handler for 64-bit core files on AIX 5.x.  */ | 
|  | if (CORE_NEW (core) && CNEW_IS_CORE_DUMPXX (core)) | 
|  | { | 
|  | bfd_set_error (bfd_error_wrong_format); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Copy fields from new or old core structure.  */ | 
|  | if (CORE_NEW (core)) | 
|  | { | 
|  | c_flag = core.new_dump.c_flag; | 
|  | c_stack = (file_ptr) core.new_dump.c_stack; | 
|  | c_size = core.new_dump.c_size; | 
|  | c_stackend = CNEW_STACKORG (core.new_dump) + c_size; | 
|  | c_lsize = CNEW_LSIZE (core.new_dump); | 
|  | c_loader = CNEW_LOADER (core.new_dump); | 
|  | c_extoff = core.new_dump.c_extctx; | 
|  | #ifndef BFD64 | 
|  | proc64 = CNEW_PROC64 (core.new_dump); | 
|  | } | 
|  | else | 
|  | { | 
|  | c_flag = core.old.c_flag; | 
|  | c_stack = (file_ptr) (ptr_to_uint) core.old.c_stack; | 
|  | c_size = core.old.c_size; | 
|  | c_stackend = COLD_STACKEND; | 
|  | c_lsize = 0x7ffffff; | 
|  | c_loader = (file_ptr) (ptr_to_uint) COLD_LOADER (core.old); | 
|  | #endif | 
|  | proc64 = 0; | 
|  | } | 
|  |  | 
|  | if (proc64) | 
|  | { | 
|  | c_regsize = sizeof (CNEW_CONTEXT64 (core.new_dump)); | 
|  | c_regptr = &CNEW_CONTEXT64 (core.new_dump); | 
|  | } | 
|  | else if (CORE_NEW (core)) | 
|  | { | 
|  | c_regsize = sizeof (CNEW_MSTSAVE (core.new_dump)); | 
|  | c_regptr = &CNEW_MSTSAVE (core.new_dump); | 
|  | } | 
|  | #ifndef BFD64 | 
|  | else | 
|  | { | 
|  | c_regsize = sizeof (COLD_MSTSAVE (core.old)); | 
|  | c_regptr = &COLD_MSTSAVE (core.old); | 
|  | } | 
|  | #endif | 
|  | c_regoff = (char *) c_regptr - (char *) &core; | 
|  |  | 
|  | if (bfd_stat (abfd, &statbuf) < 0) | 
|  | { | 
|  | bfd_set_error (bfd_error_system_call); | 
|  | 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). | 
|  |  | 
|  | 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 (!(c_flag & UBLOCK_VALID) | 
|  | || !(c_flag & LE_VALID)) | 
|  | { | 
|  | bfd_set_error (bfd_error_wrong_format); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (!(c_flag & USTACK_VALID)) | 
|  | { | 
|  | bfd_set_error (bfd_error_file_truncated); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Don't check the core file size for a full core, AIX 4.1 includes | 
|  | additional shared library sections in a full core.  */ | 
|  | if (!(c_flag & (FULL_CORE | CORE_TRUNC))) | 
|  | { | 
|  | /* If the size is wrong, it means we're misinterpreting something.  */ | 
|  | if (c_stack + (file_ptr) c_size != statbuf.st_size) | 
|  | { | 
|  | bfd_set_error (bfd_error_wrong_format); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Sanity check on the c_tab field.  */ | 
|  | if (!CORE_NEW (core) | 
|  | && ( | 
|  | #ifndef BFD64 | 
|  | c_loader < (file_ptr) sizeof core.old | 
|  | #else | 
|  | c_loader < (file_ptr) sizeof core.new_dump | 
|  | #endif | 
|  | || c_loader >= statbuf.st_size | 
|  | || c_loader >= c_stack)) | 
|  | { | 
|  | bfd_set_error (bfd_error_wrong_format); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Issue warning if the core file was truncated during writing.  */ | 
|  | if (c_flag & CORE_TRUNC) | 
|  | _bfd_error_handler (_("%pB: warning core file truncated"), abfd); | 
|  |  | 
|  | /* Allocate core file header.  */ | 
|  | #ifndef BFD64 | 
|  | size = CORE_NEW (core) ? sizeof (core.new_dump) : sizeof (core.old); | 
|  | #else | 
|  | size =  sizeof (core.new_dump); | 
|  | #endif | 
|  | tmpptr = bfd_alloc (abfd, size + 1); | 
|  | if (!tmpptr) | 
|  | return NULL; | 
|  |  | 
|  | /* Copy core file header.  */ | 
|  | memcpy (tmpptr, &core, size); | 
|  | /* Ensure core_file_failing_command string is terminated.  This is | 
|  | just to stop buffer overflows on fuzzed files.  */ | 
|  | tmpptr[size] = 0; | 
|  | set_tdata (abfd, tmpptr); | 
|  |  | 
|  | /* Set architecture.  */ | 
|  | if (CORE_NEW (core)) | 
|  | { | 
|  | enum bfd_architecture arch; | 
|  | unsigned long mach; | 
|  |  | 
|  | switch (CNEW_IMPL (core.new_dump)) | 
|  | { | 
|  | case POWER_RS1: | 
|  | case POWER_RSC: | 
|  | case POWER_RS2: | 
|  | arch = bfd_arch_rs6000; | 
|  | mach = bfd_mach_rs6k; | 
|  | break; | 
|  | default: | 
|  | arch = bfd_arch_powerpc; | 
|  | mach = bfd_mach_ppc; | 
|  | break; | 
|  | } | 
|  | bfd_default_set_arch_mach (abfd, arch, mach); | 
|  | } | 
|  |  | 
|  | /* .stack section.  */ | 
|  | if (!make_bfd_asection (abfd, ".stack", | 
|  | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | 
|  | c_size, c_stackend - c_size, c_stack)) | 
|  | goto fail; | 
|  |  | 
|  | /* .reg section for all registers.  */ | 
|  | if (!make_bfd_asection (abfd, ".reg", | 
|  | SEC_HAS_CONTENTS, | 
|  | c_regsize, (bfd_vma) 0, c_regoff)) | 
|  | goto fail; | 
|  |  | 
|  | if (c_extoff) | 
|  | { | 
|  | if (!make_bfd_asection (abfd, ".aix-vmx", | 
|  | SEC_HAS_CONTENTS, | 
|  | 560, (bfd_vma) 0, c_extoff)) | 
|  | goto fail; | 
|  |  | 
|  | if (!make_bfd_asection (abfd, ".aix-vsx", | 
|  | SEC_HAS_CONTENTS, | 
|  | 256, (bfd_vma) 0, c_extoff + 584)) | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | /* .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.  */ | 
|  | if (!make_bfd_asection (abfd, ".ldinfo", | 
|  | SEC_HAS_CONTENTS, | 
|  | c_lsize, (bfd_vma) 0, c_loader)) | 
|  | goto fail; | 
|  |  | 
|  | #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 core.c_datasize below to find out the actual size of | 
|  | the .data section.  */ | 
|  | if (c_flag & FULL_CORE) | 
|  | { | 
|  | if (!make_bfd_asection (abfd, ".data", | 
|  | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | 
|  | (bfd_size_type) core.old.c_u.u_dsize, | 
|  | (bfd_vma) | 
|  | CDATA_ADDR (core.old.c_u.u_dsize), | 
|  | c_stack + c_size)) | 
|  | goto fail; | 
|  | } | 
|  | #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.  */ | 
|  | { | 
|  | LdInfo ldinfo; | 
|  | bfd_size_type ldi_datasize; | 
|  | file_ptr ldi_core; | 
|  | uint ldi_next; | 
|  | bfd_vma ldi_dataorg; | 
|  | bfd_vma core_dataorg; | 
|  |  | 
|  | /* Fields from new and old core structures.  */ | 
|  | bfd_size_type c_datasize, c_vmregions; | 
|  | file_ptr c_data, c_vmm; | 
|  |  | 
|  | if (CORE_NEW (core)) | 
|  | { | 
|  | c_datasize = CNEW_DATASIZE (core.new_dump); | 
|  | c_data = (file_ptr) core.new_dump.c_data; | 
|  | c_vmregions = core.new_dump.c_vmregions; | 
|  | c_vmm = (file_ptr) core.new_dump.c_vmm; | 
|  | } | 
|  | #ifndef BFD64 | 
|  | else | 
|  | { | 
|  | c_datasize = core.old.c_datasize; | 
|  | c_data = (file_ptr) (ptr_to_uint) core.old.c_data; | 
|  | c_vmregions = core.old.c_vmregions; | 
|  | c_vmm = (file_ptr) (ptr_to_uint) core.old.c_vmm; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* .data section from executable.  */ | 
|  | if (c_datasize) | 
|  | { | 
|  | /* If Large Memory Model is used, then the .data segment should start from | 
|  | BDATAORG which has been defined in the system header files. */ | 
|  |  | 
|  | if (c_flag & CORE_BIGDATA) | 
|  | core_dataorg = BDATAORG; | 
|  | else | 
|  | core_dataorg = CDATA_ADDR (c_datasize); | 
|  |  | 
|  | if (!make_bfd_asection (abfd, ".data", | 
|  | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | 
|  | c_datasize, | 
|  | (bfd_vma) core_dataorg, | 
|  | c_data)) | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | /* .data sections from loaded objects.  */ | 
|  | if (proc64) | 
|  | size = (unsigned long) ((LdInfo *) 0)->l64.ldinfo_filename; | 
|  | else | 
|  | size = (unsigned long) ((LdInfo *) 0)->l32.ldinfo_filename; | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | if (bfd_seek (abfd, c_loader, SEEK_SET) != 0) | 
|  | goto fail; | 
|  | if (bfd_read (&ldinfo, size, abfd) != size) | 
|  | goto fail; | 
|  |  | 
|  | if (proc64) | 
|  | { | 
|  | ldi_core = ldinfo.l64.ldinfo_core; | 
|  | ldi_datasize = ldinfo.l64.ldinfo_datasize; | 
|  | ldi_dataorg = (bfd_vma) ldinfo.l64.ldinfo_dataorg; | 
|  | ldi_next = ldinfo.l64.ldinfo_next; | 
|  | } | 
|  | else | 
|  | { | 
|  | ldi_core = ldinfo.l32.ldinfo_core; | 
|  | ldi_datasize = ldinfo.l32.ldinfo_datasize; | 
|  | ldi_dataorg = (bfd_vma) (ptr_to_uint) ldinfo.l32.ldinfo_dataorg; | 
|  | ldi_next = ldinfo.l32.ldinfo_next; | 
|  | } | 
|  |  | 
|  | if (ldi_core) | 
|  | if (!make_bfd_asection (abfd, ".data", | 
|  | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | 
|  | ldi_datasize, ldi_dataorg, ldi_core)) | 
|  | goto fail; | 
|  |  | 
|  | if (ldi_next == 0) | 
|  | break; | 
|  | c_loader += ldi_next; | 
|  | } | 
|  |  | 
|  | /* .vmdata sections from anonymously mmapped regions.  */ | 
|  | if (c_vmregions) | 
|  | { | 
|  | bfd_size_type i; | 
|  |  | 
|  | if (bfd_seek (abfd, c_vmm, SEEK_SET) != 0) | 
|  | goto fail; | 
|  |  | 
|  | for (i = 0; i < c_vmregions; i++) | 
|  | { | 
|  | VmInfo vminfo; | 
|  | bfd_size_type vminfo_size; | 
|  | file_ptr vminfo_offset; | 
|  | bfd_vma vminfo_addr; | 
|  |  | 
|  | #ifndef BFD64 | 
|  | size = CORE_NEW (core) ? sizeof (vminfo.new_dump) : sizeof (vminfo.old); | 
|  | #else | 
|  | size = sizeof (vminfo.new_dump); | 
|  | #endif | 
|  | if (bfd_read (&vminfo, size, abfd) != size) | 
|  | goto fail; | 
|  |  | 
|  | if (CORE_NEW (core)) | 
|  | { | 
|  | vminfo_addr = (bfd_vma) vminfo.new_dump.vminfo_addr; | 
|  | vminfo_size = vminfo.new_dump.vminfo_size; | 
|  | vminfo_offset = vminfo.new_dump.vminfo_offset; | 
|  | } | 
|  | #ifndef BFD64 | 
|  | else | 
|  | { | 
|  | vminfo_addr = (bfd_vma) (ptr_to_uint) vminfo.old.vminfo_addr; | 
|  | vminfo_size = vminfo.old.vminfo_size; | 
|  | vminfo_offset = vminfo.old.vminfo_offset; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (vminfo_offset) | 
|  | if (!make_bfd_asection (abfd, ".vmdata", | 
|  | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | 
|  | vminfo_size, vminfo_addr, | 
|  | vminfo_offset)) | 
|  | goto fail; | 
|  | } | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return _bfd_no_cleanup; | 
|  |  | 
|  | fail: | 
|  | bfd_release (abfd, abfd->tdata.any); | 
|  | abfd->tdata.any = NULL; | 
|  | bfd_section_list_clear (abfd); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Return `TRUE' if given core is from the given executable.  */ | 
|  |  | 
|  | bool | 
|  | rs6000coff_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) | 
|  | { | 
|  | CoreHdr core; | 
|  | bfd_size_type size; | 
|  | char *path, *s; | 
|  | size_t alloc; | 
|  | const char *str1, *str2; | 
|  | bool ret; | 
|  | file_ptr c_loader; | 
|  |  | 
|  | if (!read_hdr (core_bfd, &core)) | 
|  | return false; | 
|  |  | 
|  | if (CORE_NEW (core)) | 
|  | c_loader = CNEW_LOADER (core.new_dump); | 
|  | #ifndef BFD64 | 
|  | else | 
|  | c_loader = (file_ptr) (ptr_to_uint) COLD_LOADER (core.old); | 
|  | #endif | 
|  |  | 
|  | if (CORE_NEW (core) && CNEW_PROC64 (core.new_dump)) | 
|  | size = (int) ((LdInfo *) 0)->l64.ldinfo_filename; | 
|  | else | 
|  | size = (int) ((LdInfo *) 0)->l32.ldinfo_filename; | 
|  |  | 
|  | if (bfd_seek (core_bfd, c_loader + size, SEEK_SET) != 0) | 
|  | return false; | 
|  |  | 
|  | alloc = 100; | 
|  | path = bfd_malloc ((bfd_size_type) alloc); | 
|  | if (path == NULL) | 
|  | return false; | 
|  | s = path; | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | if (bfd_read (s, 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, (bfd_size_type) alloc); | 
|  | if (n == NULL) | 
|  | { | 
|  | free (path); | 
|  | return false; | 
|  | } | 
|  | s = n + (path - s); | 
|  | path = n; | 
|  | } | 
|  | } | 
|  |  | 
|  | str1 = strrchr (path, '/'); | 
|  | str2 = strrchr (bfd_get_filename (exec_bfd), '/'); | 
|  |  | 
|  | /* step over character '/' */ | 
|  | str1 = str1 != NULL ? str1 + 1 : path; | 
|  | str2 = str2 != NULL ? str2 + 1 : bfd_get_filename (exec_bfd); | 
|  |  | 
|  | if (strcmp (str1, str2) == 0) | 
|  | ret = true; | 
|  | else | 
|  | ret = false; | 
|  |  | 
|  | free (path); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | char * | 
|  | rs6000coff_core_file_failing_command (bfd *abfd) | 
|  | { | 
|  | CoreHdr *core = core_hdr (abfd); | 
|  | #ifndef BFD64 | 
|  | char *com = CORE_NEW (*core) ? | 
|  | CNEW_COMM (core->new_dump) : COLD_COMM (core->old); | 
|  | #else | 
|  | char *com = CNEW_COMM (core->new_dump); | 
|  | #endif | 
|  |  | 
|  | if (*com) | 
|  | return com; | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | rs6000coff_core_file_failing_signal (bfd *abfd) | 
|  | { | 
|  | CoreHdr *core = core_hdr (abfd); | 
|  | #ifndef BFD64 | 
|  | return CORE_NEW (*core) ? core->new_dump.c_signo : core->old.c_signo; | 
|  | #else | 
|  | return  core->new_dump.c_signo; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #endif /* AIX_CORE */ |