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