summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/bfd/bfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/bfd/bfd.c')
-rw-r--r--contrib/binutils/bfd/bfd.c320
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;
+}
OpenPOWER on IntegriCloud