/* BFD back-end for IBM RS/6000 "XCOFF" files.
- Copyright (C) 1990-2022 Free Software Foundation, Inc.
+ Copyright (C) 1990-2023 Free Software Foundation, Inc.
Written by Metin G. Ozisik, Mimi Phuong-Thao Vo, and John Gilmore.
Archive support from Damon A. Permezel.
Contributed by IBM Corporation and Cygnus Support.
case C_HIDEXT:
if (indx + 1 == numaux)
{
- in->x_csect.x_scnlen.l = H_GET_32 (abfd, ext->x_csect.x_scnlen);
+ in->x_csect.x_scnlen.u64 = H_GET_32 (abfd, ext->x_csect.x_scnlen);
in->x_csect.x_parmhash = H_GET_32 (abfd, ext->x_csect.x_parmhash);
in->x_csect.x_snhash = H_GET_16 (abfd, ext->x_csect.x_snhash);
/* We don't have to hack bitfields in x_smtyp because it's
= H_GET_32 (abfd, ext->x_fcn.x_fsize);
in->x_sym.x_fcnary.x_fcn.x_lnnoptr
= H_GET_32 (abfd, ext->x_fcn.x_lnnoptr);
- in->x_sym.x_fcnary.x_fcn.x_endndx.l
+ in->x_sym.x_fcnary.x_fcn.x_endndx.u32
= H_GET_32 (abfd, ext->x_fcn.x_endndx);
}
break;
case C_HIDEXT:
if (indx + 1 == numaux)
{
- H_PUT_32 (abfd, in->x_csect.x_scnlen.l, ext->x_csect.x_scnlen);
+ H_PUT_32 (abfd, in->x_csect.x_scnlen.u64, ext->x_csect.x_scnlen);
H_PUT_32 (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash);
H_PUT_16 (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash);
/* We don't have to hack bitfields in x_smtyp because it's
H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, ext->x_fcn.x_fsize);
H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr,
ext->x_fcn.x_lnnoptr);
- H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l,
+ H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.u32,
ext->x_fcn.x_endndx);
}
break;
carsym *arsym;
bfd_byte *p;
- if (xcoff_ardata (abfd) == NULL)
+ if (x_artdata (abfd) == NULL)
{
abfd->has_armap = false;
return true;
/* This is for the old format. */
struct xcoff_ar_hdr hdr;
- GET_VALUE_IN_FIELD (off, xcoff_ardata (abfd)->symoff, 10);
+ GET_VALUE_IN_FIELD (off, x_artdata (abfd)->u.hdr.symoff, 10);
if (off == 0)
{
abfd->has_armap = false;
/* This is for the new format. */
struct xcoff_ar_hdr_big hdr;
- GET_VALUE_IN_FIELD (off, xcoff_ardata_big (abfd)->symoff, 10);
+ GET_VALUE_IN_FIELD (off, x_artdata (abfd)->u.bhdr.symoff, 10);
if (off == 0)
{
abfd->has_armap = false;
if (bfd_ardata (abfd) == (struct artdata *) NULL)
goto error_ret_restore;
- /* Cleared by bfd_zalloc above.
- bfd_ardata (abfd)->cache = NULL;
- bfd_ardata (abfd)->archive_head = NULL;
- bfd_ardata (abfd)->symdefs = NULL;
- bfd_ardata (abfd)->extended_names = NULL;
- bfd_ardata (abfd)->extended_names_size = 0; */
-
/* Now handle the two formats. */
if (magic[1] != 'b')
{
GET_VALUE_IN_FIELD (bfd_ardata (abfd)->first_file_filepos,
hdr.firstmemoff, 10);
- amt = SIZEOF_AR_FILE_HDR;
+ amt = sizeof (struct xcoff_artdata);
bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt);
if (bfd_ardata (abfd)->tdata == NULL)
goto error_ret;
- memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
+ memcpy (&x_artdata (abfd)->u.hdr, &hdr, SIZEOF_AR_FILE_HDR);
}
else
{
(const char **) 0,
10);
- amt = SIZEOF_AR_FILE_HDR_BIG;
+ amt = sizeof (struct xcoff_artdata);
bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt);
if (bfd_ardata (abfd)->tdata == NULL)
goto error_ret;
- memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG);
+ memcpy (&x_artdata (abfd)->u.bhdr, &hdr, SIZEOF_AR_FILE_HDR_BIG);
}
if (! _bfd_xcoff_slurp_armap (abfd))
return _bfd_no_cleanup;
}
+/* Track file ranges occupied by elements. Add [START,END) to the
+ list of ranges and return TRUE if there is no overlap between the
+ new and any other element or the archive file header. Note that
+ this would seem to preclude calling _bfd_get_elt_at_filepos twice
+ for the same element, but we won't get to _bfd_xcoff_read_ar_hdr if
+ an element is read more than once. See _bfd_get_elt_at_filepos use
+ of _bfd_look_for_bfd_in_cache. Also, the xcoff archive code
+ doesn't call _bfd_read_ar_hdr when reading the armap, nor does it
+ need to use extended name tables. So those other routines in
+ archive.c that call _bfd_read_ar_hdr are unused. */
+
+static bool
+add_range (bfd *abfd, ufile_ptr start, ufile_ptr end)
+{
+ if (end <= start)
+ {
+ err:
+ bfd_set_error (bfd_error_malformed_archive);
+ return false;
+ }
+
+ /* This list is kept sorted by address. Find the highest address
+ range on the list that ends before the new range starts. Exit
+ the loop with that range in LO, and the mext higher range in HI. */
+ struct ar_ranges *hi = &x_artdata (abfd)->ranges;
+ struct ar_ranges *lo = NULL;
+ while (hi && hi->end <= start)
+ {
+ lo = hi;
+ hi = hi->next;
+ }
+
+ if (lo == NULL)
+ /* Start overlaps the file header or elements adjacent to it. */
+ goto err;
+
+ if (hi && hi->start < end)
+ /* Overlap with another element. */
+ goto err;
+
+ unsigned min_elt = x_artdata (abfd)->min_elt;
+ if (start - lo->end < min_elt)
+ {
+ /* Merge into an existing range. */
+ lo->end = end;
+ if (hi && hi->start - end < min_elt)
+ {
+ /* In fact, we can merge two ranges. */
+ lo->end = hi->end;
+ lo->next = hi->next;
+ /* The list uses bfd_alloc so don't free HI. */
+ }
+ return true;
+ }
+
+ if (hi && hi->start - end < min_elt)
+ {
+ /* Merge into an existing range. */
+ hi->start = start;
+ return true;
+ }
+
+ struct ar_ranges *newr = bfd_alloc (abfd, sizeof (*newr));
+ if (newr == NULL)
+ return false;
+ newr->start = start;
+ newr->end = end;
+ newr->next = hi;
+ lo->next = newr;
+ return true;
+}
+
/* Read the archive header in an XCOFF archive. */
void *
bfd_size_type namlen;
struct areltdata *ret;
bfd_size_type amt;
+ ufile_ptr start = abfd->where;
if (! xcoff_big_format_p (abfd))
{
ret->extra_size = namlen + (namlen & 1) + SXCOFFARFMAG;
/* Skip over the XCOFFARFMAG at the end of the file name. */
- if (bfd_seek (abfd, (file_ptr) ((namlen & 1) + SXCOFFARFMAG), SEEK_CUR) != 0)
- return NULL;
+ if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0
+ || !add_range (abfd, start, abfd->where + ret->parsed_size))
+ {
+ free (ret);
+ return NULL;
+ }
return ret;
}
_bfd_xcoff_openr_next_archived_file (bfd *archive, bfd *last_file)
{
file_ptr filestart;
- file_ptr laststart, lastend;
- if (xcoff_ardata (archive) == NULL)
+ if (x_artdata (archive) == NULL)
{
bfd_set_error (bfd_error_invalid_operation);
return NULL;
if (last_file == NULL)
{
filestart = bfd_ardata (archive)->first_file_filepos;
- laststart = 0;
- lastend = SIZEOF_AR_FILE_HDR;
+ if (x_artdata (archive)->min_elt == 0)
+ {
+ x_artdata (archive)->ranges.end = SIZEOF_AR_FILE_HDR;
+ x_artdata (archive)->min_elt = SIZEOF_AR_HDR + SXCOFFARFMAG + 2;
+ }
}
else
- {
- struct areltdata *arel = arch_eltdata (last_file);
-
- GET_VALUE_IN_FIELD (filestart, arch_xhdr (last_file)->nextoff, 10);
- laststart = last_file->proxy_origin;
- lastend = laststart + arel->parsed_size;
- laststart -= SIZEOF_AR_HDR + arel->extra_size;
- }
-
- /* Sanity check that we aren't pointing into the previous element. */
- if (filestart != 0 && filestart >= laststart && filestart < lastend)
- {
- bfd_set_error (bfd_error_malformed_archive);
- return NULL;
- }
+ GET_VALUE_IN_FIELD (filestart, arch_xhdr (last_file)->nextoff, 10);
if (filestart == 0
- || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata (archive)->memoff, 10)
- || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata (archive)->symoff, 10))
+ || EQ_VALUE_IN_FIELD (filestart,
+ x_artdata (archive)->u.hdr.memoff, 10)
+ || EQ_VALUE_IN_FIELD (filestart,
+ x_artdata (archive)->u.hdr.symoff, 10))
{
bfd_set_error (bfd_error_no_more_archived_files);
return NULL;
if (last_file == NULL)
{
filestart = bfd_ardata (archive)->first_file_filepos;
- laststart = 0;
- lastend = SIZEOF_AR_FILE_HDR_BIG;
+ if (x_artdata (archive)->min_elt == 0)
+ {
+ x_artdata (archive)->ranges.end = SIZEOF_AR_FILE_HDR_BIG;
+ x_artdata (archive)->min_elt = SIZEOF_AR_HDR_BIG + SXCOFFARFMAG + 2;
+ }
}
else
- {
- struct areltdata *arel = arch_eltdata (last_file);
-
- GET_VALUE_IN_FIELD (filestart, arch_xhdr_big (last_file)->nextoff, 10);
- laststart = last_file->proxy_origin;
- lastend = laststart + arel->parsed_size;
- laststart -= SIZEOF_AR_HDR_BIG + arel->extra_size;
- }
-
- /* Sanity check that we aren't pointing into the previous element. */
- if (filestart != 0 && filestart >= laststart && filestart < lastend)
- {
- bfd_set_error (bfd_error_malformed_archive);
- return NULL;
- }
+ GET_VALUE_IN_FIELD (filestart, arch_xhdr_big (last_file)->nextoff, 10);
if (filestart == 0
- || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata_big (archive)->memoff, 10)
- || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata_big (archive)->symoff, 10))
+ || EQ_VALUE_IN_FIELD (filestart,
+ x_artdata (archive)->u.bhdr.memoff, 10)
+ || EQ_VALUE_IN_FIELD (filestart,
+ x_artdata (archive)->u.bhdr.symoff, 10))
{
bfd_set_error (bfd_error_no_more_archived_files);
return NULL;
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, XCOFFARMAG_ELEMENT_SIZE);
+ memcpy (hdr.prevoff, x_artdata (abfd)->u.hdr.memoff,
+ XCOFFARMAG_ELEMENT_SIZE);
sprintf (hdr.date, "%d", 0);
sprintf (hdr.uid, "%d", 0);
sprintf (hdr.gid, "%d", 0);
/* Explicit cast to int for compiler. */
BFD_ASSERT ((int)(str_64 + str_32) == stridx);
- fhdr = xcoff_ardata_big (abfd);
+ fhdr = &x_artdata (abfd)->u.bhdr;
/* xcoff_write_archive_contents_big passes nextoff in symoff. */
READ20 (fhdr->memoff, prevoff);
xcoff_write_archive_contents_old (bfd *abfd)
{
struct archive_iterator iterator;
- struct xcoff_ar_file_hdr fhdr;
+ struct xcoff_artdata xtdata;
+ struct xcoff_ar_file_hdr *fhdr = &xtdata.u.hdr;
bfd_size_type count;
bfd_size_type total_namlen;
file_ptr *offsets;
char *p;
char decbuf[XCOFFARMAG_ELEMENT_SIZE + 1];
- memset (&fhdr, 0, sizeof fhdr);
- (void) memcpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG);
- sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR);
- sprintf (fhdr.freeoff, "%d", 0);
+ memset (&xtdata, 0, sizeof (xtdata));
+ memcpy (fhdr->magic, XCOFFARMAG, SXCOFFARMAG);
+ sprintf (fhdr->firstmemoff, "%zu", SIZEOF_AR_FILE_HDR);
+ sprintf (fhdr->freeoff, "%d", 0);
count = 0;
total_namlen = 0;
prevoff = iterator.current.offset;
}
- sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
+ sprintf (fhdr->lastmemoff, "%ld", (long) prevoff);
/* Write out the member table. */
nextoff = iterator.next.offset;
BFD_ASSERT (nextoff == bfd_tell (abfd));
- sprintf (fhdr.memoff, "%ld", (long) nextoff);
+ sprintf (fhdr->memoff, "%ld", (long) nextoff);
memset (&ahdr, 0, sizeof ahdr);
sprintf (ahdr.size, "%ld", (long) (XCOFFARMAG_ELEMENT_SIZE
/* Write out the armap, if appropriate. */
if (! makemap || ! hasobjects)
- sprintf (fhdr.symoff, "%d", 0);
+ sprintf (fhdr->symoff, "%d", 0);
else
{
BFD_ASSERT (nextoff == bfd_tell (abfd));
- sprintf (fhdr.symoff, "%ld", (long) nextoff);
- bfd_ardata (abfd)->tdata = &fhdr;
- if (! _bfd_compute_and_write_armap (abfd, 0))
+ sprintf (fhdr->symoff, "%ld", (long) nextoff);
+ bfd_ardata (abfd)->tdata = &xtdata;
+ bool ret = _bfd_compute_and_write_armap (abfd, 0);
+ bfd_ardata (abfd)->tdata = NULL;
+ if (!ret)
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++)
+ 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_bwrite (&fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR, abfd)
- != SIZEOF_AR_FILE_HDR))
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0
+ || (bfd_bwrite (fhdr, SIZEOF_AR_FILE_HDR, abfd) != SIZEOF_AR_FILE_HDR))
return false;
return true;
static bool
xcoff_write_archive_contents_big (bfd *abfd)
{
- struct xcoff_ar_file_hdr_big fhdr;
+ struct xcoff_artdata xtdata;
+ struct xcoff_ar_file_hdr_big *fhdr = &xtdata.u.bhdr;
bfd_size_type count;
bfd_size_type total_namlen;
file_ptr *offsets;
bfd_vma member_table_size;
struct archive_iterator iterator;
- memset (&fhdr, 0, SIZEOF_AR_FILE_HDR_BIG);
- memcpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
+ memset (&xtdata, 0, sizeof (xtdata));
+ memcpy (fhdr->magic, XCOFFARMAGBIG, SXCOFFARMAG);
if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0)
return false;
if (count)
{
- PRINT20 (fhdr.firstmemoff, offsets[0]);
- PRINT20 (fhdr.lastmemoff, prevoff);
+ PRINT20 (fhdr->firstmemoff, offsets[0]);
+ PRINT20 (fhdr->lastmemoff, prevoff);
}
/* Write out the member table.
free (member_table);
- PRINT20 (fhdr.memoff, nextoff);
+ PRINT20 (fhdr->memoff, nextoff);
prevoff = nextoff;
nextoff += member_table_size;
/* Write out the armap, if appropriate. */
if (! makemap || ! hasobjects)
- PRINT20 (fhdr.symoff, 0);
+ PRINT20 (fhdr->symoff, 0);
else
{
BFD_ASSERT (nextoff == bfd_tell (abfd));
- /* Save nextoff in fhdr.symoff so the armap routine can use it. */
- PRINT20 (fhdr.symoff, nextoff);
+ /* Save nextoff in fhdr->symoff so the armap routine can use it. */
+ PRINT20 (fhdr->symoff, nextoff);
- bfd_ardata (abfd)->tdata = &fhdr;
- if (! _bfd_compute_and_write_armap (abfd, 0))
+ bfd_ardata (abfd)->tdata = &xtdata;
+ bool ret = _bfd_compute_and_write_armap (abfd, 0);
+ bfd_ardata (abfd)->tdata = NULL;
+ if (!ret)
return false;
}
/* Write out the archive file header. */
- if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
- || (bfd_bwrite (&fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR_BIG,
- abfd) != SIZEOF_AR_FILE_HDR_BIG))
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0
+ || bfd_bwrite (fhdr,
+ SIZEOF_AR_FILE_HDR_BIG, abfd) != SIZEOF_AR_FILE_HDR_BIG)
return false;
return true;
syment.n_scnum = 1;
syment.n_sclass = C_HIDEXT;
syment.n_numaux = 1;
- auxent.x_csect.x_scnlen.l = data_buffer_size;
+ auxent.x_csect.x_scnlen.u64 = data_buffer_size;
auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD;
auxent.x_csect.x_smclas = XMC_RW;
bfd_coff_swap_sym_out (abfd, &syment,
};
/* For generic entry points. */
-#define _bfd_xcoff_close_and_cleanup _bfd_archive_close_and_cleanup
+#define _bfd_xcoff_close_and_cleanup _bfd_coff_close_and_cleanup
#define _bfd_xcoff_bfd_free_cached_info _bfd_bool_bfd_true
#define _bfd_xcoff_new_section_hook coff_new_section_hook
#define _bfd_xcoff_get_section_contents _bfd_generic_get_section_contents
coff_bfd_is_target_special_symbol
#define _bfd_xcoff_get_lineno coff_get_lineno
#define _bfd_xcoff_find_nearest_line coff_find_nearest_line
+#define _bfd_xcoff_find_nearest_line_with_alt \
+coff_find_nearest_line_with_alt
#define _bfd_xcoff_find_line coff_find_line
#define _bfd_xcoff_find_inliner_info coff_find_inliner_info
#define _bfd_xcoff_bfd_make_debug_symbol coff_bfd_make_debug_symbol