aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/bfd.c142
-rw-r--r--bfd/format.c71
-rw-r--r--bfd/libbfd.h33
-rw-r--r--bfd/targets.c58
4 files changed, 183 insertions, 121 deletions
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 8fd86f6..ace2f67 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1565,10 +1565,91 @@ err_sprintf (void *stream, const char *fmt, ...)
return total;
}
-/* Communicate the bfd processed by bfd_check_format_matches to the
- error handling function error_handler_sprintf. */
+/*
+INTERNAL
+.{* Cached _bfd_check_format messages are put in this. *}
+.struct per_xvec_message
+.{
+. struct per_xvec_message *next;
+. char message[];
+.};
+.
+.{* A list of per_xvec_message objects. The targ field indicates
+. which xvec this list holds; PER_XVEC_NO_TARGET is only set for the
+. root of the list and indicates that the entry isn't yet used. The
+. abfd field is only needed in the root entry of the list. *}
+.struct per_xvec_messages
+.{
+. bfd *abfd;
+. const bfd_target *targ;
+. struct per_xvec_message *messages;
+. struct per_xvec_messages *next;
+.};
+.
+.#define PER_XVEC_NO_TARGET ((const bfd_target *) -1)
+*/
+
+/* Helper function to find or allocate the correct per-xvec object
+ when emitting a message. */
+
+static struct per_xvec_message *
+_bfd_per_xvec_warn (struct per_xvec_messages *messages, size_t alloc)
+{
+ const bfd_target *targ = messages->abfd->xvec;
+
+ struct per_xvec_messages *prev = NULL;
+ struct per_xvec_messages *iter = messages;
+
+ if (iter->targ == PER_XVEC_NO_TARGET)
+ iter->targ = targ;
+ else
+ for (; iter != NULL; iter = iter->next)
+ {
+ if (iter->targ == targ)
+ break;
+ prev = iter;
+ }
+
+ if (iter == NULL)
+ {
+ iter = bfd_malloc (sizeof (*iter));
+ if (iter == NULL)
+ return NULL;
+ iter->abfd = messages->abfd;
+ iter->targ = targ;
+ iter->messages = NULL;
+ iter->next = NULL;
+ prev->next = iter;
+ }
+
+ struct per_xvec_message **m = &iter->messages;
+ int count = 0;
+ while (*m)
+ {
+ m = &(*m)->next;
+ count++;
+ }
+ /* Anti-fuzzer measure. Don't cache more than 5 messages. */
+ if (count < 5)
+ {
+ *m = bfd_malloc (sizeof (**m) + alloc);
+ if (*m != NULL)
+ (*m)->next = NULL;
+ }
+ return *m;
+}
-static bfd *error_handler_bfd;
+/* Communicate the error-message container processed by
+ bfd_check_format_matches to the error handling function
+ error_handler_sprintf. When non-NULL, _bfd_error_handler will call
+ error_handler_sprintf; when NULL, _bfd_error_internal will be used
+ instead. */
+
+static TLS struct per_xvec_messages *error_handler_messages;
+
+/* A special value for error_handler_messages that indicates that the
+ error should simply be ignored. */
+#define IGNORE_ERROR_MESSAGES ((struct per_xvec_messages *) -1)
/* An error handler that prints to a string, then dups that string to
a per-xvec cache. */
@@ -1585,12 +1666,12 @@ error_handler_sprintf (const char *fmt, va_list ap)
_bfd_print (err_sprintf, &error_stream, fmt, ap);
size_t len = error_stream.ptr - error_buf;
- struct per_xvec_message **warn
- = _bfd_per_xvec_warn (error_handler_bfd->xvec, len + 1);
- if (*warn)
+ struct per_xvec_message *warn
+ = _bfd_per_xvec_warn (error_handler_messages, len + 1);
+ if (warn)
{
- memcpy ((*warn)->message, error_buf, len);
- (*warn)->message[len] = 0;
+ memcpy (warn->message, error_buf, len);
+ warn->message[len] = 0;
}
}
@@ -1628,7 +1709,14 @@ _bfd_error_handler (const char *fmt, ...)
va_list ap;
va_start (ap, fmt);
- _bfd_error_internal (fmt, ap);
+ if (error_handler_messages == IGNORE_ERROR_MESSAGES)
+ {
+ /* Nothing. */
+ }
+ else if (error_handler_messages != NULL)
+ error_handler_sprintf (fmt, ap);
+ else
+ _bfd_error_internal (fmt, ap);
va_end (ap);
}
@@ -1659,18 +1747,42 @@ INTERNAL_FUNCTION
_bfd_set_error_handler_caching
SYNOPSIS
- bfd_error_handler_type _bfd_set_error_handler_caching (bfd *);
+ struct per_xvec_messages *_bfd_set_error_handler_caching (struct per_xvec_messages *);
DESCRIPTION
Set the BFD error handler function to one that stores messages
- to the per_xvec_warn array. Returns the previous function.
+ to the per_xvec_messages object. Returns the previous object
+ to which messages are stored. Note that two sequential calls
+ to this with a non-NULL argument will cause output to be
+ dropped, rather than gathered.
*/
-bfd_error_handler_type
-_bfd_set_error_handler_caching (bfd *abfd)
+struct per_xvec_messages *
+_bfd_set_error_handler_caching (struct per_xvec_messages *messages)
+{
+ struct per_xvec_messages *old = error_handler_messages;
+ if (old == NULL)
+ error_handler_messages = messages;
+ else
+ error_handler_messages = IGNORE_ERROR_MESSAGES;
+ return old;
+}
+
+/*
+INTERNAL_FUNCTION
+ _bfd_restore_error_handler_caching
+
+SYNOPSIS
+ void _bfd_restore_error_handler_caching (struct per_xvec_messages *);
+
+DESCRIPTION
+ Reset the BFD error handler object to an earlier value.
+*/
+
+void
+_bfd_restore_error_handler_caching (struct per_xvec_messages *old)
{
- error_handler_bfd = abfd;
- return bfd_set_error_handler (error_handler_sprintf);
+ error_handler_messages = old;
}
/*
diff --git a/bfd/format.c b/bfd/format.c
index 6d95683..2a700ba 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -272,10 +272,34 @@ clear_warnmsg (struct per_xvec_message **list)
*list = NULL;
}
+/* Free all the storage in LIST. Note that the first element of LIST
+ is special and is assumed to be stack-allocated. TARG is used for
+ re-issuing warning messages. If TARG is PER_XVEC_NO_TARGET, then
+ it acts like a sort of wildcard -- messages are only reissued if
+ they are all associated with a single BFD target, regardless of
+ which one it is. If TARG is anything else, then only messages
+ associated with TARG are emitted. */
+
static void
-null_error_handler (const char *fmt ATTRIBUTE_UNUSED,
- va_list ap ATTRIBUTE_UNUSED)
+print_and_clear_messages (struct per_xvec_messages *list,
+ const bfd_target *targ)
{
+ struct per_xvec_messages *iter = list;
+
+ if (targ == PER_XVEC_NO_TARGET && list->next == NULL)
+ print_warnmsg (&list->messages);
+
+ while (iter != NULL)
+ {
+ struct per_xvec_messages *next = iter->next;
+
+ if (iter->targ == targ)
+ print_warnmsg (&iter->messages);
+ clear_warnmsg (&iter->messages);
+ if (iter != list)
+ free (iter);
+ iter = next;
+ }
}
/* This a copy of lto_section defined in GCC (lto-streamer.h). */
@@ -357,8 +381,8 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
unsigned int initial_section_id = _bfd_section_id;
struct bfd_preserve preserve, preserve_match;
bfd_cleanup cleanup = NULL;
- bfd_error_handler_type orig_error_handler;
- static int in_check_format;
+ struct per_xvec_messages messages = { abfd, PER_XVEC_NO_TARGET, NULL, NULL };
+ struct per_xvec_messages *orig_messages;
if (matching != NULL)
*matching = NULL;
@@ -392,11 +416,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
/* Don't report errors on recursive calls checking the first element
of an archive. */
- if (in_check_format)
- orig_error_handler = bfd_set_error_handler (null_error_handler);
- else
- orig_error_handler = _bfd_set_error_handler_caching (abfd);
- ++in_check_format;
+ orig_messages = _bfd_set_error_handler_caching (&messages);
preserve_match.marker = NULL;
if (!bfd_preserve_save (abfd, &preserve, NULL))
@@ -638,15 +658,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
if (preserve_match.marker != NULL)
bfd_preserve_finish (abfd, &preserve_match);
bfd_preserve_finish (abfd, &preserve);
- bfd_set_error_handler (orig_error_handler);
+ _bfd_restore_error_handler_caching (orig_messages);
- struct per_xvec_message **list = _bfd_per_xvec_warn (abfd->xvec, 0);
- if (*list)
- print_warnmsg (list);
- list = _bfd_per_xvec_warn (NULL, 0);
- for (size_t i = 0; i < _bfd_target_vector_entries + 1; i++)
- clear_warnmsg (list++);
- --in_check_format;
+ print_and_clear_messages (&messages, abfd->xvec);
bfd_set_lto_type (abfd);
@@ -692,27 +706,8 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
if (preserve_match.marker != NULL)
bfd_preserve_finish (abfd, &preserve_match);
bfd_preserve_restore (abfd, &preserve);
- bfd_set_error_handler (orig_error_handler);
- struct per_xvec_message **list = _bfd_per_xvec_warn (NULL, 0);
- struct per_xvec_message **one = NULL;
- for (size_t i = 0; i < _bfd_target_vector_entries + 1; i++)
- {
- if (list[i])
- {
- if (!one)
- one = list + i;
- else
- {
- one = NULL;
- break;
- }
- }
- }
- if (one)
- print_warnmsg (one);
- for (size_t i = 0; i < _bfd_target_vector_entries + 1; i++)
- clear_warnmsg (list++);
- --in_check_format;
+ _bfd_restore_error_handler_caching (orig_messages);
+ print_and_clear_messages (&messages, PER_XVEC_NO_TARGET);
return false;
}
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 5f5ad2d..d106262 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -963,7 +963,29 @@ void _bfd_clear_error_data (void) ATTRIBUTE_HIDDEN;
char *bfd_asprintf (const char *fmt, ...) ATTRIBUTE_HIDDEN;
-bfd_error_handler_type _bfd_set_error_handler_caching (bfd *) ATTRIBUTE_HIDDEN;
+/* Cached _bfd_check_format messages are put in this. */
+struct per_xvec_message
+{
+ struct per_xvec_message *next;
+ char message[];
+};
+
+/* A list of per_xvec_message objects. The targ field indicates
+ which xvec this list holds; PER_XVEC_NO_TARGET is only set for the
+ root of the list and indicates that the entry isn't yet used. The
+ abfd field is only needed in the root entry of the list. */
+struct per_xvec_messages
+{
+ bfd *abfd;
+ const bfd_target *targ;
+ struct per_xvec_message *messages;
+ struct per_xvec_messages *next;
+};
+
+#define PER_XVEC_NO_TARGET ((const bfd_target *) -1)
+struct per_xvec_messages *_bfd_set_error_handler_caching (struct per_xvec_messages *) ATTRIBUTE_HIDDEN;
+
+void _bfd_restore_error_handler_caching (struct per_xvec_messages *) ATTRIBUTE_HIDDEN;
const char *_bfd_get_error_program_name (void) ATTRIBUTE_HIDDEN;
@@ -3708,15 +3730,6 @@ bool _bfd_write_stab_strings (bfd *, struct stab_info *) ATTRIBUTE_HIDDEN;
bfd_vma _bfd_stab_section_offset (asection *, void *, bfd_vma) ATTRIBUTE_HIDDEN;
/* Extracted from targets.c. */
-/* Cached _bfd_check_format messages are put in this. */
-struct per_xvec_message
-{
- struct per_xvec_message *next;
- char message[];
-};
-
-struct per_xvec_message **_bfd_per_xvec_warn (const bfd_target *, size_t) ATTRIBUTE_HIDDEN;
-
#ifdef __cplusplus
}
#endif
diff --git a/bfd/targets.c b/bfd/targets.c
index 532b646..0d5d73b 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -1454,9 +1454,6 @@ const bfd_target *const *const bfd_associated_vector = _bfd_associated_vector;
number of entries that the array could possibly need. */
const size_t _bfd_target_vector_entries = ARRAY_SIZE (_bfd_target_vector);
-/* A place to stash a warning from _bfd_check_format. */
-static struct per_xvec_message *per_xvec_warn[ARRAY_SIZE (_bfd_target_vector)
- + 1];
/* This array maps configuration triplets onto BFD vectors. */
@@ -1476,61 +1473,6 @@ static const struct targmatch bfd_target_match[] = {
{ NULL, NULL }
};
-/*
-INTERNAL
-.{* Cached _bfd_check_format messages are put in this. *}
-.struct per_xvec_message
-.{
-. struct per_xvec_message *next;
-. char message[];
-.};
-.
-INTERNAL_FUNCTION
- _bfd_per_xvec_warn
-
-SYNOPSIS
- struct per_xvec_message **_bfd_per_xvec_warn (const bfd_target *, size_t);
-
-DESCRIPTION
- Return a location for the given target xvec to use for
- warnings specific to that target. If TARG is NULL, returns
- the array of per_xvec_message pointers, otherwise if ALLOC is
- zero, returns a pointer to a pointer to the list of messages
- for TARG, otherwise (both TARG and ALLOC non-zero), allocates
- a new per_xvec_message with space for a string of ALLOC
- bytes and returns a pointer to a pointer to it. May return a
- pointer to a NULL pointer on allocation failure.
-*/
-
-struct per_xvec_message **
-_bfd_per_xvec_warn (const bfd_target *targ, size_t alloc)
-{
- size_t idx;
-
- if (!targ)
- return per_xvec_warn;
- for (idx = 0; idx < ARRAY_SIZE (_bfd_target_vector); idx++)
- if (_bfd_target_vector[idx] == targ)
- break;
- struct per_xvec_message **m = per_xvec_warn + idx;
- if (!alloc)
- return m;
- int count = 0;
- while (*m)
- {
- m = &(*m)->next;
- count++;
- }
- /* Anti-fuzzer measure. Don't cache more than 5 messages. */
- if (count < 5)
- {
- *m = bfd_malloc (sizeof (**m) + alloc);
- if (*m != NULL)
- (*m)->next = NULL;
- }
- return m;
-}
-
/* Find a target vector, given a name or configuration triplet. */
static const bfd_target *