X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Farchive.c;h=fd44f5405fef7661f9a35a1e0c8f3255865f2ca8;hb=fd885f3a4d85dc33d794ca359ea91f31e3082717;hp=5e0fd6b97939ebcc7156c1788626936320597023;hpb=36e4dce69dd23bea9ea2258dea35f034b6d6351c;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/archive.c b/bfd/archive.c index 5e0fd6b979..fd44f5405f 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1,7 +1,7 @@ /* BFD back-end for archive files (libraries). Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 - Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. This file is part of BFD, the Binary File Descriptor library. @@ -104,7 +104,6 @@ SUBSECTION BSD 4.4 uses a third scheme: It writes a long filename directly after the header. This allows 'ar q' to work. - We currently can read BSD 4.4 archives, but not write them. */ /* Summary of archive member names: @@ -125,7 +124,6 @@ SUBSECTION "/18 " - SVR4 style, name at offset 18 in name table. "#1/23 " - Long name (or embedded spaces) 23 characters long, BSD 4.4 style, full name follows header. - Implemented for reading, not writing. " 18 " - Long name 18 characters long, extended pseudo-BSD. */ @@ -159,6 +157,11 @@ struct ar_cache { #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) #define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata (bfd)->arch_header) + +/* True iff NAME designated a BSD 4.4 extended name. */ + +#define is_bsd44_extended_name(NAME) \ + (NAME[0] == '#' && NAME[1] == '1' && NAME[2] == '/' && ISDIGIT (NAME[3])) void _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) @@ -175,13 +178,36 @@ _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val) else memcpy (p, buf, n); } + +bfd_boolean +_bfd_ar_sizepad (char *p, size_t n, bfd_size_type size) +{ + static char buf[21]; + size_t len; + + snprintf (buf, sizeof (buf), "%-10" BFD_VMA_FMT "u", size); + len = strlen (buf); + if (len > n) + { + bfd_set_error (bfd_error_file_too_big); + return FALSE; + } + if (len < n) + { + memcpy (p, buf, len); + memset (p + len, ' ', n - len); + } + else + memcpy (p, buf, n); + return TRUE; +} bfd_boolean _bfd_generic_mkarchive (bfd *abfd) { bfd_size_type amt = sizeof (struct artdata); - abfd->tdata.aout_ar_data = bfd_zalloc (abfd, amt); + abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc (abfd, amt); if (bfd_ardata (abfd) == NULL) return FALSE; @@ -300,6 +326,15 @@ eq_file_ptr (const PTR p1, const PTR p2) return arc1->ptr == arc2->ptr; } +/* The calloc function doesn't always take size_t (e.g. on VMS) + so wrap it to avoid a compile time warning. */ + +static void * +_bfd_calloc_wrapper (size_t a, size_t b) +{ + return calloc (a, b); +} + /* Kind of stupid to call cons for each one, but we don't do too many. */ bfd_boolean @@ -312,14 +347,14 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt) if (hash_table == NULL) { hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr, - NULL, calloc, free); + NULL, _bfd_calloc_wrapper, free); if (hash_table == NULL) return FALSE; bfd_ardata (arch_bfd)->cache = hash_table; } /* Insert new_elt into the hash table by filepos. */ - cache = bfd_zalloc (arch_bfd, sizeof (struct ar_cache)); + cache = (struct ar_cache *) bfd_zalloc (arch_bfd, sizeof (struct ar_cache)); cache->ptr = filepos; cache->arbfd = new_elt; *htab_find_slot (hash_table, (const void *) cache, INSERT) = cache; @@ -331,15 +366,19 @@ static bfd * _bfd_find_nested_archive (bfd *arch_bfd, const char *filename) { bfd *abfd; + const char *target; for (abfd = arch_bfd->nested_archives; abfd != NULL; abfd = abfd->archive_next) { - if (strcmp (filename, abfd->filename) == 0) + if (filename_cmp (filename, abfd->filename) == 0) return abfd; } - abfd = bfd_openr (filename, NULL); + target = NULL; + if (!arch_bfd->target_defaulted) + target = arch_bfd->xvec->name; + abfd = bfd_openr (filename, target); if (abfd) { abfd->archive_next = arch_bfd->nested_archives; @@ -354,15 +393,15 @@ _bfd_find_nested_archive (bfd *arch_bfd, const char *filename) static char * get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp) { - unsigned long index = 0; + unsigned long table_index = 0; const char *endp; /* Should extract string so that I can guarantee not to overflow into the next region, but I'm too lazy. */ errno = 0; /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ - index = strtol (name + 1, (char **) &endp, 10); - if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size) + table_index = strtol (name + 1, (char **) &endp, 10); + if (errno != 0 || table_index >= bfd_ardata (arch)->extended_names_size) { bfd_set_error (bfd_error_malformed_archive); return NULL; @@ -373,7 +412,7 @@ get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp) { file_ptr origin = strtol (endp + 1, NULL, 10); - if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size) + if (errno != 0) { bfd_set_error (bfd_error_malformed_archive); return NULL; @@ -383,7 +422,7 @@ get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp) else *originp = 0; - return bfd_ardata (arch)->extended_names + index; + return bfd_ardata (arch)->extended_names + table_index; } /* This functions reads an arch header and returns an areltdata pointer, or @@ -408,13 +447,14 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) { struct ar_hdr hdr; char *hdrp = (char *) &hdr; - size_t parsed_size; + bfd_size_type parsed_size; struct areltdata *ared; char *filename = NULL; bfd_size_type namelen = 0; bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); char *allocptr = 0; file_ptr origin = 0; + unsigned int extra_size = 0; if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr)) { @@ -431,8 +471,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) } errno = 0; - parsed_size = strtol (hdr.ar_size, NULL, 10); - if (errno != 0) + if (sscanf (hdr.ar_size, "%" BFD_VMA_FMT "u", &parsed_size) != 1) { bfd_set_error (bfd_error_malformed_archive); return NULL; @@ -450,19 +489,16 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) if (filename == NULL) return NULL; } - /* BSD4.4-style long filename. - Only implemented for reading, so far! */ - else if (hdr.ar_name[0] == '#' - && hdr.ar_name[1] == '1' - && hdr.ar_name[2] == '/' - && ISDIGIT (hdr.ar_name[3])) + /* BSD4.4-style long filename. */ + else if (is_bsd44_extended_name (hdr.ar_name)) { /* BSD-4.4 extended name */ namelen = atoi (&hdr.ar_name[3]); allocsize += namelen + 1; parsed_size -= namelen; + extra_size = namelen; - allocptr = bfd_zalloc (abfd, allocsize); + allocptr = (char *) bfd_zalloc (abfd, allocsize); if (allocptr == NULL) return NULL; filename = (allocptr @@ -483,12 +519,12 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) spaces, so only look for ' ' if we don't find '/'. */ char *e; - e = memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd)); + e = (char *) memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd)); if (e == NULL) { - e = memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)); + e = (char *) memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)); if (e == NULL) - e = memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd)); + e = (char *) memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd)); } if (e != NULL) @@ -505,7 +541,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) if (!allocptr) { - allocptr = bfd_zalloc (abfd, allocsize); + allocptr = (char *) bfd_zalloc (abfd, allocsize); if (allocptr == NULL) return NULL; } @@ -515,6 +551,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) ared->arch_header = allocptr + sizeof (struct areltdata); memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr)); ared->parsed_size = parsed_size; + ared->extra_size = extra_size; ared->origin = origin; if (filename != NULL) @@ -534,8 +571,8 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) /* Append the relative pathname for a member of the thin archive to the pathname of the directory containing the archive. */ -static char * -append_relative_path (bfd *arch, char *elt_name) +char * +_bfd_append_relative_path (bfd *arch, char *elt_name) { const char *arch_name = arch->filename; const char *base_name = lbasename (arch_name); @@ -546,7 +583,7 @@ append_relative_path (bfd *arch, char *elt_name) return elt_name; prefix_len = base_name - arch_name; - filename = bfd_alloc (arch, prefix_len + strlen (elt_name) + 1); + filename = (char *) bfd_alloc (arch, prefix_len + strlen (elt_name) + 1); if (filename == NULL) return NULL; @@ -566,12 +603,6 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) bfd *n_nfd; char *filename; - if (archive->my_archive) - { - filepos += archive->origin; - archive = archive->my_archive; - } - n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); if (n_nfd) return n_nfd; @@ -579,17 +610,19 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) if (0 > bfd_seek (archive, filepos, SEEK_SET)) return NULL; - if ((new_areldata = _bfd_read_ar_hdr (archive)) == NULL) + if ((new_areldata = (struct areltdata *) _bfd_read_ar_hdr (archive)) == NULL) return NULL; filename = new_areldata->filename; if (bfd_is_thin_archive (archive)) { + const char *target; + /* This is a proxy entry for an external file. */ if (! IS_ABSOLUTE_PATH (filename)) { - filename = append_relative_path (archive, filename); + filename = _bfd_append_relative_path (archive, filename); if (filename == NULL) return NULL; } @@ -617,7 +650,12 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) } /* It's not an element of a nested archive; open the external file as a bfd. */ - n_nfd = bfd_openr (filename, NULL); + target = NULL; + if (!archive->target_defaulted) + target = archive->xvec->name; + n_nfd = bfd_openr (filename, target); + if (n_nfd == NULL) + bfd_set_error (bfd_error_malformed_archive); } else { @@ -644,26 +682,25 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) n_nfd->arelt_data = new_areldata; + /* Copy BFD_COMPRESS and BFD_DECOMPRESS flags. */ + n_nfd->flags |= archive->flags & (BFD_COMPRESS | BFD_DECOMPRESS); + if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) return n_nfd; - /* Huh? */ - /* FIXME: n_nfd isn't allocated in the archive's memory pool. - If we reach this point, I think bfd_release will abort. */ - bfd_release (archive, n_nfd); bfd_release (archive, new_areldata); return NULL; } /* Return the BFD which is referenced by the symbol in ABFD indexed by - INDEX. INDEX should have been returned by bfd_get_next_mapent. */ + SYM_INDEX. SYM_INDEX should have been returned by bfd_get_next_mapent. */ bfd * -_bfd_generic_get_elt_at_index (bfd *abfd, symindex index) +_bfd_generic_get_elt_at_index (bfd *abfd, symindex sym_index) { carsym *entry; - entry = bfd_ardata (abfd)->symdefs + index; + entry = bfd_ardata (abfd)->symdefs + sym_index; return _bfd_get_elt_at_filepos (abfd, entry->file_offset); } @@ -706,12 +743,11 @@ bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file) filestart = bfd_ardata (archive)->first_file_filepos; else { - unsigned int size = arelt_size (last_file); + bfd_size_type size = arelt_size (last_file); + filestart = last_file->proxy_origin; if (! bfd_is_thin_archive (archive)) filestart += size; - if (archive->my_archive) - filestart -= archive->origin; /* Pad to an even boundary... Note that last_file->origin can be odd in the case of BSD-4.4-style element with a long odd size. */ @@ -740,12 +776,12 @@ bfd_generic_archive_p (bfd *abfd) if (strncmp (armag, ARMAG, SARMAG) != 0 && strncmp (armag, ARMAGB, SARMAG) != 0 && ! bfd_is_thin_archive (abfd)) - return 0; + return NULL; tdata_hold = bfd_ardata (abfd); amt = sizeof (struct artdata); - bfd_ardata (abfd) = bfd_zalloc (abfd, amt); + bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt); if (bfd_ardata (abfd) == NULL) { bfd_ardata (abfd) = tdata_hold; @@ -771,7 +807,7 @@ bfd_generic_archive_p (bfd *abfd) return NULL; } - if (bfd_has_map (abfd)) + if (abfd->target_defaulted && bfd_has_map (abfd)) { bfd *first; @@ -835,13 +871,13 @@ do_slurp_bsd_armap (bfd *abfd) bfd_size_type parsed_size, amt; carsym *set; - mapdata = _bfd_read_ar_hdr (abfd); + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == NULL) return FALSE; parsed_size = mapdata->parsed_size; bfd_release (abfd, mapdata); /* Don't need it any more. */ - raw_armap = bfd_zalloc (abfd, parsed_size); + raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); if (raw_armap == NULL) return FALSE; @@ -870,7 +906,7 @@ do_slurp_bsd_armap (bfd *abfd) + ardata->symdef_count * BSD_SYMDEF_SIZE + BSD_STRING_COUNT_SIZE); amt = ardata->symdef_count * sizeof (carsym); - ardata->symdefs = bfd_alloc (abfd, amt); + ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt); if (!ardata->symdefs) return FALSE; @@ -903,7 +939,7 @@ do_slurp_coff_armap (bfd *abfd) struct artdata *ardata = bfd_ardata (abfd); char *stringbase; bfd_size_type stringsize; - unsigned int parsed_size; + bfd_size_type parsed_size; carsym *carsyms; bfd_size_type nsymz; /* Number of symbols in armap. */ bfd_vma (*swap) (const void *); @@ -911,7 +947,7 @@ do_slurp_coff_armap (bfd *abfd) bfd_size_type carsym_size, ptrsize; unsigned int i; - mapdata = _bfd_read_ar_hdr (abfd); + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == NULL) return FALSE; parsed_size = mapdata->parsed_size; @@ -956,14 +992,15 @@ do_slurp_coff_armap (bfd *abfd) if (carsym_size + stringsize + 1 <= carsym_size) return FALSE; - ardata->symdefs = bfd_zalloc (abfd, carsym_size + stringsize + 1); + ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, + carsym_size + stringsize + 1); if (ardata->symdefs == NULL) return FALSE; carsyms = ardata->symdefs; stringbase = ((char *) ardata->symdefs) + carsym_size; /* Allocate and read in the raw offsets. */ - raw_armap = bfd_alloc (abfd, ptrsize); + raw_armap = (int *) bfd_alloc (abfd, ptrsize); if (raw_armap == NULL) goto release_symdefs; if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize @@ -998,7 +1035,7 @@ do_slurp_coff_armap (bfd *abfd) struct areltdata *tmp; bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET); - tmp = _bfd_read_ar_hdr (abfd); + tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (tmp != NULL) { if (tmp->arch_header[0] == '/' @@ -1053,6 +1090,25 @@ bfd_slurp_armap (bfd *abfd) return FALSE; #endif } + else if (CONST_STRNEQ (nextname, "#1/20 ")) + { + /* Mach-O has a special name for armap when the map is sorted by name. + However because this name has a space it is slightly more difficult + to check it. */ + struct ar_hdr hdr; + char extname[21]; + + if (bfd_bread (&hdr, sizeof (hdr), abfd) != sizeof (hdr)) + return FALSE; + /* Read the extended name. We know its length. */ + if (bfd_bread (extname, 20, abfd) != 20) + return FALSE; + if (bfd_seek (abfd, -(file_ptr) (sizeof (hdr) + 20), SEEK_CUR) != 0) + return FALSE; + if (CONST_STRNEQ (extname, "__.SYMDEF SORTED") + || CONST_STRNEQ (extname, "__.SYMDEF")) + return do_slurp_bsd_armap (abfd); + } bfd_has_map (abfd) = FALSE; return TRUE; @@ -1075,6 +1131,7 @@ bfd_slurp_bsd_armap_f2 (bfd *abfd) struct artdata *ardata = bfd_ardata (abfd); char *stringbase; unsigned int stringsize; + unsigned int left; bfd_size_type amt; carsym *set; int i = bfd_bread (nextname, 16, abfd); @@ -1098,48 +1155,51 @@ bfd_slurp_bsd_armap_f2 (bfd *abfd) return TRUE; } - mapdata = _bfd_read_ar_hdr (abfd); + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == NULL) return FALSE; - amt = mapdata->parsed_size; - raw_armap = bfd_zalloc (abfd, amt); - if (raw_armap == NULL) + if (mapdata->parsed_size < HPUX_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE) { + wrong_format: + bfd_set_error (bfd_error_wrong_format); byebye: bfd_release (abfd, mapdata); return FALSE; } + left = mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE - BSD_STRING_COUNT_SIZE; + + amt = mapdata->parsed_size; + raw_armap = (bfd_byte *) bfd_zalloc (abfd, amt); + if (raw_armap == NULL) + goto byebye; if (bfd_bread (raw_armap, amt, abfd) != amt) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_malformed_archive); - byebyebye: - bfd_release (abfd, raw_armap); goto byebye; } ardata->symdef_count = H_GET_16 (abfd, raw_armap); - if (ardata->symdef_count * BSD_SYMDEF_SIZE - > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE) - { - /* Probably we're using the wrong byte ordering. */ - bfd_set_error (bfd_error_wrong_format); - goto byebyebye; - } - ardata->cache = 0; stringsize = H_GET_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE); + if (stringsize > left) + goto wrong_format; + left -= stringsize; + /* Skip sym count and string sz. */ stringbase = ((char *) raw_armap + HPUX_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE); rbase = (bfd_byte *) stringbase + stringsize; amt = ardata->symdef_count * BSD_SYMDEF_SIZE; - ardata->symdefs = bfd_alloc (abfd, amt); + if (amt > left) + goto wrong_format; + + ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt); if (!ardata->symdefs) return FALSE; @@ -1182,7 +1242,9 @@ _bfd_slurp_extended_name_table (bfd *abfd) /* FIXME: Formatting sucks here, and in case of failure of BFD_READ, we probably don't want to return TRUE. */ - bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET); + if (bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET) != 0) + return FALSE; + if (bfd_bread (nextname, 16, abfd) == 16) { if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) @@ -1196,7 +1258,7 @@ _bfd_slurp_extended_name_table (bfd *abfd) return TRUE; } - namedata = _bfd_read_ar_hdr (abfd); + namedata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (namedata == NULL) return FALSE; @@ -1205,7 +1267,7 @@ _bfd_slurp_extended_name_table (bfd *abfd) goto byebye; bfd_ardata (abfd)->extended_names_size = amt; - bfd_ardata (abfd)->extended_names = bfd_zalloc (abfd, amt + 1); + bfd_ardata (abfd)->extended_names = (char *) bfd_zalloc (abfd, amt + 1); if (bfd_ardata (abfd)->extended_names == NULL) { byebye: @@ -1293,39 +1355,55 @@ normalize (bfd *abfd, const char *file) static const char * normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file) { - const char *filename = strrchr (file, '/'); - -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - { - /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ - char *bslash = strrchr (file, '\\'); - if (filename == NULL || (bslash != NULL && bslash > filename)) - filename = bslash; - if (filename == NULL && file[0] != '\0' && file[1] == ':') - filename = file + 1; - } -#endif - if (filename != NULL) - filename++; - else - filename = file; - return filename; + return lbasename (file); } #endif -/* Adjust a relative path name based on the reference path. */ - +/* Adjust a relative path name based on the reference path. + For example: + + Relative path Reference path Result + ------------- -------------- ------ + bar.o lib.a bar.o + foo/bar.o lib.a foo/bar.o + bar.o foo/lib.a ../bar.o + foo/bar.o baz/lib.a ../foo/bar.o + bar.o ../lib.a /bar.o + ; ../bar.o ../lib.a bar.o + ; ../bar.o lib.a ../bar.o + foo/bar.o ../lib.a /foo/bar.o + bar.o ../../lib.a //bar.o + bar.o foo/baz/lib.a ../../bar.o + + Note - the semicolons above are there to prevent the BFD chew + utility from interpreting those lines as prototypes to put into + the autogenerated bfd.h header... + + Note - the string is returned in a static buffer. */ + static const char * adjust_relative_path (const char * path, const char * ref_path) { static char *pathbuf = NULL; - static int pathbuf_len = 0; - const char *pathp = path; - const char *refp = ref_path; - int element_count = 0; - int len; + static unsigned int pathbuf_len = 0; + const char *pathp; + const char *refp; + char * lpath; + char * rpath; + unsigned int len; + unsigned int dir_up = 0; + unsigned int dir_down = 0; char *newp; + char * pwd = getpwd (); + const char * down; + + /* Remove symlinks, '.' and '..' from the paths, if possible. */ + lpath = lrealpath (path); + pathp = lpath == NULL ? path : lpath; + rpath = lrealpath (ref_path); + refp = rpath == NULL ? ref_path : rpath; + /* Remove common leading path elements. */ for (;;) { @@ -1337,39 +1415,76 @@ adjust_relative_path (const char * path, const char * ref_path) while (*e2 && ! IS_DIR_SEPARATOR (*e2)) ++e2; if (*e1 == '\0' || *e2 == '\0' || e1 - pathp != e2 - refp - || strncmp (pathp, refp, e1 - pathp) != 0) + || filename_ncmp (pathp, refp, e1 - pathp) != 0) break; pathp = e1 + 1; refp = e2 + 1; } + len = strlen (pathp) + 1; /* For each leading path element in the reference path, insert "../" into the path. */ for (; *refp; ++refp) if (IS_DIR_SEPARATOR (*refp)) - ++element_count; - len = 3 * element_count + strlen (path) + 1; + { + /* PR 12710: If the path element is "../" then instead of + inserting "../" we need to insert the name of the directory + at the current level. */ + if (refp > ref_path + 1 + && refp[-1] == '.' + && refp[-2] == '.') + dir_down ++; + else + dir_up ++; + } + + /* If the lrealpath calls above succeeded then we should never + see dir_up and dir_down both being non-zero. */ + + len += 3 * dir_up; + + if (dir_down) + { + down = pwd + strlen (pwd) - 1; + + while (dir_down && down > pwd) + { + if (IS_DIR_SEPARATOR (*down)) + --dir_down; + } + BFD_ASSERT (dir_down == 0); + len += strlen (down) + 1; + } + else + down = NULL; if (len > pathbuf_len) { if (pathbuf != NULL) free (pathbuf); pathbuf_len = 0; - pathbuf = bfd_malloc (len); + pathbuf = (char *) bfd_malloc (len); if (pathbuf == NULL) - return path; + goto out; pathbuf_len = len; } newp = pathbuf; - while (element_count-- > 0) + while (dir_up-- > 0) { /* FIXME: Support Windows style path separators as well. */ strcpy (newp, "../"); newp += 3; } - strcpy (newp, pathp); + if (down) + sprintf (newp, "%s/%s", down, pathp); + else + strcpy (newp, pathp); + + out: + free (lpath); + free (rpath); return pathbuf; } @@ -1411,7 +1526,7 @@ _bfd_construct_extended_name_table (bfd *abfd, char **tabloc, bfd_size_type *tablen) { - unsigned int maxname = abfd->xvec->ar_max_namelen; + unsigned int maxname = ar_maxnamelen (abfd); bfd_size_type total_namelen = 0; bfd *current; char *strptr; @@ -1442,7 +1557,7 @@ _bfd_construct_extended_name_table (bfd *abfd, /* If the path is the same as the previous path seen, reuse it. This can happen when flattening a thin archive that contains other archives. */ - if (last_filename && strcmp (last_filename, filename) == 0) + if (last_filename && filename_cmp (last_filename, filename) == 0) continue; last_filename = filename; @@ -1488,7 +1603,7 @@ _bfd_construct_extended_name_table (bfd *abfd, else { struct ar_hdr *hdr = arch_hdr (current); - if (strncmp (normal, hdr->ar_name, thislen) != 0 + if (filename_ncmp (normal, hdr->ar_name, thislen) != 0 || (thislen < sizeof hdr->ar_name && hdr->ar_name[thislen] != ar_padchar (current))) { @@ -1505,7 +1620,7 @@ _bfd_construct_extended_name_table (bfd *abfd, if (total_namelen == 0) return TRUE; - *tabloc = bfd_zalloc (abfd, total_namelen); + *tabloc = (char *) bfd_zalloc (abfd, total_namelen); if (*tabloc == NULL) return FALSE; @@ -1536,7 +1651,7 @@ _bfd_construct_extended_name_table (bfd *abfd, archive that contains other archives. If the path is relative, adjust it relative to the containing archive. */ - if (last_filename && strcmp (last_filename, filename) == 0) + if (last_filename && filename_cmp (last_filename, filename) == 0) normal = last_filename; else if (! IS_ABSOLUTE_PATH (filename) && ! IS_ABSOLUTE_PATH (abfd->filename)) @@ -1596,6 +1711,105 @@ _bfd_construct_extended_name_table (bfd *abfd, return TRUE; } + +/* Do not construct an extended name table but transforms name field into + its extended form. */ + +bfd_boolean +_bfd_archive_bsd44_construct_extended_name_table (bfd *abfd, + char **tabloc, + bfd_size_type *tablen, + const char **name) +{ + unsigned int maxname = ar_maxnamelen (abfd); + bfd *current; + + *tablen = 0; + *tabloc = NULL; + *name = NULL; + + for (current = abfd->archive_head; + current != NULL; + current = current->archive_next) + { + const char *normal = normalize (current, current->filename); + int has_space = 0; + unsigned int len; + + if (normal == NULL) + return FALSE; + + for (len = 0; normal[len]; len++) + if (normal[len] == ' ') + has_space = 1; + + if (len > maxname || has_space) + { + struct ar_hdr *hdr = arch_hdr (current); + + len = (len + 3) & ~3; + arch_eltdata (current)->extra_size = len; + _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len); + } + } + + return TRUE; +} + +/* Write an archive header. */ + +bfd_boolean +_bfd_generic_write_ar_hdr (bfd *archive, bfd *abfd) +{ + struct ar_hdr *hdr = arch_hdr (abfd); + + if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) + return FALSE; + return TRUE; +} + +/* Write an archive header using BSD4.4 convention. */ + +bfd_boolean +_bfd_bsd44_write_ar_hdr (bfd *archive, bfd *abfd) +{ + struct ar_hdr *hdr = arch_hdr (abfd); + + if (is_bsd44_extended_name (hdr->ar_name)) + { + /* This is a BSD 4.4 extended name. */ + const char *fullname = normalize (abfd, abfd->filename); + unsigned int len = strlen (fullname); + unsigned int padded_len = (len + 3) & ~3; + + BFD_ASSERT (padded_len == arch_eltdata (abfd)->extra_size); + + if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), + arch_eltdata (abfd)->parsed_size + padded_len)) + return FALSE; + + if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) + return FALSE; + + if (bfd_bwrite (fullname, len, archive) != len) + return FALSE; + + if (len & 3) + { + static const char pad[3] = { 0, 0, 0 }; + + len = 4 - (len & 3); + if (bfd_bwrite (pad, len, archive) != len) + return FALSE; + } + } + else + { + if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr)) + return FALSE; + } + return TRUE; +} /* A couple of functions for creating ar_hdrs. */ @@ -1639,7 +1853,7 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) if (member && (member->flags & BFD_IN_MEMORY) != 0) { /* Assume we just "made" the member, and fake it. */ - struct bfd_in_memory *bim = member->iostream; + struct bfd_in_memory *bim = (struct bfd_in_memory *) member->iostream; time (&status.st_mtime); status.st_uid = getuid (); status.st_gid = getgid (); @@ -1663,7 +1877,7 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) } amt = sizeof (struct ar_hdr) + sizeof (struct areltdata); - ared = bfd_zalloc (abfd, amt); + ared = (struct areltdata *) bfd_zalloc (abfd, amt); if (ared == NULL) return NULL; hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); @@ -1693,8 +1907,11 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) status.st_gid); _bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo", status.st_mode); - _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld", - status.st_size); + if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), status.st_size)) + { + free (ared); + return NULL; + } memcpy (hdr->ar_fmag, ARFMAG, 2); ared->parsed_size = status.st_size; ared->arch_header = (char *) hdr; @@ -1702,22 +1919,6 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) return ared; } -/* This is magic required by the "ar" program. Since it's - undocumented, it's undocumented. You may think that it would take - a strong stomach to write this, and it does, but it takes even a - stronger stomach to try to code around such a thing! */ - -struct ar_hdr *bfd_special_undocumented_glue (bfd *, const char *); - -struct ar_hdr * -bfd_special_undocumented_glue (bfd *abfd, const char *filename) -{ - struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename, 0); - if (ar_elt == NULL) - return NULL; - return (struct ar_hdr *) ar_elt->arch_header; -} - /* Analogous to stat call. */ int @@ -1817,25 +2018,9 @@ bfd_bsd_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) { struct ar_hdr *hdr = (struct ar_hdr *) arhdr; size_t length; - const char *filename = strrchr (pathname, '/'); + const char *filename = lbasename (pathname); size_t maxlen = ar_maxnamelen (abfd); -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - { - /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ - char *bslash = strrchr (pathname, '\\'); - if (filename == NULL || (bslash != NULL && bslash > filename)) - filename = bslash; - if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':') - filename = pathname + 1; - } -#endif - - if (filename == NULL) - filename = pathname; - else - ++filename; - length = strlen (filename); if (length <= maxlen) @@ -1865,26 +2050,9 @@ bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr) { struct ar_hdr *hdr = (struct ar_hdr *) arhdr; size_t length; - const char *filename = strrchr (pathname, '/'); + const char *filename = lbasename (pathname); size_t maxlen = ar_maxnamelen (abfd); -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - { - /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ - char *bslash = strrchr (pathname, '\\'); - - if (filename == NULL || (bslash != NULL && bslash > filename)) - filename = bslash; - if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':') - filename = pathname + 1; - } -#endif - - if (filename == NULL) - filename = pathname; - else - ++filename; - length = strlen (filename); if (length <= maxlen) @@ -1983,8 +2151,9 @@ _bfd_write_archive_contents (bfd *arch) memset (&hdr, ' ', sizeof (struct ar_hdr)); memcpy (hdr.ar_name, ename, strlen (ename)); /* Round size up to even number in archive header. */ - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", - (elength + 1) & ~(bfd_size_type) 1); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), + (elength + 1) & ~(bfd_size_type) 1)) + return FALSE; memcpy (hdr.ar_fmag, ARFMAG, 2); if ((bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) != sizeof (struct ar_hdr)) @@ -2002,13 +2171,11 @@ _bfd_write_archive_contents (bfd *arch) current = current->archive_next) { char buffer[DEFAULT_BUFFERSIZE]; - unsigned int remaining = arelt_size (current); - struct ar_hdr *hdr = arch_hdr (current); + bfd_size_type remaining = arelt_size (current); /* Write ar header. */ - if (bfd_bwrite (hdr, sizeof (*hdr), arch) - != sizeof (*hdr)) - return FALSE; + if (!_bfd_write_ar_hdr (arch, current)) + return FALSE; if (bfd_is_thin_archive (arch)) continue; if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) @@ -2088,13 +2255,13 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) elength += elength % 2; amt = orl_max * sizeof (struct orl); - map = bfd_malloc (amt); + map = (struct orl *) bfd_malloc (amt); if (map == NULL) goto error_return; /* We put the symbol names on the arch objalloc, and then discard them when done. */ - first_name = bfd_alloc (arch, 1); + first_name = (char *) bfd_alloc (arch, 1); if (first_name == NULL) goto error_return; @@ -2126,7 +2293,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) if (syms_max > 0) free (syms); syms_max = storage; - syms = bfd_malloc (syms_max); + syms = (asymbol **) bfd_malloc (syms_max); if (syms == NULL) goto error_return; } @@ -2144,6 +2311,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) if ((flags & BSF_GLOBAL || flags & BSF_WEAK || flags & BSF_INDIRECT + || flags & BSF_GNU_UNIQUE || bfd_is_com_section (sec)) && ! bfd_is_und_section (sec)) { @@ -2155,7 +2323,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) { orl_max *= 2; amt = orl_max * sizeof (struct orl); - new_map = bfd_realloc (map, amt); + new_map = (struct orl *) bfd_realloc (map, amt); if (new_map == NULL) goto error_return; @@ -2164,10 +2332,11 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) namelen = strlen (syms[src_count]->name); amt = sizeof (char *); - map[orl_count].name = bfd_alloc (arch, amt); + map[orl_count].name = (char **) bfd_alloc (arch, amt); if (map[orl_count].name == NULL) goto error_return; - *(map[orl_count].name) = bfd_alloc (arch, namelen + 1); + *(map[orl_count].name) = (char *) bfd_alloc (arch, + namelen + 1); if (*(map[orl_count].name) == NULL) goto error_return; strcpy (*(map[orl_count].name), syms[src_count]->name); @@ -2229,31 +2398,28 @@ bsd_write_armap (bfd *arch, bfd_byte temp[4]; unsigned int count; struct ar_hdr hdr; - struct stat statbuf; long uid, gid; firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; - stat (arch->filename, &statbuf); + /* If deterministic, we use 0 as the timestamp in the map. + Some linkers may require that the archive filesystem modification + time is less than (or near to) the archive map timestamp. Those + linkers should not be used with deterministic mode. (GNU ld and + Gold do not have this restriction.) */ + bfd_ardata (arch)->armap_timestamp = 0; + uid = 0; + gid = 0; if ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0) { - /* Remember the timestamp, to keep it holy. But fudge it a little. */ - bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime - + ARMAP_TIME_OFFSET); + struct stat statbuf; + + if (stat (arch->filename, &statbuf) == 0) + bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime + + ARMAP_TIME_OFFSET); uid = getuid(); gid = getgid(); } - else - { - /* If deterministic, we use 0 as the timestamp in the map. - Some linkers may require that the archive filesystem modification - time is less than (or near to) the archive map timestamp. Those - linkers should not be used with deterministic mode. (GNU ld and - Gold do not have this restriction.) */ - bfd_ardata (arch)->armap_timestamp = 0; - uid = 0; - gid = 0; - } memset (&hdr, ' ', sizeof (struct ar_hdr)); memcpy (hdr.ar_name, RANLIBMAG, strlen (RANLIBMAG)); @@ -2263,7 +2429,8 @@ bsd_write_armap (bfd *arch, bfd_ardata (arch)->armap_timestamp); _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", uid); _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", gid); - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) + return FALSE; memcpy (hdr.ar_fmag, ARFMAG, 2); if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) != sizeof (struct ar_hdr)) @@ -2280,7 +2447,10 @@ bsd_write_armap (bfd *arch, { do { - firstreal += arelt_size (current) + sizeof (struct ar_hdr); + struct areltdata *ared = arch_eltdata (current); + + firstreal += (ared->parsed_size + ared->extra_size + + sizeof (struct ar_hdr)); firstreal += firstreal % 2; current = current->archive_next; } @@ -2415,8 +2585,8 @@ coff_write_armap (bfd *arch, memset (&hdr, ' ', sizeof (struct ar_hdr)); hdr.ar_name[0] = '/'; - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", - mapsize); + if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) + return FALSE; _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0 ? time (NULL) : 0));