Initial revision
[external/binutils.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