Commit | Line | Data |
---|---|---|
eb1e0e80 NC |
1 | /* IBM RS/6000 "XCOFF" back-end for BFD. |
2 | Copyright 2001, 2002 | |
3 | Free Software Foundation, Inc. | |
4 | Written by Tom Rix | |
5 | Contributed by Redhat. | |
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., 59 Temple Place - Suite 330, Boston, | |
22 | MA 02111-1307, USA. */ | |
23 | ||
24 | #include "bfd.h" | |
25 | ||
26 | #ifdef AIX_5_CORE | |
27 | ||
28 | #include "sysdep.h" | |
29 | #include "libbfd.h" | |
30 | ||
31 | const bfd_target * xcoff64_core_p PARAMS ((bfd *)); | |
32 | boolean xcoff64_core_file_matches_executable_p PARAMS ((bfd *, bfd *)); | |
33 | char * xcoff64_core_file_failing_command PARAMS ((bfd *)); | |
34 | int xcoff64_core_file_failing_signal PARAMS ((bfd *)); | |
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 | ||
48 | const bfd_target * | |
49 | xcoff64_core_p (abfd) | |
50 | bfd *abfd; | |
51 | { | |
52 | struct core_dumpxx core, *new_core_hdr; | |
53 | struct stat statbuf; | |
54 | asection *sec; | |
55 | struct __ld_info64 ldinfo; | |
56 | bfd_vma ld_offset; | |
57 | bfd_size_type i; | |
58 | struct vm_infox vminfo; | |
59 | bfd_target *return_value = NULL; | |
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) | |
d1e66cd4 | 66 | != bfd_bread (&core, sizeof (struct core_dumpxx), abfd)) |
eb1e0e80 NC |
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 trucated 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 = (struct core_dumpxx *) | |
111 | bfd_zalloc (abfd, sizeof (struct core_dumpxx)); | |
112 | if (NULL == new_core_hdr) | |
113 | return return_value; | |
114 | ||
115 | memcpy (new_core_hdr, &core, sizeof (struct core_dumpxx)); | |
116 | core_hdr(abfd) = (char *)new_core_hdr; | |
117 | ||
118 | /* .stack section. */ | |
119 | sec = bfd_make_section_anyway (abfd, ".stack"); | |
120 | if (NULL == sec) | |
121 | return return_value; | |
122 | ||
123 | sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; | |
124 | sec->_raw_size = core.c_size; | |
125 | sec->vma = core.c_stackorg; | |
126 | sec->filepos = core.c_stack; | |
127 | ||
128 | /* .reg section for all registers. */ | |
129 | sec = bfd_make_section_anyway (abfd, ".reg"); | |
130 | if (NULL == sec) | |
131 | return return_value; | |
132 | ||
133 | sec->flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY; | |
134 | sec->_raw_size = sizeof (struct __context64); | |
135 | sec->vma = 0; | |
136 | sec->filepos = 0; | |
137 | sec->contents = (bfd_byte *)&new_core_hdr->c_flt.r64; | |
138 | ||
139 | /* .ldinfo section. | |
140 | To actually find out how long this section is in this particular | |
141 | core dump would require going down the whole list of struct | |
142 | ld_info's. See if we can just fake it. */ | |
143 | sec = bfd_make_section_anyway (abfd, ".ldinfo"); | |
144 | if (NULL == sec) | |
145 | return return_value; | |
146 | ||
147 | sec->flags = SEC_HAS_CONTENTS; | |
148 | sec->_raw_size = core.c_lsize; | |
149 | sec->vma = 0; | |
150 | sec->filepos = core.c_loader; | |
151 | ||
152 | /* AIX 4 adds data sections from loaded objects to the core file, | |
153 | which can be found by examining ldinfo, and anonymously mmapped | |
154 | regions. */ | |
155 | ||
156 | /* .data section from executable. */ | |
157 | sec = bfd_make_section_anyway (abfd, ".data"); | |
158 | if (NULL == sec) | |
159 | return return_value; | |
160 | ||
161 | sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; | |
162 | sec->_raw_size = core.c_datasize; | |
163 | sec->vma = core.c_dataorg; | |
164 | sec->filepos = core.c_data; | |
165 | ||
166 | /* .data sections from loaded objects. */ | |
167 | ld_offset = core.c_loader; | |
168 | ||
169 | while (1) | |
170 | { | |
171 | if (bfd_seek (abfd, ld_offset, SEEK_SET) != 0) | |
172 | return return_value; | |
173 | ||
174 | if (sizeof (struct __ld_info64) != | |
d1e66cd4 | 175 | bfd_bread (&ldinfo, sizeof (struct __ld_info64), abfd)) |
eb1e0e80 NC |
176 | return return_value; |
177 | ||
178 | if (ldinfo.ldinfo_core) | |
179 | { | |
180 | sec = bfd_make_section_anyway (abfd, ".data"); | |
181 | if (NULL == sec) | |
182 | return return_value; | |
183 | ||
184 | sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; | |
185 | sec->_raw_size = ldinfo.ldinfo_datasize; | |
186 | sec->vma = ldinfo.ldinfo_dataorg; | |
187 | sec->filepos = ldinfo.ldinfo_core; | |
188 | } | |
189 | ||
190 | if (0 == ldinfo.ldinfo_next) | |
191 | break; | |
192 | ld_offset += ldinfo.ldinfo_next; | |
193 | } | |
194 | ||
195 | /* .vmdata sections from anonymously mmapped regions. */ | |
196 | if (core.c_vmregions) | |
197 | { | |
198 | if (bfd_seek (abfd, core.c_vmm, SEEK_SET) != 0) | |
199 | return return_value; | |
200 | ||
201 | for (i = 0; i < core.c_vmregions; i++) | |
202 | if (sizeof (struct vm_infox) != | |
d1e66cd4 | 203 | bfd_bread (&vminfo, sizeof (struct vm_infox), abfd)) |
eb1e0e80 NC |
204 | return return_value; |
205 | ||
206 | if (vminfo.vminfo_offset) | |
207 | { | |
208 | sec = bfd_make_section_anyway (abfd, ".vmdata"); | |
209 | if (NULL == sec) | |
210 | return return_value; | |
211 | ||
212 | sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; | |
213 | sec->_raw_size = vminfo.vminfo_size; | |
214 | sec->vma = vminfo.vminfo_addr; | |
215 | sec->filepos = vminfo.vminfo_offset; | |
216 | } | |
217 | } | |
218 | ||
219 | return_value = abfd->xvec; /* This is garbage for now. */ | |
220 | ||
221 | xcoff64_core_p_error: | |
222 | if (bfd_get_error () != bfd_error_system_call) | |
223 | bfd_set_error (bfd_error_wrong_format); | |
224 | ||
225 | return return_value; | |
226 | } | |
227 | ||
228 | /* Return `true' if given core is from the given executable. */ | |
229 | ||
230 | boolean | |
231 | xcoff64_core_file_matches_executable_p (core_bfd, exec_bfd) | |
232 | bfd *core_bfd; | |
233 | bfd *exec_bfd; | |
234 | { | |
235 | struct core_dumpxx core; | |
236 | char *path, *s; | |
237 | size_t alloc; | |
238 | const char *str1, *str2; | |
239 | 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) != | |
d1e66cd4 | 246 | bfd_bread (&core, sizeof (struct core_dumpxx), core_bfd)) |
eb1e0e80 NC |
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 | { | |
d1e66cd4 | 261 | if (bfd_bread (s, 1, core_bfd) != 1) |
eb1e0e80 NC |
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 | ||
296 | char * | |
297 | xcoff64_core_file_failing_command (abfd) | |
298 | bfd *abfd; | |
299 | { | |
300 | struct core_dumpxx *c = core_hdr (abfd); | |
301 | char *return_value = 0; | |
302 | ||
303 | if (NULL != c) | |
304 | return_value = c->c_u.U_proc.pi_comm; | |
305 | ||
306 | return return_value; | |
307 | } | |
308 | ||
309 | int | |
310 | xcoff64_core_file_failing_signal (abfd) | |
311 | bfd *abfd; | |
312 | { | |
313 | struct core_dumpxx *c = core_hdr (abfd); | |
314 | int return_value = 0; | |
315 | ||
316 | if (NULL != c) | |
317 | return_value = c->c_signo; | |
318 | ||
319 | return return_value; | |
320 | } | |
321 | ||
322 | #else /* AIX_5_CORE */ | |
323 | ||
324 | const bfd_target * xcoff64_core_p PARAMS ((bfd *)); | |
325 | boolean xcoff64_core_file_matches_executable_p PARAMS ((bfd *, bfd *)); | |
326 | char * xcoff64_core_file_failing_command PARAMS ((bfd *)); | |
327 | int xcoff64_core_file_failing_signal PARAMS ((bfd *)); | |
328 | ||
329 | const bfd_target * | |
330 | xcoff64_core_p (abfd) | |
2d653fc7 | 331 | bfd *abfd ATTRIBUTE_UNUSED; |
eb1e0e80 NC |
332 | { |
333 | bfd_set_error (bfd_error_wrong_format); | |
334 | return 0; | |
335 | } | |
336 | ||
337 | boolean | |
338 | xcoff64_core_file_matches_executable_p (core_bfd, exec_bfd) | |
2d653fc7 AM |
339 | bfd *core_bfd ATTRIBUTE_UNUSED; |
340 | bfd *exec_bfd ATTRIBUTE_UNUSED; | |
eb1e0e80 NC |
341 | { |
342 | return false; | |
343 | } | |
344 | ||
345 | char * | |
346 | xcoff64_core_file_failing_command (abfd) | |
2d653fc7 | 347 | bfd *abfd ATTRIBUTE_UNUSED; |
eb1e0e80 NC |
348 | { |
349 | return 0; | |
350 | } | |
351 | ||
352 | int | |
353 | xcoff64_core_file_failing_signal (abfd) | |
2d653fc7 | 354 | bfd *abfd ATTRIBUTE_UNUSED; |
eb1e0e80 NC |
355 | { |
356 | return 0; | |
357 | } | |
358 | ||
359 | #endif /* AIX_5_CORE */ |