aboutsummaryrefslogtreecommitdiff
path: root/bfd/archive.c
diff options
context:
space:
mode:
authorPer Bothner <per@bothner.com>1992-12-16 00:01:59 +0000
committerPer Bothner <per@bothner.com>1992-12-16 00:01:59 +0000
commit287c221dd2a91102d870178b6e3fd5a6fcfed549 (patch)
tree44c2563b6f9fa69971a2d5cec155adfa1fff43c1 /bfd/archive.c
parentb5329d84cc108d6b44dd6d330ea209cb46ec7b76 (diff)
downloadgdb-287c221dd2a91102d870178b6e3fd5a6fcfed549.zip
gdb-287c221dd2a91102d870178b6e3fd5a6fcfed549.tar.gz
gdb-287c221dd2a91102d870178b6e3fd5a6fcfed549.tar.bz2
Various changes to improve archive support. See ChangeLog.
Diffstat (limited to 'bfd/archive.c')
-rw-r--r--bfd/archive.c355
1 files changed, 187 insertions, 168 deletions
diff --git a/bfd/archive.c b/bfd/archive.c
index a46372c..33c144b 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -1,5 +1,5 @@
/* BFD back-end for archive files (libraries).
- Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992 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.
@@ -50,12 +50,12 @@ DESCRIPTION
As expected, the BFD archive code is more general than the
archive code of any given environment. BFD archives may
- contain files of different formats (eg a.out and coff) and
+ contain files of different formats (e.g., a.out and coff) and
even different architectures. You may even place archives
recursively into archives!
This can cause unexpected confusion, since some archive
- formats are more expressive than others. For instance intel
+ formats are more expressive than others. For instance, Intel
COFF archives can preserve long filenames; Sun a.out archives
cannot. If you move a file from the first to the second
format and back again, the filename may be truncated.
@@ -273,9 +273,10 @@ get_extended_arelt_filename (arch, name)
unsigned long index = 0;
/* Should extract string so that I can guarantee not to overflow into
- the next region, but I"m too lazy. */
+ the next region, but I'm too lazy. */
errno = 0;
- index = strtol (name, NULL, 10);
+ /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
+ index = strtol (name+1, NULL, 10);
if (errno != 0) {
bfd_error = malformed_archive;
return NULL;
@@ -329,8 +330,10 @@ snarf_ar_hdr (abfd)
/* extract the filename from the archive - there are two ways to
specify an extendend name table, either the first char of the
- name is a space, or it's a slash */
- if ((hdr.ar_name[0] == '/' || hdr.ar_name[0] == ' ')
+ name is a space, or it's a slash. */
+ if ((hdr.ar_name[0] == '/'
+ || (hdr.ar_name[0] == ' '
+ && memchr (hdr.ar_name, '/', ar_maxnamelen(abfd)) == NULL))
&& bfd_ardata (abfd)->extended_names != NULL) {
filename = get_extended_arelt_filename (abfd, hdr.ar_name);
if (filename == NULL) {
@@ -340,16 +343,22 @@ snarf_ar_hdr (abfd)
}
else
{
- /* We judge the end of the name by looking for a space or a
- padchar */
+ /* We judge the end of the name by looking for '/' or ' '.
+ Note: The SYSV format (terminated by '/') allows embedded
+ spaces, so only look for ' ' if we don't find '/'. */
namelen = 0;
-
- while (namelen < (unsigned)ar_maxnamelen(abfd) &&
- ( hdr.ar_name[namelen] != 0 &&
- hdr.ar_name[namelen] != ' ' &&
- hdr.ar_name[namelen] != ar_padchar(abfd))) {
+ while (hdr.ar_name[namelen] != '\0' &&
+ hdr.ar_name[namelen] != '/') {
namelen++;
+ if (namelen == (unsigned)ar_maxnamelen(abfd)) {
+ namelen = 0;
+ while (hdr.ar_name[namelen] != ' '
+ && namelen < (unsigned)ar_maxnamelen(abfd)) {
+ namelen++;
+ }
+ break;
+ }
}
allocsize += namelen + 1;
@@ -529,7 +538,7 @@ bfd_generic_archive_p (abfd)
bfd_ardata (abfd)->first_file_filepos = SARMAG;
- if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) {
+ if (!bfd_slurp_armap (abfd)) {
bfd_release(abfd, bfd_ardata (abfd));
abfd->tdata.aout_ar_data = NULL;
return 0;
@@ -545,85 +554,71 @@ bfd_generic_archive_p (abfd)
}
/* Returns false on error, true otherwise */
-boolean
-bfd_slurp_bsd_armap (abfd)
+static boolean
+do_slurp_bsd_armap (abfd)
bfd *abfd;
{
- struct areltdata *mapdata;
- char nextname[17];
- unsigned int counter = 0;
- int *raw_armap, *rbase;
- struct artdata *ardata = bfd_ardata (abfd);
- char *stringbase;
-
- /* FIXME, if the read fails, this routine quietly returns "true"!!
- It should probably do that if the read gives 0 bytes (empty archive),
- but fail for any other size... */
- if (bfd_read ((PTR)nextname, 1, 16, abfd) == 16) {
- /* The archive has at least 16 bytes in it */
- bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
-
- /* This should be using RANLIBMAG, but at least it can be grepped for
- in this comment. */
- if (strncmp (nextname, "__.SYMDEF ", 16)) {
- bfd_has_map (abfd) = false;
- return true;
- }
-
- mapdata = snarf_ar_hdr (abfd);
- if (mapdata == NULL) return false;
-
- raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size);
- if (raw_armap == NULL) {
- bfd_error = no_memory;
- byebye:
- bfd_release (abfd, (PTR)mapdata);
- return false;
- }
-
- if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) !=
- mapdata->parsed_size) {
- bfd_error = malformed_archive;
- byebyebye:
- bfd_release (abfd, (PTR)raw_armap);
- goto byebye;
- }
-
- ardata->symdef_count = bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef);
-
- if (ardata->symdef_count * sizeof (struct symdef)
- > mapdata->parsed_size - sizeof (*raw_armap)) {
- /* Probably we're using the wrong byte ordering. */
- bfd_error = wrong_format;
- goto byebyebye;
- }
-
- ardata->cache = 0;
- rbase = raw_armap+1;
- ardata->symdefs = (carsym *) rbase;
- stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4;
+ struct areltdata *mapdata;
+ char nextname[17];
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int parsed_size;
- for (;counter < ardata->symdef_count; counter++) {
- struct symdef *sym = ((struct symdef *) rbase) + counter;
- sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
- sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
- }
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */
+
+ raw_armap = (int *) bfd_zalloc(abfd, parsed_size);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ if (bfd_read ((PTR)raw_armap, 1, parsed_size, abfd) != parsed_size) {
+ bfd_error = malformed_archive;
+ byebye:
+ bfd_release (abfd, (PTR)raw_armap);
+ return false;
+ }
+
+ ardata->symdef_count =
+ bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef);
+
+ if (ardata->symdef_count * sizeof (struct symdef)
+ > parsed_size - sizeof (*raw_armap)) {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebye;
+ }
- ardata->first_file_filepos = bfd_tell (abfd);
- /* Pad to an even boundary if you have to */
- ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
- /* FIXME, we should provide some way to free raw_ardata when
- we are done using the strings from it. For now, it seems
- to be allocated on an obstack anyway... */
- bfd_has_map (abfd) = true;
- }
- return true;
+ ardata->cache = 0;
+ rbase = raw_armap+1;
+ ardata->symdefs = (carsym *) rbase;
+ stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4;
+
+ for (;counter < ardata->symdef_count; counter++) {
+ struct symdef *sym = ((struct symdef *) rbase) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
}
/* Returns false on error, true otherwise */
-boolean
-bfd_slurp_coff_armap (abfd)
+static boolean
+do_slurp_coff_armap (abfd)
bfd *abfd;
{
struct areltdata *mapdata;
@@ -632,104 +627,119 @@ bfd_slurp_coff_armap (abfd)
struct artdata *ardata = bfd_ardata (abfd);
char *stringbase;
unsigned int stringsize;
+ unsigned int parsed_size;
carsym *carsyms;
int result;
+ unsigned int nsymz; /* Number of symbols in armap. */
+
bfd_vma (*swap)();
+ char int_buf[sizeof(long)];
+ unsigned int carsym_size, ptrsize, i;
- result = bfd_read ((PTR)&nextname, 1, 1, abfd);
- bfd_seek (abfd, (file_ptr) -1, SEEK_CUR);
-
- if (result != 1 || nextname != '/') {
- /* Actually I think this is an error for a COFF archive */
- bfd_has_map (abfd) = false;
- return true;
- }
-
mapdata = snarf_ar_hdr (abfd);
if (mapdata == NULL) return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */
- raw_armap = (int *) bfd_alloc(abfd,mapdata->parsed_size);
-
- if (raw_armap == NULL)
- {
- bfd_error = no_memory;
- byebye:
- bfd_release (abfd, (PTR)mapdata);
- return false;
- }
-
- /* read in the raw map */
- if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) !=
- mapdata->parsed_size) {
+ if (bfd_read ((PTR)int_buf, 1, 4, abfd) != 4) {
bfd_error = malformed_archive;
- oops:
- bfd_release (abfd, (PTR)raw_armap);
- goto byebye;
+ return false;
}
-
- /* The coff armap must be read sequentially. So we construct a bsd-style
- one in core all at once, for simplicity.
-
- It seems that all numeric information in a coff archive is always
+ /* It seems that all numeric information in a coff archive is always
in big endian format, nomatter the host or target. */
+ swap = _do_getb32;
+ nsymz = _do_getb32((PTR)int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
- stringsize
- = mapdata->parsed_size - (4 * (_do_getb32((PTR)raw_armap))) - 4;
- /* Except that some archive formats are broken, and it may be our
+#if 1
+ /* ... except that some archive formats are broken, and it may be our
fault - the i960 little endian coff sometimes has big and sometimes
little, because our tools changed. Here's a horrible hack to clean
- up the crap
- */
- swap = _do_getb32;
+ up the crap. */
- if (stringsize > 0xfffff)
- {
- /* This looks dangerous, let's do it the other way around */
- stringsize = mapdata->parsed_size - (4 *
- (_do_getl32((PTR)raw_armap))) - 4;
-
- swap = _do_getl32;
+ if (stringsize > 0xfffff) {
+ /* This looks dangerous, let's do it the other way around */
+ nsymz = _do_getl32((PTR)int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
+ swap = _do_getl32;
}
+#endif
+
+ /* The coff armap must be read sequentially. So we construct a bsd-style
+ one in core all at once, for simplicity. */
+ carsym_size = (nsymz * sizeof (carsym));
+ ptrsize = (4 * nsymz);
+
+ ardata->symdefs = (carsym *) bfd_zalloc(abfd, carsym_size + stringsize + 1);
+ if (ardata->symdefs == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+ carsyms = ardata->symdefs;
+ stringbase = ((char *) ardata->symdefs) + carsym_size;
+
+ /* Allocate and read in the raw offsets. */
+ raw_armap = (int *) bfd_alloc(abfd, ptrsize);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ goto release_symdefs;
+ }
+ if (bfd_read ((PTR)raw_armap, 1, ptrsize, abfd) != ptrsize
+ || bfd_read ((PTR)stringbase, 1, stringsize, abfd) != stringsize) {
+ bfd_error = malformed_archive;
+ goto release_raw_armap;
+ }
+
+ /* OK, build the carsyms */
+ for (i = 0; i < nsymz; i++) {
+ rawptr = raw_armap + i;
+ carsyms->file_offset = swap((PTR)rawptr);
+ carsyms->name = stringbase;
+ while (*stringbase++) ;
+ carsyms++;
+ }
+ *stringbase = 0;
- {
- unsigned int nsymz = swap( (PTR)raw_armap);
- unsigned int carsym_size = (nsymz * sizeof (carsym));
- unsigned int ptrsize = (4 * nsymz);
- unsigned int i;
- ardata->symdefs = (carsym *) bfd_zalloc(abfd,carsym_size + stringsize + 1);
- if (ardata->symdefs == NULL) {
- bfd_error = no_memory;
- goto oops;
- }
- carsyms = ardata->symdefs;
-
- stringbase = ((char *) ardata->symdefs) + carsym_size;
- memcpy (stringbase, (char*)raw_armap + ptrsize + 4, stringsize);
-
-
- /* OK, build the carsyms */
- for (i = 0; i < nsymz; i++)
- {
- rawptr = raw_armap + i + 1;
- carsyms->file_offset = swap((PTR)rawptr);
- carsyms->name = stringbase;
- for (; *(stringbase++););
- carsyms++;
- }
- *stringbase = 0;
- }
ardata->symdef_count = swap((PTR)raw_armap);
ardata->first_file_filepos = bfd_tell (abfd);
/* Pad to an even boundary if you have to */
ardata->first_file_filepos += (ardata->first_file_filepos) %2;
- /* We'd like to release these allocations, but we have allocated stuff
- since then (using the same obstack, if bfd_release is obstack based).
- So they will stick around until the BFD is closed. */
- /* bfd_release (abfd, (PTR)raw_armap);
- bfd_release (abfd, (PTR)mapdata); */
bfd_has_map (abfd) = true;
+ bfd_release (abfd, (PTR)raw_armap);
+ return true;
+
+ release_raw_armap:
+ bfd_release (abfd, (PTR)raw_armap);
+ release_symdefs:
+ bfd_release (abfd, (PTR)(ardata)->symdefs);
+ return false;
+}
+
+/* This routine can handle either coff-style or bsd-style armaps.
+ Returns false on error, true otherwise */
+
+boolean
+bfd_slurp_armap (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ int i = bfd_read ((PTR)nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ return do_slurp_bsd_armap (abfd);
+ else if (!strncmp (nextname, "/ ", 16))
+ return do_slurp_coff_armap (abfd);
+
+ bfd_has_map (abfd) = false;
return true;
}
@@ -785,11 +795,14 @@ _bfd_slurp_extended_name_table (abfd)
/* Since the archive is supposed to be printable if it contains
text, the entries in the list are newline-padded, not null
- padded. We'll fix that there.. */
+ padded. In SVR4-style archives, the names also have a
+ trailing '/'. We'll fix both problems here.. */
{
char *temp = bfd_ardata (abfd)->extended_names;
- for (; *temp != '\0'; ++temp)
- if (*temp == '\n') *temp = '\0';
+ char *limit = temp + namedata->parsed_size;
+ for (; temp < limit; ++temp)
+ if (*temp == '\n')
+ temp[temp[-1] == '/' ? -1 : 0] = '\0';
}
/* Pad to an even boundary if you have to */
@@ -1132,7 +1145,12 @@ _bfd_write_archive_contents (arch)
bfd *current;
char *etable = NULL;
unsigned int elength = 0;
- boolean makemap = bfd_has_map (arch);
+
+ /* This used to be: boolean makemap = bfd_has_map (arch).
+ But Posix.2 prohibits requiring a separate ranlib program, so we
+ need to make a map whenever there are object files in the archive. */
+ boolean makemap = true;
+
boolean hasobjects = false; /* if no .o's, don't bother to make a map */
unsigned int i;
@@ -1295,9 +1313,10 @@ compute_and_write_armap (arch, elength)
asection *sec =
syms[src_count]->section;
- if ((flags & BSF_GLOBAL) ||
- (flags & BSF_INDIRECT) ||
- (sec == &bfd_com_section)) {
+ if ((flags & BSF_GLOBAL ||
+ flags & BSF_INDIRECT ||
+ sec == &bfd_com_section)
+ && (sec != &bfd_und_section)) {
/* This symbol will go into the archive header */
if (orl_count == orl_max)