Commit | Line | Data |
---|---|---|
252b5132 | 1 | /* IBM RS/6000 "XCOFF" back-end for BFD. |
ced7a2cc | 2 | Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 2000 |
252b5132 RH |
3 | Free Software Foundation, Inc. |
4 | FIXME: Can someone provide a transliteration of this name into ASCII? | |
5 | Using the following chars caused a compiler warning on HIUX (so I replaced | |
6 | them with octal escapes), and isn't useful without an understanding of what | |
7 | character set it is. | |
8 | Written by Metin G. Ozisik, Mimi Ph\373\364ng-Th\345o V\365, | |
9 | and John Gilmore. | |
10 | Archive support from Damon A. Permezel. | |
11 | Contributed by IBM Corporation and Cygnus Support. | |
12 | ||
13 | This file is part of BFD, the Binary File Descriptor library. | |
14 | ||
15 | This program is free software; you can redistribute it and/or modify | |
16 | it under the terms of the GNU General Public License as published by | |
17 | the Free Software Foundation; either version 2 of the License, or | |
18 | (at your option) any later version. | |
19 | ||
20 | This program is distributed in the hope that it will be useful, | |
21 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | GNU General Public License for more details. | |
24 | ||
25 | You should have received a copy of the GNU General Public License | |
26 | along with this program; if not, write to the Free Software | |
27 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
28 | ||
29 | /* This port currently only handles reading object files, except when | |
30 | compiled on an RS/6000 host. -- no archive support, no core files. | |
31 | In all cases, it does not support writing. | |
32 | ||
33 | FIXMEmgo comments are left from Metin Ozisik's original port. | |
34 | ||
35 | This is in a separate file from coff-rs6000.c, because it includes | |
36 | system include files that conflict with coff/rs6000.h. | |
37 | */ | |
38 | ||
39 | /* Internalcoff.h and coffcode.h modify themselves based on this flag. */ | |
40 | #define RS6000COFF_C 1 | |
41 | ||
42 | /* The AIX 4.1 kernel is obviously compiled with -D_LONG_LONG, so | |
43 | we have to define _LONG_LONG for older versions of gcc to get the | |
44 | proper alignments in the user structure. */ | |
45 | #if defined(_AIX41) && !defined(_LONG_LONG) | |
46 | #define _LONG_LONG | |
47 | #endif | |
48 | ||
49 | #include "bfd.h" | |
50 | #include "sysdep.h" | |
51 | #include "libbfd.h" | |
52 | ||
53 | #ifdef AIX_CORE | |
54 | ||
55 | /* AOUTHDR is defined by the above. We need another defn of it, from the | |
56 | system include files. Punt the old one and get us a new name for the | |
57 | typedef in the system include files. */ | |
58 | #ifdef AOUTHDR | |
59 | #undef AOUTHDR | |
60 | #endif | |
61 | #define AOUTHDR second_AOUTHDR | |
62 | ||
63 | #undef SCNHDR | |
64 | ||
65 | ||
66 | /* ------------------------------------------------------------------------ */ | |
67 | /* Support for core file stuff.. */ | |
68 | /* ------------------------------------------------------------------------ */ | |
69 | ||
70 | #include <sys/user.h> | |
71 | #include <sys/ldr.h> | |
72 | #include <sys/core.h> | |
73 | ||
74 | ||
75 | /* Number of special purpose registers supported by gdb. This value | |
76 | should match `tm.h' in gdb directory. Clean this mess up and use | |
77 | the macros in sys/reg.h. FIXMEmgo. */ | |
78 | ||
79 | #define NUM_OF_SPEC_REGS 7 | |
80 | ||
81 | #define core_hdr(bfd) (((Rs6kCorData*)(bfd->tdata.any))->hdr) | |
82 | ||
83 | /* AIX 4.1 Changed the names and locations of a few items in the core file, | |
6ad49cca | 84 | this seems to be the quickest/easiest way to deal with it. |
252b5132 RH |
85 | |
86 | Note however that encoding magic addresses (STACK_END_ADDR) is going | |
87 | to be _very_ fragile. But I don't see any easy way to get that info | |
6ad49cca KB |
88 | right now. |
89 | ||
90 | AIX 4.3 defines an entirely new structure (core_dumpx). Yet the | |
91 | basic logic stays the same and we can still use our macro | |
92 | redefinition mechanism to effect the necessary changes. */ | |
93 | ||
94 | #ifdef AIX_CORE_DUMPX_CORE | |
95 | #define CORE_DATA_SIZE_FIELD c_dataorg | |
96 | #define CORE_COMM_FIELD c_u.U_proc.pi_comm | |
97 | #define SAVE_FIELD c_flt.hctx.r32 | |
98 | #define STACK_END_ADDR coredata.c_stackorg + coredata.c_size | |
99 | #define LOADER_OFFSET_FIELD c_loader | |
100 | #define LOADER_REGION_SIZE coredata.c_lsize | |
101 | #define CORE_DUMP core_dumpx | |
102 | #else | |
252b5132 RH |
103 | #ifdef CORE_VERSION_1 |
104 | #define CORE_DATA_SIZE_FIELD c_u.U_dsize | |
105 | #define CORE_COMM_FIELD c_u.U_comm | |
106 | #define SAVE_FIELD c_mst | |
107 | #define STACK_END_ADDR 0x2ff23000 | |
6ad49cca KB |
108 | #define LOADER_OFFSET_FIELD c_tab |
109 | #define LOADER_REGION_SIZE 0x7ffffff | |
110 | #define CORE_DUMP core_dump | |
252b5132 RH |
111 | #else |
112 | #define CORE_DATA_SIZE_FIELD c_u.u_dsize | |
113 | #define CORE_COMM_FIELD c_u.u_comm | |
114 | #define SAVE_FIELD c_u.u_save | |
115 | #define STACK_END_ADDR 0x2ff80000 | |
6ad49cca KB |
116 | #define LOADER_OFFSET_FIELD c_tab |
117 | #define LOADER_REGION_SIZE 0x7ffffff | |
118 | #define CORE_DUMP core_dump | |
119 | #endif | |
252b5132 RH |
120 | #endif |
121 | ||
122 | /* These are stored in the bfd's tdata */ | |
123 | typedef struct { | |
6ad49cca | 124 | struct CORE_DUMP hdr; /* core file header */ |
252b5132 RH |
125 | } Rs6kCorData; |
126 | ||
127 | static asection *make_bfd_asection PARAMS ((bfd *, CONST char *, flagword, | |
128 | bfd_size_type, bfd_vma, file_ptr)); | |
129 | ||
130 | static asection * | |
131 | make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos) | |
132 | bfd *abfd; | |
133 | CONST char *name; | |
134 | flagword flags; | |
135 | bfd_size_type _raw_size; | |
136 | bfd_vma vma; | |
137 | file_ptr filepos; | |
138 | { | |
139 | asection *asect; | |
140 | ||
141 | asect = bfd_make_section_anyway (abfd, name); | |
142 | if (!asect) | |
143 | return NULL; | |
144 | ||
145 | asect->flags = flags; | |
146 | asect->_raw_size = _raw_size; | |
147 | asect->vma = vma; | |
148 | asect->filepos = filepos; | |
149 | asect->alignment_power = 8; | |
150 | ||
151 | return asect; | |
152 | } | |
153 | ||
154 | /* Decide if a given bfd represents a `core' file or not. There really is no | |
155 | magic number or anything like, in rs6000coff. */ | |
156 | ||
157 | const bfd_target * | |
158 | rs6000coff_core_p (abfd) | |
159 | bfd *abfd; | |
160 | { | |
6ad49cca | 161 | struct CORE_DUMP coredata; |
252b5132 RH |
162 | struct stat statbuf; |
163 | bfd_size_type nread; | |
164 | char *tmpptr; | |
165 | ||
166 | if (bfd_seek (abfd, 0, SEEK_SET) != 0) | |
167 | return NULL; | |
168 | ||
6ad49cca KB |
169 | nread = bfd_read (&coredata, 1, sizeof (struct CORE_DUMP), abfd); |
170 | if (nread != sizeof (struct CORE_DUMP)) | |
252b5132 RH |
171 | { |
172 | if (bfd_get_error () != bfd_error_system_call) | |
173 | bfd_set_error (bfd_error_wrong_format); | |
174 | return NULL; | |
175 | } | |
176 | ||
177 | if (bfd_stat (abfd, &statbuf) < 0) | |
178 | { | |
179 | bfd_set_error (bfd_error_system_call); | |
180 | return NULL; | |
181 | } | |
182 | ||
183 | /* If the core file ulimit is too small, the system will first | |
184 | omit the data segment, then omit the stack, then decline to | |
185 | dump core altogether (as far as I know UBLOCK_VALID and LE_VALID | |
186 | are always set) (this is based on experimentation on AIX 3.2). | |
187 | Now, the thing is that GDB users will be surprised | |
188 | if segments just silently don't appear (well, maybe they would | |
189 | think to check "info files", I don't know). | |
190 | ||
191 | For the data segment, we have no choice but to keep going if it's | |
192 | not there, since the default behavior is not to dump it (regardless | |
193 | of the ulimit, it's based on SA_FULLDUMP). But for the stack segment, | |
194 | if it's not there, we refuse to have anything to do with this core | |
195 | file. The usefulness of a core dump without a stack segment is pretty | |
196 | limited anyway. */ | |
197 | ||
198 | if (!(coredata.c_flag & UBLOCK_VALID) | |
199 | || !(coredata.c_flag & LE_VALID)) | |
200 | { | |
201 | bfd_set_error (bfd_error_wrong_format); | |
202 | return NULL; | |
203 | } | |
204 | ||
205 | if (!(coredata.c_flag & USTACK_VALID)) | |
206 | { | |
207 | bfd_set_error (bfd_error_file_truncated); | |
208 | return NULL; | |
209 | } | |
210 | ||
211 | /* Don't check the core file size for a full core, AIX 4.1 includes | |
212 | additional shared library sections in a full core. */ | |
213 | if (!(coredata.c_flag & (FULL_CORE | CORE_TRUNC)) | |
214 | && ((bfd_vma)coredata.c_stack + coredata.c_size) != statbuf.st_size) | |
215 | { | |
216 | /* If the size is wrong, it means we're misinterpreting something. */ | |
217 | bfd_set_error (bfd_error_wrong_format); | |
218 | return NULL; | |
219 | } | |
220 | ||
6ad49cca KB |
221 | #ifdef AIX_CORE_DUMPX_CORE |
222 | /* For the core_dumpx format, make sure c_entries == 0 If it does | |
223 | not, the core file uses the old format */ | |
224 | if (coredata.c_entries != 0) | |
225 | { | |
226 | bfd_set_error (bfd_error_wrong_format); | |
227 | return NULL; | |
228 | } | |
229 | #else | |
252b5132 RH |
230 | /* Sanity check on the c_tab field. */ |
231 | if ((u_long) coredata.c_tab < sizeof coredata || | |
232 | (u_long) coredata.c_tab >= statbuf.st_size || | |
233 | (long) coredata.c_tab >= (long)coredata.c_stack) | |
234 | { | |
235 | bfd_set_error (bfd_error_wrong_format); | |
236 | return NULL; | |
237 | } | |
6ad49cca | 238 | #endif |
252b5132 RH |
239 | |
240 | /* Issue warning if the core file was truncated during writing. */ | |
241 | if (coredata.c_flag & CORE_TRUNC) | |
242 | (*_bfd_error_handler) (_("%s: warning core file truncated"), | |
243 | bfd_get_filename (abfd)); | |
244 | ||
245 | /* Allocate core file header. */ | |
246 | tmpptr = (char*) bfd_zalloc (abfd, sizeof (Rs6kCorData)); | |
247 | if (!tmpptr) | |
248 | return NULL; | |
249 | ||
250 | set_tdata (abfd, tmpptr); | |
251 | ||
252 | /* Copy core file header. */ | |
253 | core_hdr (abfd) = coredata; | |
254 | ||
255 | /* .stack section. */ | |
256 | if (!make_bfd_asection (abfd, ".stack", | |
257 | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | |
258 | (bfd_size_type) coredata.c_size, | |
259 | (bfd_vma) (STACK_END_ADDR - coredata.c_size), | |
260 | (file_ptr) coredata.c_stack)) | |
261 | return NULL; | |
262 | ||
263 | /* .reg section for GPRs and special registers. */ | |
264 | if (!make_bfd_asection (abfd, ".reg", | |
265 | SEC_HAS_CONTENTS, | |
266 | (bfd_size_type) ((32 + NUM_OF_SPEC_REGS) * 4), | |
267 | (bfd_vma) 0, | |
268 | (file_ptr) ((char *) &coredata.SAVE_FIELD | |
269 | - (char *) &coredata))) | |
270 | return NULL; | |
271 | ||
272 | /* .reg2 section for FPRs (floating point registers). */ | |
273 | if (!make_bfd_asection (abfd, ".reg2", | |
274 | SEC_HAS_CONTENTS, | |
275 | (bfd_size_type) 8 * 32, /* 32 FPRs. */ | |
276 | (bfd_vma) 0, | |
277 | (file_ptr) ((char *) &coredata.SAVE_FIELD.fpr[0] | |
278 | - (char *) &coredata))) | |
279 | return NULL; | |
280 | ||
281 | /* .ldinfo section. | |
282 | To actually find out how long this section is in this particular | |
283 | core dump would require going down the whole list of struct ld_info's. | |
284 | See if we can just fake it. */ | |
285 | if (!make_bfd_asection (abfd, ".ldinfo", | |
286 | SEC_HAS_CONTENTS, | |
6ad49cca | 287 | (bfd_size_type) LOADER_REGION_SIZE, |
252b5132 | 288 | (bfd_vma) 0, |
6ad49cca | 289 | (file_ptr) coredata.LOADER_OFFSET_FIELD)) |
252b5132 RH |
290 | return NULL; |
291 | ||
292 | #ifndef CORE_VERSION_1 | |
293 | /* .data section if present. | |
294 | AIX 3 dumps the complete data section and sets FULL_CORE if the | |
295 | ulimit is large enough, otherwise the data section is omitted. | |
296 | AIX 4 sets FULL_CORE even if the core file is truncated, we have | |
297 | to examine coredata.c_datasize below to find out the actual size of | |
298 | the .data section. */ | |
299 | if (coredata.c_flag & FULL_CORE) | |
300 | { | |
301 | if (!make_bfd_asection (abfd, ".data", | |
302 | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | |
303 | (bfd_size_type) coredata.CORE_DATA_SIZE_FIELD, | |
304 | (bfd_vma) | |
305 | CDATA_ADDR (coredata.CORE_DATA_SIZE_FIELD), | |
306 | (file_ptr) coredata.c_stack + coredata.c_size)) | |
307 | return NULL; | |
308 | } | |
309 | #endif | |
310 | ||
311 | #ifdef CORE_VERSION_1 | |
312 | /* AIX 4 adds data sections from loaded objects to the core file, | |
313 | which can be found by examining ldinfo, and anonymously mmapped | |
314 | regions. */ | |
315 | { | |
316 | struct ld_info ldinfo; | |
317 | bfd_size_type ldinfo_size; | |
6ad49cca | 318 | file_ptr ldinfo_offset = (file_ptr) coredata.LOADER_OFFSET_FIELD; |
252b5132 RH |
319 | |
320 | /* .data section from executable. */ | |
321 | if (coredata.c_datasize) | |
322 | { | |
323 | if (!make_bfd_asection (abfd, ".data", | |
324 | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | |
325 | (bfd_size_type) coredata.c_datasize, | |
326 | (bfd_vma) | |
327 | CDATA_ADDR (coredata.CORE_DATA_SIZE_FIELD), | |
328 | (file_ptr) coredata.c_data)) | |
329 | return NULL; | |
330 | } | |
331 | ||
332 | /* .data sections from loaded objects. */ | |
333 | ldinfo_size = (char *) &ldinfo.ldinfo_filename[0] | |
334 | - (char *) &ldinfo.ldinfo_next; | |
335 | while (1) | |
336 | { | |
337 | if (bfd_seek (abfd, ldinfo_offset, SEEK_SET) != 0) | |
338 | return NULL; | |
339 | if (bfd_read (&ldinfo, ldinfo_size, 1, abfd) != ldinfo_size) | |
340 | return NULL; | |
341 | if (ldinfo.ldinfo_core) | |
342 | { | |
343 | if (!make_bfd_asection (abfd, ".data", | |
344 | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | |
345 | (bfd_size_type) ldinfo.ldinfo_datasize, | |
346 | (bfd_vma) ldinfo.ldinfo_dataorg, | |
347 | (file_ptr) ldinfo.ldinfo_core)) | |
348 | return NULL; | |
349 | } | |
350 | if (ldinfo.ldinfo_next == 0) | |
351 | break; | |
352 | ldinfo_offset += ldinfo.ldinfo_next; | |
353 | } | |
354 | ||
355 | /* .vmdata sections from anonymously mmapped regions. */ | |
356 | if (coredata.c_vmregions) | |
357 | { | |
358 | int i; | |
359 | ||
360 | if (bfd_seek (abfd, (file_ptr) coredata.c_vmm, SEEK_SET) != 0) | |
361 | return NULL; | |
362 | ||
363 | for (i = 0; i < coredata.c_vmregions; i++) | |
364 | { | |
365 | struct vm_info vminfo; | |
366 | ||
367 | if (bfd_read (&vminfo, sizeof (vminfo), 1, abfd) != sizeof (vminfo)) | |
368 | return NULL; | |
369 | if (vminfo.vminfo_offset) | |
370 | { | |
371 | if (!make_bfd_asection (abfd, ".vmdata", | |
372 | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS, | |
373 | (bfd_size_type) vminfo.vminfo_size, | |
374 | (bfd_vma) vminfo.vminfo_addr, | |
375 | (file_ptr) vminfo.vminfo_offset)) | |
376 | return NULL; | |
377 | } | |
378 | } | |
379 | } | |
380 | } | |
381 | #endif | |
382 | ||
383 | return abfd->xvec; /* this is garbage for now. */ | |
384 | } | |
385 | ||
386 | ||
387 | ||
388 | /* return `true' if given core is from the given executable.. */ | |
389 | boolean | |
390 | rs6000coff_core_file_matches_executable_p (core_bfd, exec_bfd) | |
391 | bfd *core_bfd; | |
392 | bfd *exec_bfd; | |
393 | { | |
6ad49cca | 394 | struct CORE_DUMP coredata; |
252b5132 RH |
395 | struct ld_info ldinfo; |
396 | bfd_size_type size; | |
397 | char *path, *s; | |
398 | size_t alloc; | |
399 | const char *str1, *str2; | |
400 | boolean ret; | |
401 | ||
402 | if (bfd_seek (core_bfd, 0, SEEK_SET) != 0 | |
403 | || bfd_read (&coredata, sizeof coredata, 1, core_bfd) != sizeof coredata) | |
404 | return false; | |
405 | ||
6ad49cca | 406 | if (bfd_seek (core_bfd, (long) coredata.LOADER_OFFSET_FIELD, SEEK_SET) != 0) |
252b5132 RH |
407 | return false; |
408 | ||
409 | size = (char *) &ldinfo.ldinfo_filename[0] - (char *) &ldinfo.ldinfo_next; | |
410 | if (bfd_read (&ldinfo, size, 1, core_bfd) != size) | |
411 | return false; | |
412 | ||
413 | alloc = 100; | |
414 | path = bfd_malloc (alloc); | |
415 | if (path == NULL) | |
416 | return false; | |
417 | s = path; | |
418 | ||
419 | while (1) | |
420 | { | |
421 | if (bfd_read (s, 1, 1, core_bfd) != 1) | |
422 | { | |
423 | free (path); | |
424 | return false; | |
425 | } | |
426 | if (*s == '\0') | |
427 | break; | |
428 | ++s; | |
429 | if (s == path + alloc) | |
430 | { | |
431 | char *n; | |
432 | ||
433 | alloc *= 2; | |
434 | n = bfd_realloc (path, alloc); | |
435 | if (n == NULL) | |
436 | { | |
437 | free (path); | |
438 | return false; | |
439 | } | |
440 | s = n + (path - s); | |
441 | path = n; | |
442 | } | |
443 | } | |
444 | ||
445 | str1 = strrchr (path, '/'); | |
446 | str2 = strrchr (exec_bfd->filename, '/'); | |
447 | ||
448 | /* step over character '/' */ | |
449 | str1 = str1 != NULL ? str1 + 1 : path; | |
450 | str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename; | |
451 | ||
452 | if (strcmp (str1, str2) == 0) | |
453 | ret = true; | |
454 | else | |
455 | ret = false; | |
456 | ||
457 | free (path); | |
458 | ||
459 | return ret; | |
460 | } | |
461 | ||
462 | char * | |
463 | rs6000coff_core_file_failing_command (abfd) | |
464 | bfd *abfd; | |
465 | { | |
466 | char *com = core_hdr (abfd).CORE_COMM_FIELD; | |
467 | if (*com) | |
468 | return com; | |
469 | else | |
470 | return 0; | |
471 | } | |
472 | ||
473 | int | |
474 | rs6000coff_core_file_failing_signal (abfd) | |
475 | bfd *abfd; | |
476 | { | |
477 | return core_hdr (abfd).c_signo; | |
478 | } | |
479 | ||
480 | ||
481 | boolean | |
482 | rs6000coff_get_section_contents (abfd, section, location, offset, count) | |
483 | bfd *abfd; | |
484 | sec_ptr section; | |
485 | PTR location; | |
486 | file_ptr offset; | |
487 | bfd_size_type count; | |
488 | { | |
489 | if (count == 0) | |
490 | return true; | |
491 | ||
492 | /* Reading a core file's sections will be slightly different. For the | |
493 | rest of them we can use bfd_generic_get_section_contents () I suppose. */ | |
494 | /* Make sure this routine works for any bfd and any section. FIXMEmgo. */ | |
495 | ||
496 | if (abfd->format == bfd_core && strcmp (section->name, ".reg") == 0) { | |
497 | ||
498 | struct mstsave mstatus; | |
499 | int regoffset = (char*)&mstatus.gpr[0] - (char*)&mstatus; | |
500 | ||
501 | /* Assert that the only way this code will be executed is reading the | |
502 | whole section. */ | |
503 | if (offset || count != (sizeof(mstatus.gpr) + (4 * NUM_OF_SPEC_REGS))) | |
504 | (*_bfd_error_handler) | |
505 | (_("ERROR! in rs6000coff_get_section_contents()\n")); | |
506 | ||
507 | /* for `.reg' section, `filepos' is a pointer to the `mstsave' structure | |
508 | in the core file. */ | |
509 | ||
510 | /* read GPR's into the location. */ | |
511 | if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 | |
512 | || bfd_read(location, sizeof (mstatus.gpr), 1, abfd) != sizeof (mstatus.gpr)) | |
513 | return (false); /* on error */ | |
514 | ||
515 | /* increment location to the beginning of special registers in the section, | |
516 | reset register offset value to the beginning of first special register | |
517 | in mstsave structure, and read special registers. */ | |
518 | ||
519 | location = (PTR) ((char*)location + sizeof (mstatus.gpr)); | |
520 | regoffset = (char*)&mstatus.iar - (char*)&mstatus; | |
521 | ||
522 | if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 | |
523 | || bfd_read(location, 4 * NUM_OF_SPEC_REGS, 1, abfd) != | |
524 | 4 * NUM_OF_SPEC_REGS) | |
525 | return (false); /* on error */ | |
526 | ||
527 | /* increment location address, and read the special registers.. */ | |
528 | /* FIXMEmgo */ | |
529 | return (true); | |
530 | } | |
531 | ||
532 | /* else, use default bfd section content transfer. */ | |
533 | else | |
534 | return _bfd_generic_get_section_contents | |
535 | (abfd, section, location, offset, count); | |
536 | } | |
537 | ||
538 | #endif /* AIX_CORE */ |