Initial revision
[binutils-gdb.git] / bfd / coff-rs6000.c
1 /* IBM RS/6000 "XCOFF" back-end for BFD.
2 Copyright (C) 1990, 1991 Free Software Foundation, Inc.
3 Written by Metin G. Ozisik, Mimi Phûông-Thåo Võ, and John Gilmore.
4 Archive support from Damon A. Permezel.
5 Contributed by IBM Corporation and Cygnus Support.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
22
23 /* This port currently only handles reading object files -- no archive
24 support, no core files, and no writing. FIXME. */
25
26 /* Internalcoff.h and coffcode.h modify themselves based on this flag. */
27 #define RS6000COFF_C 1
28
29 #include <ansidecl.h>
30 #include <sysdep.h>
31 #include "bfd.h"
32 #include "libbfd.h"
33 #include "obstack.h"
34 #include "internalcoff.h"
35 #include "rs6000coff.h"
36 #include "libcoff.h"
37
38 /* The main body of code is in coffcode.h. */
39 #include "coffcode.h"
40
41
42 #if 0
43 /* These are not yet ready for prime time. */
44 #define coff_core_file_matches_executable_p \
45 rs6000coff_core_file_matches_executable_p
46 #define coff_get_section_contents rs6000coff_get_section_contents
47 #define coff_openr_next_archived_file rs6000coff_openr_next_archived_file
48 #define coff_write_armap rs6000coff_write_armap
49 #define coff_stat_arch_elt rs6000coff_stat_arch_elt
50 #define coff_snarf_ar_hdr rs6000coff_snarf_ar_hdr
51 #define coff_mkarchive rs6000coff_mkarchive
52
53 static bfd_target *rs6000coff_archive_p ();
54 static bfd_target *rs6000coff_core_p ();
55 static bfd_target *rs6000coff_object_p ();
56 static bfd_target *rs6000coff_real_object_p ();
57 #endif
58
59 bfd_target rs6000coff_vec =
60 {
61 "coff_rs6000", /* name */
62 bfd_target_coff_flavour,
63 true, /* data byte order is big */
64 true, /* header byte order is big */
65
66 (HAS_RELOC | EXEC_P | /* object flags */
67 HAS_LINENO | HAS_DEBUG |
68 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
69
70 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
71 '/', /* ar_pad_char */
72 15, /* ar_max_namelen??? FIXMEmgo */
73 3, /* default alignment power */
74
75 _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* data */
76 _do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* hdrs */
77
78 {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
79 bfd_generic_archive_p, _bfd_dummy_target},
80 {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
81 bfd_false},
82 {bfd_false, coff_write_object_contents, /* bfd_write_contents */
83 _bfd_write_archive_contents, bfd_false},
84
85 JUMP_TABLE(coff),
86 COFF_SWAP_TABLE
87
88 };
89
90
91 #if 0 /* we don't have include file for this yet */
92 /* ------------------------------------------------------------------------ */
93 /* Support for archive file stuff.. */
94 /* Stolen from Damon A. Parmazel's `bfd' portation. */
95 /* ------------------------------------------------------------------------ */
96
97 #include "/usr/include/ar.h" /* <ar.h> doesn't do it. */
98
99
100 #define arch_hdr(bfd) \
101 ((struct ar_hdr *) \
102 (((struct areltdata *)((bfd)->arelt_data))->arch_header))
103
104
105 static boolean
106 rs6000coff_mkarchive (abfd)
107 bfd *abfd;
108 {
109 bfd_error = invalid_operation; /* write not supported */
110 }
111
112
113 /* This functions reads an arch header and returns an areltdata pointer, or
114 NULL on error.
115
116 Presumes the file pointer is already in the right place (ie pointing
117 to the ar_hdr in the file). Moves the file pointer; on success it
118 should be pointing to the front of the file contents; on failure it
119 could have been moved arbitrarily.
120 */
121
122 struct areltdata *
123 rs6000coff_snarf_ar_hdr (abfd)
124 bfd *abfd;
125 {
126 extern int errno;
127
128 struct {
129 struct ar_hdr hdr;
130 char namebuf[256];
131 } h;
132 int size;
133 struct areltdata *ared;
134 unsigned int namelen = 0;
135 char *allocptr;
136
137 size = sizeof (h.hdr);
138 if (bfd_read(&h.hdr, 1, size, abfd) != size) {
139 bfd_error = no_more_archived_files;
140 return NULL;
141 }
142 size = atoi(h.hdr.ar_namlen); /* ar_name[] length */
143 size += size & 1;
144
145 if (bfd_read(&h.hdr._ar_name.ar_name[2], 1, size, abfd) != size) {
146 bfd_error = no_more_archived_files;
147 return NULL;
148 }
149
150 if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) {
151 bfd_error = malformed_archive;
152 return NULL;
153 }
154
155 h.hdr._ar_name.ar_name[size] = 0; /* terminate filename */
156
157 /*
158 * if the filename is NULL, we're (probably) at the end.
159 */
160 if (size == 0) {
161 bfd_error = no_more_archived_files;
162 return NULL;
163 }
164
165 size += sizeof (h.hdr);
166 allocptr = bfd_zalloc(abfd, sizeof (*ared) + size);
167
168 if (allocptr == NULL) {
169 bfd_error = no_memory;
170 return NULL;
171 }
172
173 ared = (struct areltdata *) allocptr;
174
175 ared->arch_header = (void *) (allocptr + sizeof (struct areltdata));
176 memcpy ((char *) ared->arch_header, &h.hdr, size);
177 ared->parsed_size = atoi(h.hdr.ar_size);
178 ared->filename = ((AR_HDR*) ared->arch_header)->_ar_name.ar_name;
179
180 return ared;
181 }
182
183 /*
184 * xcoff_openr_next_archived_file - xcoff has nxt/prv seek addrs.
185 */
186 static bfd *
187 rs6000coff_openr_next_archived_file(archive, last_file)
188 bfd *archive, *last_file;
189 {
190 file_ptr filestart;
191
192 if (!last_file)
193 filestart = bfd_ardata(archive)->first_file_filepos;
194 else
195 filestart = atol(arch_hdr(last_file)->ar_nxtmem);
196
197 return get_elt_at_filepos (archive, filestart);
198 }
199
200
201 static bfd_target *
202 rs6000coff_archive_p (abfd)
203 bfd *abfd;
204 {
205 struct fl_hdr hdr;
206 register struct artdata *art;
207
208 if (bfd_read (&hdr, 1, sizeof (hdr), abfd) != sizeof (hdr)) {
209 bfd_error = wrong_format;
210 return 0;
211 }
212
213 if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) {
214 bfd_error = wrong_format;
215 return 0;
216 }
217
218 /*
219 * bfd_ardata() accesses the bfd->tdata field.
220 */
221 abfd->tdata = (void *) bfd_zalloc(abfd, sizeof (*art) + sizeof (hdr));
222 if ((art = bfd_ardata (abfd)) == NULL) {
223 bfd_error = no_memory;
224 return 0;
225 }
226
227 art->first_file_filepos = atoi(hdr.fl_fstmoff);
228 *(struct fl_hdr *) (1 + art) = hdr;
229
230 /*
231 * slurp in the member table, which I thing is the armap equivalent.
232 xcoff_slurp_armap(abfd);
233 */
234
235 if (abfd->obj_arch == bfd_arch_unknown) /* FIXME!!! */
236 abfd->obj_arch = bfd_arch_rs6000;
237
238 return abfd->xvec;
239 }
240
241
242 static int
243 rs6000coff_stat_arch_elt(abfd, buf)
244 bfd *abfd;
245 struct stat *buf;
246 {
247 struct ar_hdr *hdr;
248 char *aloser;
249
250 if (abfd->arelt_data == NULL) {
251 bfd_error = invalid_operation;
252 return -1;
253 }
254
255 hdr = arch_hdr (abfd);
256
257 #define foo(arelt, stelt, size) \
258 buf->stelt = strtol (hdr->arelt, &aloser, size); \
259 if (aloser == hdr->arelt) return -1;
260
261 foo (ar_date, st_mtime, 10);
262 foo (ar_uid, st_uid, 10);
263 foo (ar_gid, st_gid, 10);
264 foo (ar_mode, st_mode, 8);
265 foo (ar_size, st_size, 10);
266
267 return 0;
268 }
269
270 static boolean
271 rs6000coff_write_armap (arch, elength, map, orl_count, stridx)
272 bfd *arch;
273 unsigned int elength;
274 struct orl *map;
275 {
276 bfd_error = invalid_operation;
277 return false;
278 }
279
280
281 #endif /* if 0 */
282
283 #if 0 /* not sure if this will work on all hosts yet! */
284 #ifdef AOUTHDR
285 #undef AOUTHDR
286 #endif
287
288 /* ------------------------------------------------------------------------ */
289 /* Support for core file stuff.. */
290 /* ------------------------------------------------------------------------ */
291
292 #include <sys/user.h>
293 #include <sys/ldr.h>
294 #include <sys/core.h>
295
296
297 /* Number of special purpose registers supported bygdb. This value should match
298 `tm.h' in gdb directory. Clean this mess up and use the macros in sys/reg.h.
299 FIXMEmgo. */
300
301 #define NUM_OF_SPEC_REGS 7
302 #define STACK_END_ADDR 0x2ff80000
303
304 #define core_hdr(bfd) (((Rs6kCorData*)(bfd->tdata))->hdr)
305 #define core_datasec(bfd) (((Rs6kCorData*)(bfd->tdata))->data_section)
306 #define core_stacksec(bfd) (((Rs6kCorData*)(bfd->tdata))->stack_section)
307 #define core_regsec(bfd) (((Rs6kCorData*)(bfd->tdata))->reg_section)
308 #define core_reg2sec(bfd) (((Rs6kCorData*)(bfd->tdata))->reg2_section)
309
310 /* These are stored in the bfd's tdata */
311 typedef struct {
312 struct core *hdr; /* core file header */
313 asection *data_section,
314 *stack_section,
315 *reg_section, /* section for GPRs and special registers. */
316 *reg2_section; /* section for FPRs. */
317 } Rs6kCorData;
318
319
320 /* Decide if a given bfd represents a `core' file or not. There really is no
321 magic number or anything like, in rs6000coff. */
322
323 static bfd_target *
324 rs6000coff_core_p (abfd)
325 bfd *abfd;
326 {
327 int fd;
328 struct core_dump coredata;
329 struct stat statbuf;
330 char *tmpptr;
331
332 /* Use bfd_xxx routines, rather than O/S primitives to read coredata. FIXMEmgo */
333 fd = open (abfd->filename, O_RDONLY);
334
335 fstat (fd, &statbuf);
336 read (fd, &coredata, sizeof (struct core_dump));
337
338 close (fd);
339
340 if (coredata.c_tab < (sizeof (coredata.c_u) + (int)&coredata.c_u - (int)&coredata.c_signo) ||
341 coredata.c_tab >= statbuf.st_size ||
342 (long)coredata.c_stack <= (long)coredata.c_tab ) {
343 return NULL;
344 }
345
346 /*
347 If it looks like core file, then.....
348 read core file header..... (maybe you've done it above..)
349 */
350
351 /* maybe you should alloc space for the whole core chunk over here!! FIXMEmgo */
352 tmpptr = (char*)bfd_zalloc (abfd, sizeof (Rs6kCorData));
353 set_tdata (abfd, tmpptr);
354
355 /* .stack section. */
356 if ((core_stacksec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection)))
357 == NULL) {
358 bfd_error = no_memory;
359 /* bfd_release (abfd, ???? ) */
360 return NULL;
361 }
362 core_stacksec (abfd)->name = ".stack";
363 core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD;
364 core_stacksec (abfd)->size = coredata.c_size;
365 core_stacksec (abfd)->vma = STACK_END_ADDR - coredata.c_size;
366 core_stacksec (abfd)->filepos = coredata.c_stack; /*???? */
367
368 /* .reg section for GPRs and special registers. */
369 if ((core_regsec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection)))
370 == NULL) {
371 bfd_error = no_memory;
372 /* bfd_release (abfd, ???? ) */
373 return NULL;
374 }
375 core_regsec (abfd)->name = ".reg";
376 core_regsec (abfd)->flags = SEC_ALLOC;
377 core_regsec (abfd)->size = (32 + NUM_OF_SPEC_REGS) * 4;
378 core_regsec (abfd)->vma = NULL; /* not used?? */
379 core_regsec (abfd)->filepos =
380 (char*)&coredata.c_u.u_save - (char*)&coredata;
381
382 /* .reg2 section for FPRs (floating point registers). */
383 if ((core_reg2sec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection)))
384 == NULL) {
385 bfd_error = no_memory;
386 /* bfd_release (abfd, ???? ) */
387 return NULL;
388 }
389 core_reg2sec (abfd)->name = ".reg2";
390 core_reg2sec (abfd)->flags = SEC_ALLOC;
391 core_reg2sec (abfd)->size = 8 * 32; /* 32 FPRs. */
392 core_reg2sec (abfd)->vma = NULL; /* not used?? */
393 core_reg2sec (abfd)->filepos =
394 (char*)&coredata.c_u.u_save.fpr[0] - (char*)&coredata;
395
396 /* set up section chain here. */
397 abfd->section_count = 3;
398 abfd->sections = core_stacksec (abfd);
399 core_stacksec (abfd)->next = core_regsec(abfd);
400 core_regsec (abfd)->next = core_reg2sec (abfd);
401 core_reg2sec (abfd)->next = NULL;
402
403 return abfd->xvec; /* this is garbage for now. */
404 }
405
406
407
408 /* return `true' if given core is from the given executable.. */
409 static boolean
410 rs6000coff_core_file_matches_executable_p (core_bfd, exec_bfd)
411 bfd *core_bfd;
412 bfd *exec_bfd;
413 {
414 FILE *fd;
415 struct core_dump coredata;
416 struct ld_info ldinfo;
417 char pathname [1024];
418 char *str1, *str2;
419
420 /* Use bfd_xxx routines, rather than O/S primitives, do error checking!!
421 FIXMEmgo */
422 fd = fopen (core_bfd->filename, "r");
423
424 fread (&coredata, sizeof (struct core_dump), 1, fd);
425 fseek (fd, (long)coredata.c_tab, 0);
426 fread (&ldinfo, (char*)&ldinfo.ldinfo_filename[0] - (char*)&ldinfo.ldinfo_next,
427 1, fd);
428 fscanf (fd, "%s", pathname);
429 printf ("path: %s\n", pathname);
430
431 str1 = strrchr (pathname, '/');
432 str2 = strrchr (exec_bfd->filename, '/');
433
434 /* step over character '/' */
435 str1 = str1 ? str1+1 : &pathname[0];
436 str2 = str2 ? str2+1 : exec_bfd->filename;
437
438 fclose (fd);
439 return strcmp (str1, str2);
440 }
441
442
443 static boolean
444 rs6000coff_get_section_contents (abfd, section, location, offset, count)
445 bfd *abfd;
446 sec_ptr section;
447 PTR location;
448 file_ptr offset;
449 int count;
450 {
451 if (count == 0)
452 return true;
453
454 /* Reading a core file's sections will be slightly different. For the
455 rest of them we can use bfd_generic_get_section_contents () I suppose. */
456 /* Make sure this routine works for any bfd and any section. FIXMEmgo. */
457
458 if (abfd->format == bfd_core && strcmp (section->name, ".reg") == 0) {
459
460 struct mstsave mstatus;
461 int regoffset = (char*)&mstatus.gpr[0] - (char*)&mstatus;
462
463 /* Assert that the only way this code will be executed is reading the
464 whole section. */
465 if (offset || count != (sizeof(mstatus.gpr) + (4 * NUM_OF_SPEC_REGS)))
466 printf ("ERROR! in rs6000coff_get_section_contents()\n");
467
468 /* for `.reg' section, `filepos' is a pointer to the `mstsave' structure
469 in the core file. */
470
471 /* read GPR's into the location. */
472 if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1
473 || bfd_read(location, 1, sizeof (mstatus.gpr), abfd) != sizeof (mstatus.gpr))
474 return (false); /* on error */
475
476 /* increment location to the beginning of special registers in the section,
477 reset register offset value to the beginning of first special register
478 in mstsave structure, and read special registers. */
479
480 location = (PTR) ((char*)location + sizeof (mstatus.gpr));
481 regoffset = (char*)&mstatus.iar - (char*)&mstatus;
482
483 if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1
484 || bfd_read(location, 1, 4 * NUM_OF_SPEC_REGS, abfd) !=
485 4 * NUM_OF_SPEC_REGS)
486 return (false); /* on error */
487
488 /* increment location address, and read the special registers.. */
489 /* FIXMEmgo */
490 return (true);
491 }
492
493 /* else, use default bfd section content transfer. */
494 else
495 return bfd_generic_get_section_contents
496 (abfd, section, location, offset, count);
497 }
498
499 #endif /* if 0 - for CORE */
500