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