* opncls.c (_bfd_new_bfd, _bfd_new_bfd_contained_in): Add
[external/binutils.git] / bfd / coff-rs6000.c
1 /* BFD back-end for IBM RS/6000 "XCOFF" files.
2    Copyright 1990, 1991, 1992, 1993 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 /* Internalcoff.h and coffcode.h modify themselves based on this flag.  */
35 #define RS6000COFF_C 1
36
37 #include "bfd.h"
38 #include "sysdep.h"
39 #include "libbfd.h"
40 #include "obstack.h"
41 #include "coff/internal.h"
42 #include "coff/rs6000.h"
43 #include "libcoff.h"
44
45 /* The main body of code is in coffcode.h.  */
46
47 /* Can't read rs6000 relocs */
48 static reloc_howto_type dummy_reloc =
49   HOWTO (0,                     /* type */
50          0,                     /* rightshift */
51          0,                     /* size (0 = byte, 1 = short, 2 = long) */
52          8,                     /* bitsize */
53          false,                 /* pc_relative */
54          0,                     /* bitpos */
55          complain_overflow_dont, /* complain_on_overflow */
56          0,                     /* special_function */
57          "UNKNOWN",             /* name */
58          false,                 /* partial_inplace */
59          0,                     /* src_mask */
60          0,                     /* dst_mask */
61          false);                /* pcrel_offset */
62
63 #define RTYPE2HOWTO(cache_ptr, dst) cache_ptr->howto = &dummy_reloc;
64
65 #include "coffcode.h"
66
67 #define coff_archive_p          bfd_generic_archive_p
68 #define coff_mkarchive          _bfd_generic_mkarchive
69
70 #ifdef ARCHIVES_PLEASE
71
72 /* ------------------------------------------------------------------------ */
73 /*      Support for archive file stuff..                                    */
74 /*      Stolen from Damon A. Permezel's `bfd' portation.                    */
75 /* ------------------------------------------------------------------------ */
76
77 #undef  coff_openr_next_archived_file
78 #define coff_openr_next_archived_file   rs6000coff_openr_next_archived_file
79
80 #undef  coff_write_armap
81 #define coff_write_armap                rs6000coff_write_armap
82
83 #undef  coff_stat_arch_elt
84 #define coff_stat_arch_elt              rs6000coff_stat_arch_elt
85
86 #undef  coff_snarf_ar_hdr
87 #define coff_snarf_ar_hdr               rs6000coff_snarf_ar_hdr
88
89 #undef  coff_mkarchive
90 #define coff_mkarchive                  rs6000coff_mkarchive
91
92 #undef  coff_archive_p
93 #define coff_archive_p                  rs6000coff_archive_p
94
95 #include "/usr/include/ar.h"            /* <ar.h> doesn't do it.        */
96
97
98 #define arch_hdr(bfd)           \
99         ((struct ar_hdr *)      \
100          (((struct areltdata *)((bfd)->arelt_data))->arch_header))
101
102
103 static boolean
104 rs6000coff_mkarchive (abfd)
105      bfd *abfd;
106 {
107         bfd_error = invalid_operation;  /* write not supported  */
108 }
109
110
111 /* This functions reads an arch header and returns an areltdata pointer, or
112    NULL on error.
113
114    Presumes the file pointer is already in the right place (ie pointing
115    to the ar_hdr in the file).   Moves the file pointer; on success it
116    should be pointing to the front of the file contents; on failure it
117    could have been moved arbitrarily.
118 */
119
120 struct areltdata *
121 rs6000coff_snarf_ar_hdr (abfd)
122      bfd *abfd;
123 {
124         extern int errno;
125
126         struct {
127                 struct ar_hdr hdr;
128                 char namebuf[256];
129         } h;
130         int size;
131         struct areltdata *ared;
132         unsigned int namelen = 0;
133         char *allocptr;
134
135         size = sizeof (h.hdr);
136         if (bfd_read(&h.hdr, 1, size, abfd) != size) {
137                 bfd_error = no_more_archived_files;
138                 return NULL;
139         }
140         size  = atoi(h.hdr.ar_namlen);  /* ar_name[] length     */
141         size += size & 1;
142
143         if (bfd_read(&h.hdr._ar_name.ar_name[2], 1, size, abfd) != size) {
144                 bfd_error = no_more_archived_files;
145                 return NULL;
146         }
147
148         if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) {
149                 bfd_error = malformed_archive;
150                 return NULL;
151         }
152
153         h.hdr._ar_name.ar_name[size] = 0;       /* terminate filename   */
154
155         /*
156          * if the filename is NULL, we're (probably) at the end.
157          */
158         if (size == 0) {
159                 bfd_error = no_more_archived_files;
160                 return NULL;
161         }
162
163         size += sizeof (h.hdr);
164         allocptr = bfd_zalloc(abfd, sizeof (*ared) + size);
165
166         if (allocptr == NULL) {
167                 bfd_error = no_memory;
168                 return NULL;
169         }
170
171         ared = (struct areltdata *) allocptr;
172
173         ared->arch_header = (void *) (allocptr + sizeof (struct areltdata));
174         memcpy ((char *) ared->arch_header, &h.hdr, size);
175         ared->parsed_size = atoi(h.hdr.ar_size);
176         ared->filename    = ((AR_HDR*) ared->arch_header)->_ar_name.ar_name;
177
178         return ared;
179 }
180
181 /* Stolen directly from archive.c, except it calls rs6000coff_snarf_ar_hdr.
182    Why wasn't this part of the transfer vector?  */
183
184 bfd *
185 rs6000coff_get_elt_at_filepos (archive, filepos)
186      bfd *archive;
187      file_ptr filepos;
188 {
189   struct areltdata *new_areldata;
190   bfd *n_nfd;
191
192   n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
193   if (n_nfd) return n_nfd;
194
195   if (0 != bfd_seek (archive, filepos, SEEK_SET)) {
196     bfd_error = system_call_error;
197     return NULL;
198   }
199
200   if ((new_areldata = rs6000coff_snarf_ar_hdr (archive)) == NULL) return NULL;
201   
202   n_nfd = _bfd_create_empty_archive_element_shell (archive);
203   if (n_nfd == NULL) {
204     bfd_release (archive, (PTR)new_areldata);
205     return NULL;
206   }
207   n_nfd->origin = bfd_tell (archive);
208   n_nfd->arelt_data = (PTR) new_areldata;
209   n_nfd->filename = new_areldata->filename;
210
211   if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
212     return n_nfd;
213
214   /* huh? */
215   bfd_release (archive, (PTR)n_nfd);
216   bfd_release (archive, (PTR)new_areldata);
217   return NULL;
218 }
219
220 /*
221  * xcoff_openr_next_archived_file -     xcoff has nxt/prv seek addrs.
222  */
223 static bfd *
224 rs6000coff_openr_next_archived_file(archive, last_file)
225   bfd *archive, *last_file; 
226 {
227         file_ptr filestart;
228
229         if (!last_file)
230                 filestart = bfd_ardata(archive)->first_file_filepos;
231         else
232                 filestart = atol(arch_hdr(last_file)->ar_nxtmem);
233
234         return rs6000coff_get_elt_at_filepos (archive, filestart);
235 }
236
237
238 static bfd_target *
239 rs6000coff_archive_p (abfd)
240      bfd *abfd;
241 {
242         struct fl_hdr hdr;
243         register struct artdata *art;
244
245         if (bfd_read (&hdr, sizeof (hdr), 1, abfd) != sizeof (hdr)) {
246                 bfd_error = wrong_format;
247                 return 0;
248         }
249
250         if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) {
251                 bfd_error = wrong_format;
252                 return 0;
253         }
254
255         /*
256          * bfd_ardata() accesses the bfd->tdata field.
257          */
258         abfd->tdata.aout_ar_data =
259           (void *) bfd_zalloc(abfd, sizeof (*art) + sizeof (hdr));
260         if ((art = bfd_ardata (abfd)) == NULL) {
261                 bfd_error = no_memory;
262                 return 0;
263         }
264
265         art->first_file_filepos = atoi(hdr.fl_fstmoff);
266         *(struct fl_hdr *) (1 + art) = hdr;
267
268         /* Someday...
269          * slurp in the member table, which I think is the armap equivalent.
270         xcoff_slurp_armap(abfd);
271          */
272   
273         return abfd->xvec;
274 }
275
276
277 static int
278 rs6000coff_stat_arch_elt(abfd, buf)
279   bfd *abfd;
280   struct stat *buf;
281 {
282         struct ar_hdr *hdr;
283         char *aloser;
284   
285         if (abfd->arelt_data == NULL) {
286                 bfd_error = invalid_operation;
287                 return -1;
288         }
289     
290         hdr = arch_hdr (abfd);
291
292 #define foo(arelt, stelt, size)  \
293         buf->stelt = strtol (hdr->arelt, &aloser, size); \
294                 if (aloser == hdr->arelt) return -1;
295   
296         foo (ar_date, st_mtime, 10);
297         foo (ar_uid, st_uid, 10);
298         foo (ar_gid, st_gid, 10);
299         foo (ar_mode, st_mode, 8);
300         foo (ar_size, st_size, 10);
301 #undef foo
302
303         return 0;
304 }
305
306 static boolean
307 rs6000coff_write_armap (arch, elength, map, orl_count, stridx)
308   bfd *arch;
309   unsigned int elength;
310   struct orl *map; 
311 {
312         bfd_error = invalid_operation;
313         return false;
314 }
315 #endif  /* ARCHIVES_PLEASE */
316
317 \f
318 #ifdef COREFILES_PLEASE
319 extern bfd_target * rs6000coff_core_p ();
320 extern boolean rs6000coff_get_section_contents ();
321 extern boolean rs6000coff_core_file_matches_executable_p ();
322
323 #undef  coff_core_file_matches_executable_p
324 #define coff_core_file_matches_executable_p  \
325                                      rs6000coff_core_file_matches_executable_p
326
327 #undef  coff_get_section_contents
328 #define coff_get_section_contents       rs6000coff_get_section_contents
329 #endif
330
331 /* The transfer vector that leads the outside world to all of the above. */
332
333 bfd_target rs6000coff_vec =
334 {
335   "aixcoff-rs6000",             /* name */
336   bfd_target_coff_flavour,      
337   true,                         /* data byte order is big */
338   true,                         /* header byte order is big */
339
340   (HAS_RELOC | EXEC_P |         /* object flags */
341    HAS_LINENO | HAS_DEBUG |
342    HAS_SYMS | HAS_LOCALS | WP_TEXT),
343
344   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
345   0,                            /* leading char */
346   '/',                          /* ar_pad_char */
347   15,                           /* ar_max_namelen??? FIXMEmgo */
348   3,                            /* default alignment power */
349
350   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
351      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
352      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
353   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
354      bfd_getb32, bfd_getb_signed_32, bfd_putb32,
355      bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
356
357   {_bfd_dummy_target, coff_object_p,    /* bfd_check_format */
358      coff_archive_p,
359 #ifdef  COREFILES_PLEASE
360      rs6000coff_core_p
361 #else
362      _bfd_dummy_target
363 #endif
364        },
365   {bfd_false, coff_mkobject, coff_mkarchive, /* bfd_set_format */
366      bfd_false},
367   {bfd_false, coff_write_object_contents,       /* bfd_write_contents */
368      _bfd_write_archive_contents, bfd_false},
369
370   JUMP_TABLE(coff),
371   COFF_SWAP_TABLE,
372 };