Home | History | Annotate | Download | only in bfd
      1 /* IBM RS/6000 "XCOFF" back-end for BFD.
      2    Copyright (C) 2001-2014 Free Software Foundation, Inc.
      3    Written by Tom Rix
      4    Contributed by Red Hat Inc.
      5 
      6    This file is part of BFD, the Binary File Descriptor library.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21    MA 02110-1301, USA.  */
     22 
     23 #include "sysdep.h"
     24 #include "bfd.h"
     25 
     26 const bfd_target *xcoff64_core_p (bfd *);
     27 bfd_boolean xcoff64_core_file_matches_executable_p (bfd *, bfd *);
     28 char *xcoff64_core_file_failing_command (bfd *);
     29 int xcoff64_core_file_failing_signal (bfd *);
     30 
     31 #ifdef AIX_5_CORE
     32 
     33 #include "libbfd.h"
     34 
     35 /* Aix 5.1 system include file.  */
     36 
     37 /* Need to define this macro so struct ld_info64 get included.  */
     38 #define __LDINFO_PTRACE64__
     39 #include <sys/ldr.h>
     40 #include <core.h>
     41 
     42 /* The default architecture and machine for matching core files.  */
     43 #define DEFAULT_ARCHITECTURE	bfd_arch_powerpc
     44 #define DEFAULT_MACHINE		bfd_mach_ppc_620
     45 
     46 #define	core_hdr(abfd)		((struct core_dumpxx *) abfd->tdata.any)
     47 
     48 #define CHECK_FILE_OFFSET(s, v) \
     49   ((bfd_signed_vma)(v) < 0 || (bfd_signed_vma)(v) > (bfd_signed_vma)(s).st_size)
     50 
     51 const bfd_target *
     52 xcoff64_core_p (bfd *abfd)
     53 {
     54   enum bfd_architecture arch;
     55   unsigned long mach;
     56   struct core_dumpxx core, *new_core_hdr;
     57   struct stat statbuf;
     58   asection *sec;
     59   struct __ld_info64 ldinfo;
     60   bfd_vma ld_offset;
     61   bfd_size_type i;
     62   struct vm_infox vminfo;
     63   const bfd_target *return_value = NULL;
     64   flagword flags;
     65 
     66   /* Get the header.  */
     67   if (bfd_seek (abfd, 0, SEEK_SET) != 0)
     68     goto xcoff64_core_p_error;
     69 
     70   if (sizeof (struct core_dumpxx)
     71       != bfd_bread (&core, sizeof (struct core_dumpxx), abfd))
     72     goto xcoff64_core_p_error;
     73 
     74   if (bfd_stat (abfd, &statbuf) < 0)
     75     goto xcoff64_core_p_error;
     76 
     77   /* Sanity checks
     78      c_flag has CORE_VERSION_1, Aix 4+
     79      c_entries = 0 for Aix 4.3+
     80      IS_PROC64 is a macro defined in procinfo.h, test for 64 bit process.
     81 
     82      We will still be confused if a Aix 4.3 64 bit core file is
     83      copied over to a Aix 5 machine.
     84 
     85      Check file header offsets
     86 
     87      See rs6000-core.c for comment on size of core
     88      If there isn't enough of a real core file, bail.  */
     89 
     90   if ((CORE_VERSION_1 != (core.c_flag & CORE_VERSION_1))
     91       || (0 != core.c_entries)
     92       || (! (IS_PROC64 (&core.c_u.U_proc)))
     93       || ((CHECK_FILE_OFFSET (statbuf, core.c_fdsinfox)))
     94       || ((CHECK_FILE_OFFSET (statbuf, core.c_loader)))
     95       || ((CHECK_FILE_OFFSET (statbuf, core.c_loader + core.c_lsize)))
     96       || ((CHECK_FILE_OFFSET (statbuf, core.c_thr)))
     97       || ((CHECK_FILE_OFFSET (statbuf, core.c_segregion)))
     98       || ((CHECK_FILE_OFFSET (statbuf, core.c_stack)))
     99       || ((CHECK_FILE_OFFSET (statbuf, core.c_stack + core.c_size)))
    100       || ((CHECK_FILE_OFFSET (statbuf, core.c_data)))
    101       || ((CHECK_FILE_OFFSET (statbuf, core.c_data + core.c_datasize)))
    102       || (! (core.c_flag & UBLOCK_VALID))
    103       || (! (core.c_flag & LE_VALID)))
    104     goto xcoff64_core_p_error;
    105 
    106   /* Check for truncated stack or general truncating.  */
    107   if ((! (core.c_flag & USTACK_VALID))
    108       || (core.c_flag & CORE_TRUNC))
    109     {
    110       bfd_set_error (bfd_error_file_truncated);
    111 
    112       return return_value;
    113     }
    114 
    115   new_core_hdr = bfd_zalloc (abfd, sizeof (struct core_dumpxx));
    116   if (NULL == new_core_hdr)
    117     return return_value;
    118 
    119   memcpy (new_core_hdr, &core, sizeof (struct core_dumpxx));
    120   /* The core_hdr() macro is no longer used here because it would
    121      expand to code relying on gcc's cast-as-lvalue extension,
    122      which was removed in gcc 4.0.  */
    123   abfd->tdata.any = new_core_hdr;
    124 
    125   /* .stack section.  */
    126   flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
    127   sec = bfd_make_section_anyway_with_flags (abfd, ".stack", flags);
    128   if (NULL == sec)
    129     return return_value;
    130 
    131   sec->size = core.c_size;
    132   sec->vma = core.c_stackorg;
    133   sec->filepos = core.c_stack;
    134 
    135   /* .reg section for all registers.  */
    136   flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY;
    137   sec = bfd_make_section_anyway_with_flags (abfd, ".reg", flags);
    138   if (NULL == sec)
    139     return return_value;
    140 
    141   sec->size = sizeof (struct __context64);
    142   sec->vma = 0;
    143   sec->filepos = 0;
    144   sec->contents = (bfd_byte *)&new_core_hdr->c_flt.r64;
    145 
    146   /* .ldinfo section.
    147      To actually find out how long this section is in this particular
    148      core dump would require going down the whole list of struct
    149      ld_info's.   See if we can just fake it.  */
    150   flags = SEC_HAS_CONTENTS;
    151   sec = bfd_make_section_anyway_with_flags (abfd, ".ldinfo", flags);
    152   if (NULL == sec)
    153     return return_value;
    154 
    155   sec->size = core.c_lsize;
    156   sec->vma = 0;
    157   sec->filepos = core.c_loader;
    158 
    159   /* AIX 4 adds data sections from loaded objects to the core file,
    160      which can be found by examining ldinfo, and anonymously mmapped
    161      regions.  */
    162 
    163   /* .data section from executable.  */
    164   flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
    165   sec = bfd_make_section_anyway_with_flags (abfd, ".data", flags);
    166   if (NULL == sec)
    167     return return_value;
    168 
    169   sec->size = core.c_datasize;
    170   sec->vma = core.c_dataorg;
    171   sec->filepos = core.c_data;
    172 
    173   /* .data sections from loaded objects.  */
    174   ld_offset = core.c_loader;
    175 
    176   while (1)
    177     {
    178       if (bfd_seek (abfd, ld_offset, SEEK_SET) != 0)
    179 	return return_value;
    180 
    181       if (sizeof (struct __ld_info64) !=
    182 	  bfd_bread (&ldinfo, sizeof (struct __ld_info64), abfd))
    183 	return return_value;
    184 
    185       if (ldinfo.ldinfo_core)
    186 	{
    187 	  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
    188 	  sec = bfd_make_section_anyway_with_flags (abfd, ".data", flags);
    189 	  if (NULL == sec)
    190 	    return return_value;
    191 
    192 	  sec->size = ldinfo.ldinfo_datasize;
    193 	  sec->vma = ldinfo.ldinfo_dataorg;
    194 	  sec->filepos = ldinfo.ldinfo_core;
    195 	}
    196 
    197       if (0 == ldinfo.ldinfo_next)
    198 	break;
    199       ld_offset += ldinfo.ldinfo_next;
    200     }
    201 
    202   /* .vmdata sections from anonymously mmapped regions.  */
    203   if (core.c_vmregions)
    204     {
    205       if (bfd_seek (abfd, core.c_vmm, SEEK_SET) != 0)
    206 	return return_value;
    207 
    208       for (i = 0; i < core.c_vmregions; i++)
    209 	if (sizeof (struct vm_infox) !=
    210 	    bfd_bread (&vminfo, sizeof (struct vm_infox), abfd))
    211 	  return return_value;
    212 
    213       if (vminfo.vminfo_offset)
    214 	{
    215 	  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
    216 	  sec = bfd_make_section_anyway_with_flags (abfd, ".vmdata", flags);
    217 	  if (NULL == sec)
    218 	    return return_value;
    219 
    220 	  sec->size = vminfo.vminfo_size;
    221 	  sec->vma = vminfo.vminfo_addr;
    222 	  sec->filepos = vminfo.vminfo_offset;
    223 	}
    224     }
    225 
    226   /* Set the architecture and machine.  */
    227   arch = DEFAULT_ARCHITECTURE;
    228   mach = DEFAULT_MACHINE;
    229   bfd_default_set_arch_mach (abfd, arch, mach);
    230 
    231   return_value = (bfd_target *) abfd->xvec;	/* This is garbage for now.  */
    232 
    233  xcoff64_core_p_error:
    234   if (bfd_get_error () != bfd_error_system_call)
    235     bfd_set_error (bfd_error_wrong_format);
    236 
    237   return return_value;
    238 }
    239 
    240 /* Return `TRUE' if given core is from the given executable.  */
    241 
    242 bfd_boolean
    243 xcoff64_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd)
    244 {
    245   struct core_dumpxx core;
    246   char *path, *s;
    247   size_t alloc;
    248   const char *str1, *str2;
    249   bfd_boolean return_value = FALSE;
    250 
    251   /* Get the header.  */
    252   if (bfd_seek (core_bfd, 0, SEEK_SET) != 0)
    253     return return_value;
    254 
    255   if (sizeof (struct core_dumpxx) !=
    256       bfd_bread (&core, sizeof (struct core_dumpxx), core_bfd))
    257     return return_value;
    258 
    259   if (bfd_seek (core_bfd, core.c_loader, SEEK_SET) != 0)
    260     return return_value;
    261 
    262   alloc = 100;
    263   path = bfd_malloc (alloc);
    264   if (path == NULL)
    265     return return_value;
    266 
    267   s = path;
    268 
    269   while (1)
    270     {
    271       if (bfd_bread (s, 1, core_bfd) != 1)
    272 	goto xcoff64_core_file_matches_executable_p_end_1;
    273 
    274       if (*s == '\0')
    275 	break;
    276       ++s;
    277       if (s == path + alloc)
    278 	{
    279 	  char *n;
    280 
    281 	  alloc *= 2;
    282 	  n = bfd_realloc (path, alloc);
    283 	  if (n == NULL)
    284 	    goto xcoff64_core_file_matches_executable_p_end_1;
    285 
    286 	  s = n + (path - s);
    287 	  path = n;
    288 	}
    289     }
    290 
    291   str1 = strrchr (path, '/');
    292   str2 = strrchr (exec_bfd->filename, '/');
    293 
    294   /* Step over character '/'.  */
    295   str1 = str1 != NULL ? str1 + 1 : path;
    296   str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename;
    297 
    298   if (strcmp (str1, str2) == 0)
    299     return_value = TRUE;
    300 
    301  xcoff64_core_file_matches_executable_p_end_1:
    302   free (path);
    303   return return_value;
    304 }
    305 
    306 char *
    307 xcoff64_core_file_failing_command (bfd *abfd)
    308 {
    309   struct core_dumpxx *c = core_hdr (abfd);
    310   char *return_value = 0;
    311 
    312   if (NULL != c)
    313     return_value = c->c_u.U_proc.pi_comm;
    314 
    315   return return_value;
    316 }
    317 
    318 int
    319 xcoff64_core_file_failing_signal (bfd *abfd)
    320 {
    321   struct core_dumpxx *c = core_hdr (abfd);
    322   int return_value = 0;
    323 
    324   if (NULL != c)
    325     return_value = c->c_signo;
    326 
    327   return return_value;
    328 }
    329 
    330 #else /* AIX_5_CORE */
    331 
    332 const bfd_target *
    333 xcoff64_core_p (bfd *abfd ATTRIBUTE_UNUSED)
    334 {
    335   bfd_set_error (bfd_error_wrong_format);
    336   return 0;
    337 }
    338 
    339 bfd_boolean
    340 xcoff64_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd)
    341 {
    342   return generic_core_file_matches_executable_p (core_bfd, exec_bfd);
    343 }
    344 
    345 char *
    346 xcoff64_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
    347 {
    348   return 0;
    349 }
    350 
    351 int
    352 xcoff64_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
    353 {
    354   return 0;
    355 }
    356 
    357 #endif /* AIX_5_CORE */
    358