diff options
Diffstat (limited to 'contrib/binutils/bfd/bfd.c')
-rw-r--r-- | contrib/binutils/bfd/bfd.c | 320 |
1 files changed, 296 insertions, 24 deletions
diff --git a/contrib/binutils/bfd/bfd.c b/contrib/binutils/bfd/bfd.c index 733f6ee..510df0a 100644 --- a/contrib/binutils/bfd/bfd.c +++ b/contrib/binutils/bfd/bfd.c @@ -1,6 +1,6 @@ /* Generic BFD library interface and support routines. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Cygnus Support. @@ -139,7 +139,7 @@ CODE_FRAGMENT . {* Stuff only useful for archives. *} . void *arelt_data; . struct bfd *my_archive; {* The containing archive BFD. *} -. struct bfd *next; {* The next BFD in the archive. *} +. struct bfd *archive_next; {* The next BFD in the archive. *} . struct bfd *archive_head; {* The first BFD in the archive. *} . bfd_boolean has_armap; . @@ -202,11 +202,12 @@ CODE_FRAGMENT . */ -#include "bfd.h" -#include "bfdver.h" #include "sysdep.h" #include <stdarg.h> +#include "bfd.h" +#include "bfdver.h" #include "libiberty.h" +#include "demangle.h" #include "safe-ctype.h" #include "bfdlink.h" #include "libbfd.h" @@ -271,6 +272,7 @@ CODE_FRAGMENT . bfd_error_bad_value, . bfd_error_file_truncated, . bfd_error_file_too_big, +. bfd_error_on_input, . bfd_error_invalid_error_code .} .bfd_error_type; @@ -278,6 +280,8 @@ CODE_FRAGMENT */ static bfd_error_type bfd_error = bfd_error_no_error; +static bfd *input_bfd = NULL; +static bfd_error_type input_error = bfd_error_no_error; const char *const bfd_errmsgs[] = { @@ -300,6 +304,7 @@ const char *const bfd_errmsgs[] = N_("Bad value"), N_("File truncated"), N_("File too big"), + N_("Error reading %s: %s"), N_("#<Invalid error code>") }; @@ -325,16 +330,32 @@ FUNCTION bfd_set_error SYNOPSIS - void bfd_set_error (bfd_error_type error_tag); + void bfd_set_error (bfd_error_type error_tag, ...); DESCRIPTION Set the BFD error condition to be @var{error_tag}. + If @var{error_tag} is bfd_error_on_input, then this function + takes two more parameters, the input bfd where the error + occurred, and the bfd_error_type error. */ void -bfd_set_error (bfd_error_type error_tag) +bfd_set_error (bfd_error_type error_tag, ...) { bfd_error = error_tag; + if (error_tag == bfd_error_on_input) + { + /* This is an error that occurred during bfd_close when + writing an archive, but on one of the input files. */ + va_list ap; + + va_start (ap, error_tag); + input_bfd = va_arg (ap, bfd *); + input_error = va_arg (ap, int); + if (input_error >= bfd_error_on_input) + abort (); + va_end (ap); + } } /* @@ -355,6 +376,19 @@ bfd_errmsg (bfd_error_type error_tag) #ifndef errno extern int errno; #endif + if (error_tag == bfd_error_on_input) + { + char *buf; + const char *msg = bfd_errmsg (input_error); + + if (asprintf (&buf, _(bfd_errmsgs [error_tag]), input_bfd->filename, msg) + != -1) + return buf; + + /* Ick, what to do on out of memory? */ + return msg; + } + if (error_tag == bfd_error_system_call) return xstrerror (errno); @@ -382,16 +416,10 @@ DESCRIPTION void bfd_perror (const char *message) { - if (bfd_get_error () == bfd_error_system_call) - /* Must be a system error then. */ - perror ((char *) message); + if (message == NULL || *message == '\0') + fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ())); else - { - if (message == NULL || *message == '\0') - fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ())); - else - fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ())); - } + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ())); } /* @@ -419,6 +447,23 @@ static const char *_bfd_error_program_name; %A section name from section. For group components, print group name too. %B file name from bfd. For archive components, prints archive too. + + Note - because these two extra format specifiers require special handling + they are scanned for and processed in this function, before calling + vfprintf. This means that the *arguments* for these format specifiers + must be the first ones in the variable argument list, regardless of where + the specifiers appear in the format string. Thus for example calling + this function with a format string of: + + "blah %s blah %A blah %d blah %B" + + would involve passing the arguments as: + + "blah %s blah %A blah %d blah %B", + asection_for_the_%A, + bfd_for_the_%B, + string_for_the_%s, + integer_for_the_%d); */ void @@ -483,7 +528,11 @@ _bfd_default_error_handler (const char *fmt, ...) if (p[1] == 'B') { bfd *abfd = va_arg (ap, bfd *); - if (abfd->my_archive) + + if (abfd == NULL) + /* Invoking %B with a null bfd pointer is an internal error. */ + abort (); + else if (abfd->my_archive) snprintf (bufp, avail, "%s(%s)", abfd->my_archive->filename, abfd->filename); else @@ -492,10 +541,14 @@ _bfd_default_error_handler (const char *fmt, ...) else { asection *sec = va_arg (ap, asection *); - bfd *abfd = sec->owner; + bfd *abfd; const char *group = NULL; struct coff_comdat_info *ci; + if (sec == NULL) + /* Invoking %A with a null section pointer is an internal error. */ + abort (); + abfd = sec->owner; if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour && elf_next_in_group (sec) != NULL @@ -851,14 +904,16 @@ bfd_get_sign_extend_vma (bfd *abfd) name = bfd_get_target (abfd); - /* Return a proper value for DJGPP & PE COFF (x86 COFF variants). + /* Return a proper value for DJGPP & PE COFF. This function is required for DWARF2 support, but there is no place to store this information in the COFF back end. Should enough other COFF targets add support for DWARF2, a place will have to be found. Until then, this hack will do. */ - if (strncmp (name, "coff-go32", sizeof ("coff-go32") - 1) == 0 + if (CONST_STRNEQ (name, "coff-go32") || strcmp (name, "pe-i386") == 0 - || strcmp (name, "pei-i386") == 0) + || strcmp (name, "pei-i386") == 0 + || strcmp (name, "pe-arm-wince-little") == 0 + || strcmp (name, "pei-arm-wince-little") == 0) return 1; bfd_set_error (bfd_error_wrong_format); @@ -1158,8 +1213,8 @@ FUNCTION DESCRIPTION The following functions exist but have not yet been documented. -.#define bfd_sizeof_headers(abfd, reloc) \ -. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) +.#define bfd_sizeof_headers(abfd, info) \ +. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, info)) . .#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ . BFD_SEND (abfd, _bfd_find_nearest_line, \ @@ -1298,11 +1353,10 @@ bfd_record_phdr (bfd *abfd, amt = sizeof (struct elf_segment_map); amt += ((bfd_size_type) count - 1) * sizeof (asection *); - m = bfd_alloc (abfd, amt); + m = bfd_zalloc (abfd, amt); if (m == NULL) return FALSE; - m->next = NULL; m->p_type = type; m->p_flags = flags; m->p_paddr = at; @@ -1335,6 +1389,15 @@ bfd_fprintf_vma (bfd *abfd, void *stream, bfd_vma value) { if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) get_elf_backend_data (abfd)->elf_backend_fprintf_vma (abfd, stream, value); +#ifdef BFD64 + /* fprintf_vma() on a 64-bit enabled host will always print a 64-bit + value, but really we want to display the address in the target's + address size. Since we do not have a field in the bfd structure + to tell us this, we take a guess, based on the target's name. */ + else if (strstr (bfd_get_target (abfd), "64") == NULL + && strcmp (bfd_get_target (abfd), "mmo") != 0) + fprintf ((FILE *) stream, "%08lx", (unsigned long) (value & 0xffffffff)); +#endif else fprintf_vma ((FILE *) stream, value); } @@ -1513,3 +1576,212 @@ bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve) objalloc. */ bfd_hash_table_free (&preserve->section_htab); } + +/* +FUNCTION + bfd_emul_get_maxpagesize + +SYNOPSIS + bfd_vma bfd_emul_get_maxpagesize (const char *); + +DESCRIPTION + Returns the maximum page size, in bytes, as determined by + emulation. + +RETURNS + Returns the maximum page size in bytes for ELF, abort + otherwise. +*/ + +bfd_vma +bfd_emul_get_maxpagesize (const char *emul) +{ + const bfd_target *target; + + target = bfd_find_target (emul, NULL); + if (target != NULL + && target->flavour == bfd_target_elf_flavour) + return xvec_get_elf_backend_data (target)->maxpagesize; + + abort (); + return 0; +} + +static void +bfd_elf_set_pagesize (const bfd_target *target, bfd_vma size, + int offset, const bfd_target *orig_target) +{ + if (target->flavour == bfd_target_elf_flavour) + { + const struct elf_backend_data *bed; + + bed = xvec_get_elf_backend_data (target); + *((bfd_vma *) ((char *) bed + offset)) = size; + } + + if (target->alternative_target + && target->alternative_target != orig_target) + bfd_elf_set_pagesize (target->alternative_target, size, offset, + orig_target); +} + +/* +FUNCTION + bfd_emul_set_maxpagesize + +SYNOPSIS + void bfd_emul_set_maxpagesize (const char *, bfd_vma); + +DESCRIPTION + For ELF, set the maximum page size for the emulation. It is + a no-op for other formats. + +*/ + +void +bfd_emul_set_maxpagesize (const char *emul, bfd_vma size) +{ + const bfd_target *target; + + target = bfd_find_target (emul, NULL); + if (target) + bfd_elf_set_pagesize (target, size, + offsetof (struct elf_backend_data, + maxpagesize), target); +} + +/* +FUNCTION + bfd_emul_get_commonpagesize + +SYNOPSIS + bfd_vma bfd_emul_get_commonpagesize (const char *); + +DESCRIPTION + Returns the common page size, in bytes, as determined by + emulation. + +RETURNS + Returns the common page size in bytes for ELF, abort otherwise. +*/ + +bfd_vma +bfd_emul_get_commonpagesize (const char *emul) +{ + const bfd_target *target; + + target = bfd_find_target (emul, NULL); + if (target != NULL + && target->flavour == bfd_target_elf_flavour) + return xvec_get_elf_backend_data (target)->commonpagesize; + + abort (); + return 0; +} + +/* +FUNCTION + bfd_emul_set_commonpagesize + +SYNOPSIS + void bfd_emul_set_commonpagesize (const char *, bfd_vma); + +DESCRIPTION + For ELF, set the common page size for the emulation. It is + a no-op for other formats. + +*/ + +void +bfd_emul_set_commonpagesize (const char *emul, bfd_vma size) +{ + const bfd_target *target; + + target = bfd_find_target (emul, NULL); + if (target) + bfd_elf_set_pagesize (target, size, + offsetof (struct elf_backend_data, + commonpagesize), target); +} + +/* +FUNCTION + bfd_demangle + +SYNOPSIS + char *bfd_demangle (bfd *, const char *, int); + +DESCRIPTION + Wrapper around cplus_demangle. Strips leading underscores and + other such chars that would otherwise confuse the demangler. + If passed a g++ v3 ABI mangled name, returns a buffer allocated + with malloc holding the demangled name. Returns NULL otherwise + and on memory alloc failure. +*/ + +char * +bfd_demangle (bfd *abfd, const char *name, int options) +{ + char *res, *alloc; + const char *pre, *suf; + size_t pre_len; + + if (abfd != NULL + && *name != '\0' + && bfd_get_symbol_leading_char (abfd) == *name) + ++name; + + /* This is a hack for better error reporting on XCOFF, PowerPC64-ELF + or the MS PE format. These formats have a number of leading '.'s + on at least some symbols, so we remove all dots to avoid + confusing the demangler. */ + pre = name; + while (*name == '.' || *name == '$') + ++name; + pre_len = name - pre; + + /* Strip off @plt and suchlike too. */ + alloc = NULL; + suf = strchr (name, '@'); + if (suf != NULL) + { + alloc = bfd_malloc (suf - name + 1); + if (alloc == NULL) + return NULL; + memcpy (alloc, name, suf - name); + alloc[suf - name] = '\0'; + name = alloc; + } + + res = cplus_demangle (name, options); + + if (alloc != NULL) + free (alloc); + + if (res == NULL) + return NULL; + + /* Put back any prefix or suffix. */ + if (pre_len != 0 || suf != NULL) + { + size_t len; + size_t suf_len; + char *final; + + len = strlen (res); + if (suf == NULL) + suf = res + len; + suf_len = strlen (suf) + 1; + final = bfd_malloc (pre_len + len + suf_len); + if (final != NULL) + { + memcpy (final, pre, pre_len); + memcpy (final + pre_len, res, len); + memcpy (final + pre_len + len, suf, suf_len); + } + free (res); + res = final; + } + + return res; +} |