From bb2deaf25f57e1a6d77f2321e9091f1e4a5e9c1d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 Oct 1995 16:12:59 +0000 Subject: * coff-rs6000.c: Add full support for AIX archives. Rewrite old read-only/host-only support. --- bfd/coff-rs6000.c | 897 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 702 insertions(+), 195 deletions(-) (limited to 'bfd/coff-rs6000.c') diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index 70c6e04..31c51d5 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -1,5 +1,5 @@ /* BFD back-end for IBM RS/6000 "XCOFF" files. - Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. FIXME: Can someone provide a transliteration of this name into ASCII? Using the following chars caused a compiler warning on HIUX (so I replaced them with octal escapes), and isn't useful without an understanding of what @@ -25,12 +25,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* This port currently only handles reading object files, except when - compiled on an RS/6000 host. -- no archive support, no core files. - In all cases, it does not support writing. - - FIXMEmgo comments are left from Metin Ozisik's original port. */ - /* Internalcoff.h and coffcode.h modify themselves based on this flag. */ #define RS6000COFF_C 1 @@ -42,6 +36,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "coff/rs6000.h" #include "libcoff.h" +static boolean xcoff_slurp_armap PARAMS ((bfd *)); +static const bfd_target *xcoff_archive_p PARAMS ((bfd *)); +static PTR xcoff_read_ar_hdr PARAMS ((bfd *)); +static bfd *xcoff_openr_next_archived_file PARAMS ((bfd *, bfd *)); +static int xcoff_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); +static const char *normalize_filename PARAMS ((bfd *)); +static boolean xcoff_write_armap + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); +static boolean xcoff_write_archive_contents PARAMS ((bfd *)); + /* The main body of code is in coffcode.h. */ #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) @@ -460,253 +464,752 @@ rs6000coff_reloc_type_lookup (abfd, code) #define COFF_LONG_FILENAMES #include "coffcode.h" + +/* XCOFF archive support. The original version of this code was by + Damon A. Permezel. It was enhanced to permit cross support, and + writing archive files, by Ian Lance Taylor, Cygnus Support. + + XCOFF uses its own archive format. Everything is hooked together + with file offset links, so it is possible to rapidly update an + archive in place. Of course, we don't do that. An XCOFF archive + has a real file header, not just an ARMAG string. The structure of + the file header and of each archive header appear below. + + An XCOFF archive also has a member table, which is a list of + elements in the archive (you can get that by looking through the + linked list, but you have to read a lot more of the file). The + member table has a normal archive header with an empty name. It is + normally (and perhaps must be) the second to last entry in the + archive. The member table data is almost printable ASCII. It + starts with a 12 character decimal string which is the number of + entries in the table. For each entry it has a 12 character decimal + string which is the offset in the archive of that member. These + entries are followed by a series of null terminated strings which + are the member names for each entry. + + Finally, an XCOFF archive has a global symbol table, which is what + we call the armap. The global symbol table has a normal archive + header with an empty name. It is normally (and perhaps must be) + the last entry in the archive. The contents start with a four byte + binary number which is the number of entries. This is followed by + a that many four byte binary numbers; each is the file offset of an + entry in the archive. These numbers are followed by a series of + null terminated strings, which are symbol names. */ + +/* XCOFF archives use this as a magic string. */ + +#define XCOFFARMAG "\012" +#define SXCOFFARMAG 8 + +/* This terminates an XCOFF archive member name. */ + +#define XCOFFARFMAG "`\012" +#define SXCOFFARFMAG 2 + +/* XCOFF archives start with this (printable) structure. */ + +struct xcoff_ar_file_hdr +{ + /* Magic string. */ + char magic[SXCOFFARMAG]; + + /* Offset of the member table (decimal ASCII string). */ + char memoff[12]; + + /* Offset of the global symbol table (decimal ASCII string). */ + char symoff[12]; + + /* Offset of the first member in the archive (decimal ASCII string). */ + char firstmemoff[12]; + + /* Offset of the last member in the archive (decimal ASCII string). */ + char lastmemoff[12]; + + /* Offset of the first member on the free list (decimal ASCII + string). */ + char freeoff[12]; +}; -#define coff_archive_p bfd_generic_archive_p -#define coff_mkarchive _bfd_generic_mkarchive +#define SIZEOF_AR_FILE_HDR (5 * 12 + SXCOFFARMAG) -#ifdef HOST_AIX +/* Each XCOFF archive member starts with this (printable) structure. */ + +struct xcoff_ar_hdr +{ + /* File size not including the header (decimal ASCII string). */ + char size[12]; + + /* File offset of next archive member (decimal ASCII string). */ + char nextoff[12]; + + /* File offset of previous archive member (decimal ASCII string). */ + char prevoff[12]; + + /* File mtime (decimal ASCII string). */ + char date[12]; + + /* File UID (decimal ASCII string). */ + char uid[12]; + + /* File GID (decimal ASCII string). */ + char gid[12]; + + /* File mode (octal ASCII string). */ + char mode[12]; + + /* Length of file name (decimal ASCII string). */ + char namlen[4]; + + /* This structure is followed by the file name. The length of the + name is given in the namlen field. If the length of the name is + odd, the name is followed by a null byte. The name and optional + null byte are followed by XCOFFARFMAG, which is not included in + namlen. The contents of the archive member follow; the number of + bytes is given in the size field. */ +}; -/* ------------------------------------------------------------------------ */ -/* Support for archive file stuff.. */ -/* Stolen from Damon A. Permezel's `bfd' portation. */ -/* ------------------------------------------------------------------------ */ +#define SIZEOF_AR_HDR (7 * 12 + 4) -#define rs6000coff_slurp_armap bfd_slurp_coff_armap -#define rs6000coff_slurp_extended_name_table _bfd_slurp_extended_name_table -#define rs6000coff_construct_extended_name_table \ - _bfd_archive_coff_construct_extended_name_table -#define rs6000coff_truncate_arname bfd_dont_truncate_arname -#define rs6000coff_update_armap_timestamp bfd_true +/* We store a copy of the xcoff_ar_file_hdr in the tdata field of the + artdata structure. */ +#define xcoff_ardata(abfd) \ + ((struct xcoff_ar_file_hdr *) bfd_ardata (abfd)->tdata) -#undef coff_mkarchive -#define coff_mkarchive rs6000coff_mkarchive +/* We store a copy of the xcoff_ar_hdr in the arelt_data field of an + archive element. */ +#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) +#define arch_xhdr(bfd) \ + ((struct xcoff_ar_hdr *) arch_eltdata (bfd)->arch_header) -#undef coff_archive_p -#define coff_archive_p rs6000coff_archive_p +/* XCOFF archives do not have anything which corresponds to an + extended name table. */ -#include "/usr/include/ar.h" /* doesn't do it. */ +#define xcoff_slurp_extended_name_table bfd_false +#define xcoff_construct_extended_name_table \ + ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_false) +#define xcoff_truncate_arname bfd_dont_truncate_arname +/* XCOFF archives do not have a timestamp. */ -#define arch_hdr(bfd) \ - ((struct ar_hdr *) \ - (((struct areltdata *)((bfd)->arelt_data))->arch_header)) +#define xcoff_update_armap_timestamp bfd_true +/* Read in the armap of an XCOFF archive. */ static boolean -rs6000coff_mkarchive (abfd) +xcoff_slurp_armap (abfd) bfd *abfd; { - bfd_set_error (bfd_error_invalid_operation); /* write not supported */ - return false; -} + file_ptr off; + struct xcoff_ar_hdr hdr; + size_t namlen; + bfd_size_type sz; + bfd_byte *contents, *cend; + unsigned int c, i; + carsym *arsym; + bfd_byte *p; + + if (xcoff_ardata (abfd) == NULL) + { + bfd_has_map (abfd) = false; + return true; + } + + off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10); + if (off == 0) + { + bfd_has_map (abfd) = false; + return true; + } + + if (bfd_seek (abfd, off, SEEK_SET) != 0) + return false; + + /* The symbol table starts with a normal archive header. */ + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) + return false; + + /* Skip the name (normally empty). */ + namlen = strtol (hdr.namlen, (char **) NULL, 10); + if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0) + return false; + + /* Read in the entire symbol table. */ + sz = strtol (hdr.size, (char **) NULL, 10); + contents = (bfd_byte *) bfd_alloc (abfd, sz); + if (contents == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (bfd_read ((PTR) contents, 1, sz, abfd) != sz) + return false; + + /* The symbol table starts with a four byte count. */ + c = bfd_h_get_32 (abfd, contents); + + if (c * 4 >= sz) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_ardata (abfd)->symdefs = ((carsym *) + bfd_alloc (abfd, c * sizeof (carsym))); + if (bfd_ardata (abfd)->symdefs == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + /* After the count comes a list of four byte file offsets. */ + for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 4; + i < c; + ++i, ++arsym, p += 4) + arsym->file_offset = bfd_h_get_32 (abfd, p); + + /* After the file offsets come null terminated symbol names. */ + cend = contents + sz; + for (i = 0, arsym = bfd_ardata (abfd)->symdefs; + i < c; + ++i, ++arsym, p += strlen ((char *) p) + 1) + { + if (p >= cend) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + arsym->name = (char *) p; + } + bfd_ardata (abfd)->symdef_count = c; + bfd_has_map (abfd) = true; -/* This functions reads an arch header and returns an areltdata pointer, or - NULL on error. + return true; +} - Presumes the file pointer is already in the right place (ie pointing - to the ar_hdr in the file). Moves the file pointer; on success it - should be pointing to the front of the file contents; on failure it - could have been moved arbitrarily. -*/ +/* See if this is an XCOFF archive. */ -struct areltdata * -rs6000coff_snarf_ar_hdr (abfd) +static const bfd_target * +xcoff_archive_p (abfd) bfd *abfd; { - struct { - struct ar_hdr hdr; - char namebuf[256]; - } h; - int size; - struct areltdata *ared; - char *allocptr; - - size = sizeof (h.hdr); - if (bfd_read(&h.hdr, 1, size, abfd) != size) { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; - } - size = atoi(h.hdr.ar_namlen); /* ar_name[] length */ - size += size & 1; + struct xcoff_ar_file_hdr hdr; - if (bfd_read(&h.hdr._ar_name.ar_name[2], 1, size, abfd) != size) { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; - } + if (bfd_read ((PTR) &hdr, SIZEOF_AR_FILE_HDR, 1, abfd) + != SIZEOF_AR_FILE_HDR) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } - if (strncmp(h.hdr._ar_name.ar_fmag + size, AIAFMAG, 2)) { - bfd_set_error (bfd_error_malformed_archive); - return NULL; - } + if (strncmp (hdr.magic, XCOFFARMAG, SXCOFFARMAG) != 0) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } - h.hdr._ar_name.ar_name[size] = 0; /* terminate filename */ + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of + assignment. */ + abfd->tdata.aout_ar_data = + (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata)); - /* - * if the filename is NULL, we're (probably) at the end. - */ - if (size == 0) { - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; - } + if (bfd_ardata (abfd) == (struct artdata *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } - size += sizeof (h.hdr); - allocptr = bfd_zalloc(abfd, sizeof (*ared) + size); + bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff, + (char **) NULL, 10); + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; - if (allocptr == NULL) { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR); + if (bfd_ardata (abfd)->tdata == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } - ared = (struct areltdata *) allocptr; + memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR); - ared->arch_header = (void *) (allocptr + sizeof (struct areltdata)); - memcpy ((char *) ared->arch_header, &h.hdr, size); - ared->parsed_size = atoi(h.hdr.ar_size); - ared->filename = ((AR_HDR*) ared->arch_header)->_ar_name.ar_name; + if (! xcoff_slurp_armap (abfd)) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = (struct artdata *) NULL; + return NULL; + } - return ared; + return abfd->xvec; } -/* Stolen directly from archive.c, except it calls rs6000coff_snarf_ar_hdr. - Why wasn't this part of the transfer vector? */ +/* Read the archive header in an XCOFF archive. */ -bfd * -rs6000coff_get_elt_at_filepos (archive, filepos) - bfd *archive; - file_ptr filepos; +static PTR +xcoff_read_ar_hdr (abfd) + bfd *abfd; { - struct areltdata *new_areldata; - bfd *n_nfd; - - n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); - if (n_nfd) return n_nfd; + struct xcoff_ar_hdr hdr; + size_t namlen; + struct xcoff_ar_hdr *hdrp; + struct areltdata *ret; - if (0 != bfd_seek (archive, filepos, SEEK_SET)) + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) return NULL; - if ((new_areldata = rs6000coff_snarf_ar_hdr (archive)) == NULL) return NULL; - - n_nfd = _bfd_create_empty_archive_element_shell (archive); - if (n_nfd == NULL) { - bfd_release (archive, (PTR)new_areldata); + namlen = strtol (hdr.namlen, (char **) NULL, 10); + hdrp = bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1); + if (hdrp == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + memcpy (hdrp, &hdr, SIZEOF_AR_HDR); + if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen) return NULL; - } - n_nfd->origin = bfd_tell (archive); - n_nfd->arelt_data = (PTR) new_areldata; - n_nfd->filename = new_areldata->filename; + ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0'; - if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) - return n_nfd; + ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata)); + if (ret == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + ret->arch_header = (char *) hdrp; + ret->parsed_size = strtol (hdr.size, (char **) NULL, 10); + ret->filename = (char *) hdrp + SIZEOF_AR_HDR; + + /* Skip over the XCOFFARFMAG at the end of the file name. */ + if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0) + return NULL; - /* huh? */ - bfd_release (archive, (PTR)n_nfd); - bfd_release (archive, (PTR)new_areldata); - return NULL; + return (PTR) ret; } -/* - * xcoff_openr_next_archived_file - xcoff has nxt/prv seek addrs. - */ +/* Open the next element in an XCOFF archive. */ + static bfd * -rs6000coff_openr_next_archived_file(archive, last_file) - bfd *archive, *last_file; +xcoff_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; { - file_ptr filestart; + file_ptr filestart; + + if (xcoff_ardata (archive) == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + if (last_file == NULL) + filestart = bfd_ardata (archive)->first_file_filepos; + else + filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL, 10); - if (!last_file) - filestart = bfd_ardata(archive)->first_file_filepos; - else - filestart = atol(arch_hdr(last_file)->ar_nxtmem); + if (filestart == 0 + || filestart == strtol (xcoff_ardata (archive)->memoff, + (char **) NULL, 10) + || filestart == strtol (xcoff_ardata (archive)->symoff, + (char **) NULL, 10)) + { + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } - return rs6000coff_get_elt_at_filepos (archive, filestart); + return _bfd_get_elt_at_filepos (archive, filestart); } +/* Stat an element in an XCOFF archive. */ -static const bfd_target * -rs6000coff_archive_p (abfd) +int +xcoff_generic_stat_arch_elt (abfd, s) bfd *abfd; + struct stat *s; { - struct fl_hdr hdr; - register struct artdata *art; + struct xcoff_ar_hdr *hdrp; - if (bfd_read (&hdr, sizeof (hdr), 1, abfd) != sizeof (hdr)) { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return 0; - } + if (abfd->arelt_data == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } - if (strncmp(hdr.fl_magic, AIAMAG, SAIAMAG)) { - bfd_set_error (bfd_error_wrong_format); - return 0; - } + hdrp = arch_xhdr (abfd); - /* - * bfd_ardata() accesses the bfd->tdata field. - */ - abfd->tdata.aout_ar_data = - (void *) bfd_zalloc(abfd, sizeof (*art) + sizeof (hdr)); - if ((art = bfd_ardata (abfd)) == NULL) { - bfd_set_error (bfd_error_no_memory); - return 0; - } + s->st_mtime = strtol (hdrp->date, (char **) NULL, 10); + s->st_uid = strtol (hdrp->uid, (char **) NULL, 10); + s->st_gid = strtol (hdrp->gid, (char **) NULL, 10); + s->st_mode = strtol (hdrp->mode, (char **) NULL, 8); + s->st_size = arch_eltdata (abfd)->parsed_size; - art->first_file_filepos = atoi(hdr.fl_fstmoff); - *(struct fl_hdr *) (1 + art) = hdr; + return 0; +} - /* Someday... - * slurp in the member table, which I think is the armap equivalent. - xcoff_slurp_armap(abfd); - */ - - return abfd->xvec; +/* Normalize a file name for inclusion in an archive. */ + +static const char * +normalize_filename (abfd) + bfd *abfd; +{ + const char *file; + const char *filename; + + file = bfd_get_filename (abfd); + filename = strrchr (file, '/'); + if (filename != NULL) + filename++; + else + filename = file; + return filename; } +/* Write out an XCOFF armap. */ -static int -rs6000coff_generic_stat_arch_elt(abfd, buf) - bfd *abfd; - struct stat *buf; +/*ARGSUSED*/ +static boolean +xcoff_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; { - struct ar_hdr *hdr; - char *aloser; + struct xcoff_ar_hdr hdr; + char *p; + char buf[4]; + bfd *sub; + file_ptr fileoff; + unsigned int i; + + memset (&hdr, 0, sizeof hdr); + sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx)); + sprintf (hdr.nextoff, "%d", 0); + memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, 12); + sprintf (hdr.date, "%d", 0); + sprintf (hdr.uid, "%d", 0); + sprintf (hdr.gid, "%d", 0); + sprintf (hdr.mode, "%d", 0); + sprintf (hdr.namlen, "%d", 0); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR + || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG) + return false; - if (abfd->arelt_data == NULL) { - bfd_set_error (bfd_error_invalid_operation); - return -1; + bfd_h_put_32 (abfd, orl_count, buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + + sub = abfd->archive_head; + fileoff = SIZEOF_AR_FILE_HDR; + i = 0; + while (sub != NULL && i < orl_count) + { + size_t namlen; + + while (((bfd *) (map[i]).pos) == sub) + { + bfd_h_put_32 (abfd, fileoff, buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + ++i; } - - hdr = arch_hdr (abfd); + namlen = strlen (normalize_filename (sub)); + namlen = (namlen + 1) &~ 1; + fileoff += (SIZEOF_AR_HDR + + namlen + + SXCOFFARFMAG + + arelt_size (sub)); + fileoff = (fileoff + 1) &~ 1; + sub = sub->next; + } -#define foo(arelt, stelt, size) \ - buf->stelt = strtol (hdr->arelt, &aloser, size); \ - if (aloser == hdr->arelt) return -1; - - foo (ar_date, st_mtime, 10); - foo (ar_uid, st_uid, 10); - foo (ar_gid, st_gid, 10); - foo (ar_mode, st_mode, 8); - foo (ar_size, st_size, 10); -#undef foo - - return 0; + for (i = 0; i < orl_count; i++) + { + const char *name; + size_t namlen; + + name = *map[i].name; + namlen = strlen (name); + if (bfd_write (name, 1, namlen + 1, abfd) != namlen + 1) + return false; + } + + if ((stridx & 1) != 0) + { + char b; + + b = '\0'; + if (bfd_write (&b, 1, 1, abfd) != 1) + return false; + } + + return true; } +/* Write out an XCOFF archive. We always write an entire archive, + rather than fussing with the freelist and so forth. */ + static boolean -rs6000coff_write_armap (arch, elength, map, orl_count, stridx) - bfd *arch; - unsigned int elength; - struct orl *map; - unsigned int orl_count; - int stridx; +xcoff_write_archive_contents (abfd) + bfd *abfd; { - bfd_set_error (bfd_error_invalid_operation); + struct xcoff_ar_file_hdr fhdr; + size_t count; + size_t total_namlen; + file_ptr *offsets; + boolean makemap; + boolean hasobjects; + file_ptr prevoff, nextoff; + bfd *sub; + unsigned int i; + struct xcoff_ar_hdr ahdr; + bfd_size_type size; + char *p; + char decbuf[13]; + + memset (&fhdr, 0, sizeof fhdr); + strncpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG); + sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR); + sprintf (fhdr.freeoff, "%d", 0); + + count = 0; + total_namlen = 0; + for (sub = abfd->archive_head; sub != NULL; sub = sub->next) + { + ++count; + total_namlen += strlen (normalize_filename (sub)) + 1; + } + offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr)); + if (offsets == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR, SEEK_SET) != 0) + return false; + + makemap = bfd_has_map (abfd); + hasobjects = false; + prevoff = 0; + nextoff = SIZEOF_AR_FILE_HDR; + for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++) + { + const char *name; + size_t namlen; + struct xcoff_ar_hdr *ahdrp; + bfd_size_type remaining; + + if (makemap && ! hasobjects) + { + if (bfd_check_format (sub, bfd_object)) + hasobjects = true; + } + + name = normalize_filename (sub); + namlen = strlen (name); + + if (sub->arelt_data != NULL) + ahdrp = arch_xhdr (sub); + else + ahdrp = NULL; + + if (ahdrp == NULL) + { + struct stat s; + + memset (&ahdr, 0, sizeof ahdr); + ahdrp = &ahdr; + if (stat (bfd_get_filename (sub), &s) != 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + sprintf (ahdrp->size, "%ld", (long) s.st_size); + sprintf (ahdrp->date, "%ld", (long) s.st_mtime); + sprintf (ahdrp->uid, "%ld", (long) s.st_uid); + sprintf (ahdrp->gid, "%ld", (long) s.st_gid); + sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode); + + if (sub->arelt_data == NULL) + { + sub->arelt_data = ((struct areltdata *) + bfd_alloc (sub, sizeof (struct areltdata))); + if (sub->arelt_data == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + } + + arch_eltdata (sub)->parsed_size = s.st_size; + } + + sprintf (ahdrp->prevoff, "%ld", (long) prevoff); + sprintf (ahdrp->namlen, "%ld", (long) namlen); + + /* If the length of the name is odd, we write out the null byte + after the name as well. */ + namlen = (namlen + 1) &~ 1; + + remaining = arelt_size (sub); + size = (SIZEOF_AR_HDR + + namlen + + SXCOFFARFMAG + + remaining); + + BFD_ASSERT (nextoff == bfd_tell (abfd)); + + offsets[i] = nextoff; + + prevoff = nextoff; + nextoff += size + (size & 1); + + sprintf (ahdrp->nextoff, "%ld", (long) nextoff); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) ahdrp, 1, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR + || bfd_write ((PTR) name, 1, namlen, abfd) != namlen + || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) + != SXCOFFARFMAG)) return false; -} -#endif /* HOST_AIX */ + if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0) + return false; + while (remaining != 0) + { + bfd_size_type amt; + bfd_byte buffer[DEFAULT_BUFFERSIZE]; + + amt = sizeof buffer; + if (amt > remaining) + amt = remaining; + if (bfd_read (buffer, 1, amt, sub) != amt + || bfd_write (buffer, 1, amt, abfd) != amt) + return false; + remaining -= amt; + } + + if ((size & 1) != 0) + { + bfd_byte b; + + b = '\0'; + if (bfd_write (&b, 1, 1, abfd) != 1) + return false; + } + } + + sprintf (fhdr.lastmemoff, "%ld", (long) prevoff); + + /* Write out the member table. */ + + BFD_ASSERT (nextoff == bfd_tell (abfd)); + sprintf (fhdr.memoff, "%ld", (long) nextoff); + + memset (&ahdr, 0, sizeof ahdr); + sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen)); + sprintf (ahdr.prevoff, "%ld", (long) prevoff); + sprintf (ahdr.date, "%d", 0); + sprintf (ahdr.uid, "%d", 0); + sprintf (ahdr.gid, "%d", 0); + sprintf (ahdr.mode, "%d", 0); + sprintf (ahdr.namlen, "%d", 0); + + size = (SIZEOF_AR_HDR + + 12 + + count * 12 + + total_namlen + + SXCOFFARFMAG); + + prevoff = nextoff; + nextoff += size + (size & 1); + + if (makemap && hasobjects) + sprintf (ahdr.nextoff, "%ld", (long) nextoff); + else + sprintf (ahdr.nextoff, "%d", 0); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) &ahdr, 1, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR + || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) + != SXCOFFARFMAG)) + return false; + + sprintf (decbuf, "%-12ld", (long) count); + if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12) + return false; + for (i = 0; i < count; i++) + { + sprintf (decbuf, "%-12ld", (long) offsets[i]); + if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12) + return false; + } + for (sub = abfd->archive_head; sub != NULL; sub = sub->next) + { + const char *name; + size_t namlen; + + name = normalize_filename (sub); + namlen = strlen (name); + if (bfd_write ((PTR) name, 1, namlen + 1, abfd) != namlen + 1) + return false; + } + if ((size & 1) != 0) + { + bfd_byte b; + + b = '\0'; + if (bfd_write ((PTR) &b, 1, 1, abfd) != 1) + return false; + } + + /* Write out the armap, if appropriate. */ + + if (! makemap || ! hasobjects) + sprintf (fhdr.symoff, "%d", 0); + else + { + BFD_ASSERT (nextoff == bfd_tell (abfd)); + sprintf (fhdr.symoff, "%ld", (long) nextoff); + bfd_ardata (abfd)->tdata = (PTR) &fhdr; + if (! _bfd_compute_and_write_armap (abfd, 0)) + return false; + } + + /* Write out the archive file header. */ + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) &fhdr, SIZEOF_AR_FILE_HDR, 1, abfd) != + SIZEOF_AR_FILE_HDR)) + return false; + + return true; +} #define CORE_FILE_P _bfd_dummy_target @@ -726,6 +1229,14 @@ extern boolean rs6000coff_core_file_matches_executable_p (); #define coff_core_file_matches_executable_p \ rs6000coff_core_file_matches_executable_p +extern char *rs6000coff_core_file_failing_command PARAMS ((bfd *abfd)); +#undef coff_core_file_failing_command +#define coff_core_file_failing_command rs6000coff_core_file_failing_command + +extern int rs6000coff_core_file_failing_signal PARAMS ((bfd *abfd)); +#undef coff_core_file_failing_signal +#define coff_core_file_failing_signal rs6000coff_core_file_failing_signal + #undef coff_get_section_contents #define coff_get_section_contents rs6000coff_get_section_contents #endif /* AIX_CORE */ @@ -777,20 +1288,16 @@ const bfd_target rs6000coff_vec = bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - coff_archive_p, CORE_FILE_P}, - {bfd_false, coff_mkobject, coff_mkarchive, /* bfd_set_format */ - bfd_false}, + xcoff_archive_p, CORE_FILE_P}, + {bfd_false, coff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, + xcoff_write_archive_contents, bfd_false}, BFD_JUMP_TABLE_GENERIC (coff), BFD_JUMP_TABLE_COPY (coff), BFD_JUMP_TABLE_CORE (coff), -#ifdef HOST_AIX - BFD_JUMP_TABLE_ARCHIVE (rs6000coff), -#else - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), -#endif + BFD_JUMP_TABLE_ARCHIVE (xcoff), BFD_JUMP_TABLE_SYMBOLS (coff), BFD_JUMP_TABLE_RELOCS (coff), BFD_JUMP_TABLE_WRITE (coff), -- cgit v1.1