]>
Commit | Line | Data |
---|---|---|
9783e04a DM |
1 | /* IBM RS/6000 "XCOFF" back-end for BFD. |
2 | Copyright (C) 1990, 1991 Free Software Foundation, Inc. | |
3 | FIXME: Can someone provide a transliteration of this name into ASCII? | |
4 | Using the following chars caused a compiler warning on HIUX (so I replaced | |
5 | them with octal escapes), and isn't useful without an understanding of what | |
6 | character set it is. | |
7 | Written by Metin G. Ozisik, Mimi Ph\373\364ng-Th\345o V\365, | |
8 | and John Gilmore. | |
9 | Archive support from Damon A. Permezel. | |
10 | Contributed by IBM Corporation and Cygnus Support. | |
11 | ||
12 | This file is part of BFD, the Binary File Descriptor library. | |
13 | ||
14 | This program is free software; you can redistribute it and/or modify | |
15 | it under the terms of the GNU General Public License as published by | |
16 | the Free Software Foundation; either version 2 of the License, or | |
17 | (at your option) any later version. | |
18 | ||
19 | This program is distributed in the hope that it will be useful, | |
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | GNU General Public License for more details. | |
23 | ||
24 | You should have received a copy of the GNU General Public License | |
25 | along with this program; if not, write to the Free Software | |
26 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
27 | ||
28 | /* This port currently only handles reading object files, except when | |
29 | compiled on an RS/6000 host. -- no archive support, no core files. | |
30 | In all cases, it does not support writing. | |
31 | ||
32 | FIXMEmgo comments are left from Metin Ozisik's original port. | |
33 | ||
34 | This is in a separate file from coff-rs6000.c, because it includes | |
35 | system include files that conflict with coff/rs6000.h. | |
36 | */ | |
37 | ||
38 | /* Internalcoff.h and coffcode.h modify themselves based on this flag. */ | |
39 | #define RS6000COFF_C 1 | |
40 | ||
41 | #include "bfd.h" | |
42 | #include "sysdep.h" | |
43 | #include "libbfd.h" | |
44 | ||
8b8ddedb | 45 | #ifdef HOST_AIX |
9783e04a DM |
46 | |
47 | /* AOUTHDR is defined by the above. We need another defn of it, from the | |
48 | system include files. Punt the old one and get us a new name for the | |
49 | typedef in the system include files. */ | |
50 | #ifdef AOUTHDR | |
51 | #undef AOUTHDR | |
52 | #endif | |
53 | #define AOUTHDR second_AOUTHDR | |
54 | ||
55 | #undef SCNHDR | |
56 | ||
57 | ||
58 | /* ------------------------------------------------------------------------ */ | |
59 | /* Support for core file stuff.. */ | |
60 | /* ------------------------------------------------------------------------ */ | |
61 | ||
62 | #include <sys/user.h> | |
63 | #include <sys/ldr.h> | |
64 | #include <sys/core.h> | |
65 | ||
66 | ||
67 | /* Number of special purpose registers supported by gdb. This value | |
68 | should match `tm.h' in gdb directory. Clean this mess up and use | |
69 | the macros in sys/reg.h. FIXMEmgo. */ | |
70 | ||
71 | #define NUM_OF_SPEC_REGS 7 | |
72 | #define STACK_END_ADDR 0x2ff80000 | |
73 | ||
74 | #define core_hdr(bfd) (((Rs6kCorData*)(bfd->tdata.any))->hdr) | |
75 | #define core_datasec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->data_section) | |
76 | #define core_stacksec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->stack_section) | |
77 | #define core_regsec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->reg_section) | |
78 | #define core_reg2sec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->reg2_section) | |
79 | ||
80 | /* These are stored in the bfd's tdata */ | |
81 | typedef struct { | |
82 | struct core *hdr; /* core file header */ | |
83 | asection *data_section, | |
84 | *stack_section, | |
85 | *reg_section, /* section for GPRs and special registers. */ | |
86 | *reg2_section; /* section for FPRs. */ | |
87 | ||
88 | /* This tells us where everything is mapped (shared libraries and so on). | |
89 | GDB needs it. */ | |
90 | asection *ldinfo_section; | |
91 | #define core_ldinfosec(bfd) (((Rs6kCorData *)(bfd->tdata.any))->ldinfo_section) | |
92 | } Rs6kCorData; | |
93 | ||
94 | ||
95 | /* Decide if a given bfd represents a `core' file or not. There really is no | |
96 | magic number or anything like, in rs6000coff. */ | |
97 | ||
98 | bfd_target * | |
99 | rs6000coff_core_p (abfd) | |
100 | bfd *abfd; | |
101 | { | |
102 | int fd; | |
103 | struct core_dump coredata; | |
104 | struct stat statbuf; | |
105 | char *tmpptr; | |
106 | ||
107 | /* Use bfd_xxx routines, rather than O/S primitives to read coredata. FIXMEmgo */ | |
108 | fd = open (abfd->filename, O_RDONLY); | |
109 | if (fd < 0) | |
110 | { | |
111 | bfd_error = system_call_error; | |
112 | return NULL; | |
113 | } | |
114 | ||
115 | if (fstat (fd, &statbuf) < 0) | |
116 | { | |
117 | bfd_error = system_call_error; | |
118 | close (fd); | |
119 | return NULL; | |
120 | } | |
121 | if (read (fd, &coredata, sizeof (struct core_dump)) | |
122 | != sizeof (struct core_dump)) | |
123 | { | |
124 | bfd_error = wrong_format; | |
125 | close (fd); | |
126 | return NULL; | |
127 | } | |
128 | ||
129 | if (close (fd) < 0) | |
130 | { | |
131 | bfd_error = system_call_error; | |
132 | return NULL; | |
133 | } | |
134 | ||
135 | /* If the core file ulimit is too small, the system will first | |
136 | omit the data segment, then omit the stack, then decline to | |
137 | dump core altogether (as far as I know UBLOCK_VALID and LE_VALID | |
138 | are always set) (this is based on experimentation on AIX 3.2). | |
139 | Now, the thing is that GDB users will be surprised | |
140 | if segments just silently don't appear (well, maybe they would | |
141 | think to check "info files", I don't know), but we have no way of | |
142 | returning warnings (as opposed to errors). | |
143 | ||
144 | For the data segment, we have no choice but to keep going if it's | |
145 | not there, since the default behavior is not to dump it (regardless | |
146 | of the ulimit, it's based on SA_FULLDUMP). But for the stack segment, | |
147 | if it's not there, we refuse to have anything to do with this core | |
148 | file. The usefulness of a core dump without a stack segment is pretty | |
149 | limited anyway. */ | |
150 | ||
151 | if (!(coredata.c_flag & UBLOCK_VALID) | |
152 | || !(coredata.c_flag & LE_VALID)) | |
153 | { | |
154 | bfd_error = wrong_format; | |
155 | return NULL; | |
156 | } | |
157 | ||
158 | if ((coredata.c_flag & CORE_TRUNC) | |
159 | || !(coredata.c_flag & USTACK_VALID)) | |
160 | { | |
161 | bfd_error = file_truncated; | |
162 | return NULL; | |
163 | } | |
164 | ||
165 | if (((bfd_vma)coredata.c_stack + coredata.c_size | |
166 | + ((coredata.c_flag & FULL_CORE) ? coredata.c_u.u_dsize : 0)) | |
167 | != statbuf.st_size) | |
168 | { | |
169 | /* If the size is wrong, it means we're misinterpreting something. */ | |
170 | bfd_error = wrong_format; | |
171 | return NULL; | |
172 | } | |
173 | ||
174 | /* Sanity check on the c_tab field. */ | |
175 | if ((u_long) coredata.c_tab < sizeof coredata || | |
176 | (u_long) coredata.c_tab >= statbuf.st_size || | |
177 | (long) coredata.c_tab >= (long)coredata.c_stack) | |
178 | { | |
179 | bfd_error = wrong_format; | |
180 | return NULL; | |
181 | } | |
182 | ||
183 | /* maybe you should alloc space for the whole core chunk over here!! FIXMEmgo */ | |
184 | tmpptr = (char*)bfd_zalloc (abfd, sizeof (Rs6kCorData)); | |
185 | if (!tmpptr) | |
186 | { | |
187 | bfd_error = no_memory; | |
188 | return NULL; | |
189 | } | |
190 | ||
191 | set_tdata (abfd, tmpptr); | |
192 | ||
193 | /* .stack section. */ | |
194 | if ((core_stacksec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) | |
195 | == NULL) { | |
196 | bfd_error = no_memory; | |
197 | /* bfd_release (abfd, ???? ) */ | |
198 | return NULL; | |
199 | } | |
200 | core_stacksec (abfd)->name = ".stack"; | |
201 | core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD; | |
202 | core_stacksec (abfd)->_raw_size = coredata.c_size; | |
203 | core_stacksec (abfd)->vma = STACK_END_ADDR - coredata.c_size; | |
204 | core_stacksec (abfd)->filepos = (int)coredata.c_stack; /*???? */ | |
205 | ||
206 | /* .reg section for GPRs and special registers. */ | |
207 | if ((core_regsec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) | |
208 | == NULL) { | |
209 | bfd_error = no_memory; | |
210 | /* bfd_release (abfd, ???? ) */ | |
211 | return NULL; | |
212 | } | |
213 | core_regsec (abfd)->name = ".reg"; | |
214 | core_regsec (abfd)->flags = SEC_ALLOC; | |
215 | core_regsec (abfd)->_raw_size = (32 + NUM_OF_SPEC_REGS) * 4; | |
216 | core_regsec (abfd)->vma = 0; /* not used?? */ | |
217 | core_regsec (abfd)->filepos = | |
218 | (char*)&coredata.c_u.u_save - (char*)&coredata; | |
219 | ||
220 | /* .reg2 section for FPRs (floating point registers). */ | |
221 | if ((core_reg2sec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) | |
222 | == NULL) { | |
223 | bfd_error = no_memory; | |
224 | /* bfd_release (abfd, ???? ) */ | |
225 | return NULL; | |
226 | } | |
227 | core_reg2sec (abfd)->name = ".reg2"; | |
228 | core_reg2sec (abfd)->flags = SEC_ALLOC; | |
229 | core_reg2sec (abfd)->_raw_size = 8 * 32; /* 32 FPRs. */ | |
230 | core_reg2sec (abfd)->vma = 0; /* not used?? */ | |
231 | core_reg2sec (abfd)->filepos = | |
232 | (char*)&coredata.c_u.u_save.fpr[0] - (char*)&coredata; | |
233 | ||
234 | if ((core_ldinfosec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) | |
235 | == NULL) { | |
236 | bfd_error = no_memory; | |
237 | /* bfd_release (abfd, ???? ) */ | |
238 | return NULL; | |
239 | } | |
240 | core_ldinfosec (abfd)->name = ".ldinfo"; | |
241 | core_ldinfosec (abfd)->flags = SEC_ALLOC + SEC_LOAD; | |
242 | /* To actually find out how long this section is in this particular | |
243 | core dump would require going down the whole list of struct ld_info's. | |
244 | See if we can just fake it. */ | |
245 | core_ldinfosec (abfd)->_raw_size = 0x7fffffff; | |
246 | /* Not relevant for ldinfo section. */ | |
247 | core_ldinfosec (abfd)->vma = 0; | |
248 | core_ldinfosec (abfd)->filepos = coredata.c_tab; | |
249 | ||
250 | /* set up section chain here. */ | |
251 | abfd->section_count = 4; | |
252 | abfd->sections = core_stacksec (abfd); | |
253 | core_stacksec (abfd)->next = core_regsec(abfd); | |
254 | core_regsec (abfd)->next = core_reg2sec (abfd); | |
255 | core_reg2sec (abfd)->next = core_ldinfosec (abfd); | |
256 | core_ldinfosec (abfd)->next = NULL; | |
257 | ||
258 | if (coredata.c_flag & FULL_CORE) | |
259 | { | |
260 | asection *sec = (asection *) bfd_zalloc (abfd, sizeof (asection)); | |
261 | if (sec == NULL) | |
262 | { | |
263 | bfd_error = no_memory; | |
264 | return NULL; | |
265 | } | |
266 | sec->name = ".data"; | |
267 | sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; | |
268 | sec->_raw_size = coredata.c_u.u_dsize; | |
269 | sec->vma = CDATA_ADDR (coredata.c_u.u_dsize); | |
270 | sec->filepos = (int)coredata.c_stack + coredata.c_size; | |
271 | ||
272 | sec->next = abfd->sections; | |
273 | abfd->sections = sec; | |
274 | ++abfd->section_count; | |
275 | } | |
276 | ||
277 | return abfd->xvec; /* this is garbage for now. */ | |
278 | } | |
279 | ||
280 | ||
281 | ||
282 | /* return `true' if given core is from the given executable.. */ | |
283 | boolean | |
284 | rs6000coff_core_file_matches_executable_p (core_bfd, exec_bfd) | |
285 | bfd *core_bfd; | |
286 | bfd *exec_bfd; | |
287 | { | |
288 | FILE *fd; | |
289 | struct core_dump coredata; | |
290 | struct ld_info ldinfo; | |
291 | char pathname [1024]; | |
292 | char *str1, *str2; | |
293 | ||
294 | /* Use bfd_xxx routines, rather than O/S primitives, do error checking!! | |
295 | FIXMEmgo */ | |
296 | /* Actually should be able to use bfd_get_section_contents now that | |
297 | we have a .ldinfo section. */ | |
298 | fd = fopen (core_bfd->filename, FOPEN_RB); | |
299 | ||
300 | fread (&coredata, sizeof (struct core_dump), 1, fd); | |
301 | fseek (fd, (long)coredata.c_tab, 0); | |
302 | fread (&ldinfo, (char*)&ldinfo.ldinfo_filename[0] - (char*)&ldinfo.ldinfo_next, | |
303 | 1, fd); | |
304 | fscanf (fd, "%s", pathname); | |
305 | ||
306 | str1 = strrchr (pathname, '/'); | |
307 | str2 = strrchr (exec_bfd->filename, '/'); | |
308 | ||
309 | /* step over character '/' */ | |
310 | str1 = str1 ? str1+1 : &pathname[0]; | |
311 | str2 = str2 ? str2+1 : exec_bfd->filename; | |
312 | ||
313 | fclose (fd); | |
314 | return strcmp (str1, str2) == 0; | |
315 | } | |
316 | ||
317 | ||
318 | boolean | |
319 | rs6000coff_get_section_contents (abfd, section, location, offset, count) | |
320 | bfd *abfd; | |
321 | sec_ptr section; | |
322 | PTR location; | |
323 | file_ptr offset; | |
324 | int count; | |
325 | { | |
326 | if (count == 0) | |
327 | return true; | |
328 | ||
329 | /* Reading a core file's sections will be slightly different. For the | |
330 | rest of them we can use bfd_generic_get_section_contents () I suppose. */ | |
331 | /* Make sure this routine works for any bfd and any section. FIXMEmgo. */ | |
332 | ||
333 | if (abfd->format == bfd_core && strcmp (section->name, ".reg") == 0) { | |
334 | ||
335 | struct mstsave mstatus; | |
336 | int regoffset = (char*)&mstatus.gpr[0] - (char*)&mstatus; | |
337 | ||
338 | /* Assert that the only way this code will be executed is reading the | |
339 | whole section. */ | |
340 | if (offset || count != (sizeof(mstatus.gpr) + (4 * NUM_OF_SPEC_REGS))) | |
341 | fprintf (stderr, "ERROR! in rs6000coff_get_section_contents()\n"); | |
342 | ||
343 | /* for `.reg' section, `filepos' is a pointer to the `mstsave' structure | |
344 | in the core file. */ | |
345 | ||
346 | /* read GPR's into the location. */ | |
347 | if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 | |
348 | || bfd_read(location, sizeof (mstatus.gpr), 1, abfd) != sizeof (mstatus.gpr)) | |
349 | return (false); /* on error */ | |
350 | ||
351 | /* increment location to the beginning of special registers in the section, | |
352 | reset register offset value to the beginning of first special register | |
353 | in mstsave structure, and read special registers. */ | |
354 | ||
355 | location = (PTR) ((char*)location + sizeof (mstatus.gpr)); | |
356 | regoffset = (char*)&mstatus.iar - (char*)&mstatus; | |
357 | ||
358 | if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 | |
359 | || bfd_read(location, 4 * NUM_OF_SPEC_REGS, 1, abfd) != | |
360 | 4 * NUM_OF_SPEC_REGS) | |
361 | return (false); /* on error */ | |
362 | ||
363 | /* increment location address, and read the special registers.. */ | |
364 | /* FIXMEmgo */ | |
365 | return (true); | |
366 | } | |
367 | ||
368 | /* else, use default bfd section content transfer. */ | |
369 | else | |
370 | return bfd_generic_get_section_contents | |
371 | (abfd, section, location, offset, count); | |
372 | } | |
373 | ||
8b8ddedb | 374 | #endif /* HOST_AIX */ |