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