12159047fSniklas /* ldmisc.c
2c074d1c9Sdrahn Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3c074d1c9Sdrahn 2000, 2002, 2003
4b305b0f1Sespie Free Software Foundation, Inc.
52159047fSniklas Written by Steve Chamberlain of Cygnus Support.
62159047fSniklas
72159047fSniklas This file is part of GLD, the Gnu Linker.
82159047fSniklas
92159047fSniklas GLD is free software; you can redistribute it and/or modify
102159047fSniklas it under the terms of the GNU General Public License as published by
112159047fSniklas the Free Software Foundation; either version 2, or (at your option)
122159047fSniklas any later version.
132159047fSniklas
142159047fSniklas GLD is distributed in the hope that it will be useful,
152159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
162159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
172159047fSniklas GNU General Public License for more details.
182159047fSniklas
192159047fSniklas You should have received a copy of the GNU General Public License
20b305b0f1Sespie along with GLD; see the file COPYING. If not, write to the Free
21b305b0f1Sespie Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22b305b0f1Sespie 02111-1307, USA. */
232159047fSniklas
242159047fSniklas #include "bfd.h"
25007c2a45Smiod #include "bfdlink.h"
262159047fSniklas #include "sysdep.h"
27191aa565Sniklas #include "libiberty.h"
28191aa565Sniklas #include "demangle.h"
29191aa565Sniklas #include <stdarg.h>
302159047fSniklas #include "ld.h"
312159047fSniklas #include "ldmisc.h"
322159047fSniklas #include "ldexp.h"
332159047fSniklas #include "ldlang.h"
34c074d1c9Sdrahn #include <ldgram.h>
352159047fSniklas #include "ldlex.h"
362159047fSniklas #include "ldmain.h"
372159047fSniklas #include "ldfile.h"
382159047fSniklas
392159047fSniklas /*
402159047fSniklas %% literal %
412159047fSniklas %F error is fatal
422159047fSniklas %P print program name
432159047fSniklas %S print script file and linenumber
442159047fSniklas %E current bfd error or errno
452159047fSniklas %I filename from a lang_input_statement_type
462159047fSniklas %B filename from a bfd
472159047fSniklas %T symbol name
482159047fSniklas %X no object output, fail return
492159047fSniklas %V hex bfd_vma
502159047fSniklas %v hex bfd_vma, no leading zeros
51191aa565Sniklas %W hex bfd_vma with 0x with no leading zeros taking up 8 spaces
522159047fSniklas %C clever filename:linenumber with function
532159047fSniklas %D like %C, but no function name
54191aa565Sniklas %G like %D, but only function name
552159047fSniklas %R info about a relent
562159047fSniklas %s arbitrary string, like printf
572159047fSniklas %d integer, like printf
582159047fSniklas %u integer, like printf
592159047fSniklas */
602159047fSniklas
612159047fSniklas static void
vfinfo(FILE * fp,const char * fmt,va_list arg)62007c2a45Smiod vfinfo (FILE *fp, const char *fmt, va_list arg)
632159047fSniklas {
64c074d1c9Sdrahn bfd_boolean fatal = FALSE;
652159047fSniklas
66191aa565Sniklas while (*fmt != '\0')
672159047fSniklas {
682159047fSniklas while (*fmt != '%' && *fmt != '\0')
692159047fSniklas {
702159047fSniklas putc (*fmt, fp);
712159047fSniklas fmt++;
722159047fSniklas }
732159047fSniklas
742159047fSniklas if (*fmt == '%')
752159047fSniklas {
762159047fSniklas fmt++;
772159047fSniklas switch (*fmt++)
782159047fSniklas {
792159047fSniklas default:
802159047fSniklas fprintf (fp, "%%%c", fmt[-1]);
812159047fSniklas break;
822159047fSniklas
832159047fSniklas case '%':
842159047fSniklas /* literal % */
852159047fSniklas putc ('%', fp);
862159047fSniklas break;
872159047fSniklas
882159047fSniklas case 'X':
892159047fSniklas /* no object output, fail return */
90c074d1c9Sdrahn config.make_executable = FALSE;
912159047fSniklas break;
922159047fSniklas
932159047fSniklas case 'V':
942159047fSniklas /* hex bfd_vma */
952159047fSniklas {
962159047fSniklas bfd_vma value = va_arg (arg, bfd_vma);
972159047fSniklas fprintf_vma (fp, value);
982159047fSniklas }
992159047fSniklas break;
1002159047fSniklas
1012159047fSniklas case 'v':
1022159047fSniklas /* hex bfd_vma, no leading zeros */
1032159047fSniklas {
1042159047fSniklas char buf[100];
1052159047fSniklas char *p = buf;
1062159047fSniklas bfd_vma value = va_arg (arg, bfd_vma);
1072159047fSniklas sprintf_vma (p, value);
1082159047fSniklas while (*p == '0')
1092159047fSniklas p++;
1102159047fSniklas if (!*p)
1112159047fSniklas p--;
1122159047fSniklas fputs (p, fp);
1132159047fSniklas }
1142159047fSniklas break;
1152159047fSniklas
116191aa565Sniklas case 'W':
117191aa565Sniklas /* hex bfd_vma with 0x with no leading zeroes taking up
118191aa565Sniklas 8 spaces. */
119191aa565Sniklas {
120191aa565Sniklas char buf[100];
121191aa565Sniklas bfd_vma value;
122191aa565Sniklas char *p;
123191aa565Sniklas int len;
124191aa565Sniklas
125191aa565Sniklas value = va_arg (arg, bfd_vma);
126191aa565Sniklas sprintf_vma (buf, value);
127191aa565Sniklas for (p = buf; *p == '0'; ++p)
128191aa565Sniklas ;
1290c6d0228Sniklas if (*p == '\0')
1300c6d0228Sniklas --p;
131191aa565Sniklas len = strlen (p);
132191aa565Sniklas while (len < 8)
133191aa565Sniklas {
134191aa565Sniklas putc (' ', fp);
135191aa565Sniklas ++len;
136191aa565Sniklas }
137191aa565Sniklas fprintf (fp, "0x%s", p);
138191aa565Sniklas }
139191aa565Sniklas break;
140191aa565Sniklas
1412159047fSniklas case 'T':
1422159047fSniklas /* Symbol name. */
1432159047fSniklas {
1442159047fSniklas const char *name = va_arg (arg, const char *);
1452159047fSniklas
146007c2a45Smiod if (name == NULL || *name == 0)
147b305b0f1Sespie fprintf (fp, _("no symbol"));
148b305b0f1Sespie else if (! demangling)
149b305b0f1Sespie fprintf (fp, "%s", name);
150191aa565Sniklas else
151191aa565Sniklas {
152191aa565Sniklas char *demangled;
153191aa565Sniklas
154191aa565Sniklas demangled = demangle (name);
155191aa565Sniklas fprintf (fp, "%s", demangled);
156191aa565Sniklas free (demangled);
157191aa565Sniklas }
1582159047fSniklas }
1592159047fSniklas break;
1602159047fSniklas
1612159047fSniklas case 'B':
1622159047fSniklas /* filename from a bfd */
1632159047fSniklas {
1642159047fSniklas bfd *abfd = va_arg (arg, bfd *);
165191aa565Sniklas if (abfd->my_archive)
1662159047fSniklas fprintf (fp, "%s(%s)", abfd->my_archive->filename,
1672159047fSniklas abfd->filename);
168191aa565Sniklas else
1692159047fSniklas fprintf (fp, "%s", abfd->filename);
1702159047fSniklas }
1712159047fSniklas break;
1722159047fSniklas
1732159047fSniklas case 'F':
174b55d4692Sfgsch /* Error is fatal. */
175c074d1c9Sdrahn fatal = TRUE;
1762159047fSniklas break;
1772159047fSniklas
1782159047fSniklas case 'P':
179b55d4692Sfgsch /* Print program name. */
1802159047fSniklas fprintf (fp, "%s", program_name);
1812159047fSniklas break;
1822159047fSniklas
1832159047fSniklas case 'E':
1842159047fSniklas /* current bfd error or errno */
185b305b0f1Sespie fprintf (fp, "%s", bfd_errmsg (bfd_get_error ()));
1862159047fSniklas break;
1872159047fSniklas
1882159047fSniklas case 'I':
1892159047fSniklas /* filename from a lang_input_statement_type */
1902159047fSniklas {
191191aa565Sniklas lang_input_statement_type *i;
1922159047fSniklas
193191aa565Sniklas i = va_arg (arg, lang_input_statement_type *);
194191aa565Sniklas if (bfd_my_archive (i->the_bfd) != NULL)
195191aa565Sniklas fprintf (fp, "(%s)",
196191aa565Sniklas bfd_get_filename (bfd_my_archive (i->the_bfd)));
1972159047fSniklas fprintf (fp, "%s", i->local_sym_name);
198191aa565Sniklas if (bfd_my_archive (i->the_bfd) == NULL
199191aa565Sniklas && strcmp (i->local_sym_name, i->filename) != 0)
200191aa565Sniklas fprintf (fp, " (%s)", i->filename);
2012159047fSniklas }
2022159047fSniklas break;
2032159047fSniklas
2042159047fSniklas case 'S':
205b55d4692Sfgsch /* Print script file and linenumber. */
2062159047fSniklas if (parsing_defsym)
2072159047fSniklas fprintf (fp, "--defsym %s", lex_string);
2082159047fSniklas else if (ldfile_input_filename != NULL)
2092159047fSniklas fprintf (fp, "%s:%u", ldfile_input_filename, lineno);
2102159047fSniklas else
211b305b0f1Sespie fprintf (fp, _("built in linker script:%u"), lineno);
2122159047fSniklas break;
2132159047fSniklas
2142159047fSniklas case 'R':
215b55d4692Sfgsch /* Print all that's interesting about a relent. */
2162159047fSniklas {
2172159047fSniklas arelent *relent = va_arg (arg, arelent *);
2182159047fSniklas
219b305b0f1Sespie lfinfo (fp, "%s+0x%v (type %s)",
2202159047fSniklas (*(relent->sym_ptr_ptr))->name,
2212159047fSniklas relent->addend,
2222159047fSniklas relent->howto->name);
2232159047fSniklas }
2242159047fSniklas break;
2252159047fSniklas
2262159047fSniklas case 'C':
2272159047fSniklas case 'D':
228191aa565Sniklas case 'G':
229c074d1c9Sdrahn /* Clever filename:linenumber with function name if possible.
230c074d1c9Sdrahn The arguments are a BFD, a section, and an offset. */
2312159047fSniklas {
2322159047fSniklas static bfd *last_bfd;
2332159047fSniklas static char *last_file = NULL;
2342159047fSniklas static char *last_function = NULL;
2352159047fSniklas bfd *abfd;
2362159047fSniklas asection *section;
2372159047fSniklas bfd_vma offset;
2382159047fSniklas lang_input_statement_type *entry;
2392159047fSniklas asymbol **asymbols;
2402159047fSniklas const char *filename;
2412159047fSniklas const char *functionname;
2422159047fSniklas unsigned int linenumber;
243c074d1c9Sdrahn bfd_boolean discard_last;
2442159047fSniklas
2452159047fSniklas abfd = va_arg (arg, bfd *);
2462159047fSniklas section = va_arg (arg, asection *);
2472159047fSniklas offset = va_arg (arg, bfd_vma);
2482159047fSniklas
2492159047fSniklas entry = (lang_input_statement_type *) abfd->usrdata;
2502159047fSniklas if (entry != (lang_input_statement_type *) NULL
2512159047fSniklas && entry->asymbols != (asymbol **) NULL)
2522159047fSniklas asymbols = entry->asymbols;
2532159047fSniklas else
2542159047fSniklas {
2552159047fSniklas long symsize;
2562159047fSniklas long symbol_count;
2572159047fSniklas
2582159047fSniklas symsize = bfd_get_symtab_upper_bound (abfd);
2592159047fSniklas if (symsize < 0)
260b305b0f1Sespie einfo (_("%B%F: could not read symbols\n"), abfd);
261007c2a45Smiod asymbols = xmalloc (symsize);
2622159047fSniklas symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
2632159047fSniklas if (symbol_count < 0)
264b305b0f1Sespie einfo (_("%B%F: could not read symbols\n"), abfd);
2652159047fSniklas if (entry != (lang_input_statement_type *) NULL)
2662159047fSniklas {
2672159047fSniklas entry->asymbols = asymbols;
2682159047fSniklas entry->symbol_count = symbol_count;
2692159047fSniklas }
2702159047fSniklas }
2712159047fSniklas
272c074d1c9Sdrahn lfinfo (fp, "%B(%s+0x%v)", abfd, section->name, offset);
273c074d1c9Sdrahn
274c074d1c9Sdrahn discard_last = TRUE;
2752159047fSniklas if (bfd_find_nearest_line (abfd, section, asymbols, offset,
276191aa565Sniklas &filename, &functionname,
277191aa565Sniklas &linenumber))
2782159047fSniklas {
279c074d1c9Sdrahn bfd_boolean need_colon = TRUE;
2802159047fSniklas
281c074d1c9Sdrahn if (functionname != NULL && fmt[-1] == 'C')
282c074d1c9Sdrahn {
2832159047fSniklas if (last_bfd == NULL
2842159047fSniklas || last_file == NULL
2852159047fSniklas || last_function == NULL
2862159047fSniklas || last_bfd != abfd
287c074d1c9Sdrahn || (filename != NULL
288c074d1c9Sdrahn && strcmp (last_file, filename) != 0)
2892159047fSniklas || strcmp (last_function, functionname) != 0)
2902159047fSniklas {
291c074d1c9Sdrahn lfinfo (fp, _(": In function `%T':\n"),
292c074d1c9Sdrahn functionname);
293c074d1c9Sdrahn need_colon = FALSE;
2942159047fSniklas
2952159047fSniklas last_bfd = abfd;
2962159047fSniklas if (last_file != NULL)
2972159047fSniklas free (last_file);
298c074d1c9Sdrahn last_file = NULL;
299c074d1c9Sdrahn if (filename)
300b55d4692Sfgsch last_file = xstrdup (filename);
3012159047fSniklas if (last_function != NULL)
3022159047fSniklas free (last_function);
303b55d4692Sfgsch last_function = xstrdup (functionname);
3042159047fSniklas }
305c074d1c9Sdrahn discard_last = FALSE;
3062159047fSniklas }
307c074d1c9Sdrahn
308c074d1c9Sdrahn if (filename != NULL)
3092159047fSniklas {
310c074d1c9Sdrahn if (need_colon)
311c074d1c9Sdrahn putc (':', fp);
312c074d1c9Sdrahn fputs (filename, fp);
3132159047fSniklas }
314c074d1c9Sdrahn
315c074d1c9Sdrahn if (functionname != NULL && fmt[-1] == 'G')
316c074d1c9Sdrahn lfinfo (fp, ":%T", functionname);
317c074d1c9Sdrahn else if (filename != NULL && linenumber != 0)
318c074d1c9Sdrahn fprintf (fp, ":%u", linenumber);
3192159047fSniklas }
320c074d1c9Sdrahn
321c074d1c9Sdrahn if (asymbols != NULL && entry == NULL)
322c074d1c9Sdrahn free (asymbols);
3232159047fSniklas
3242159047fSniklas if (discard_last)
3252159047fSniklas {
3262159047fSniklas last_bfd = NULL;
3272159047fSniklas if (last_file != NULL)
3282159047fSniklas {
3292159047fSniklas free (last_file);
3302159047fSniklas last_file = NULL;
3312159047fSniklas }
3322159047fSniklas if (last_function != NULL)
3332159047fSniklas {
3342159047fSniklas free (last_function);
3352159047fSniklas last_function = NULL;
3362159047fSniklas }
3372159047fSniklas }
3382159047fSniklas }
3392159047fSniklas break;
3402159047fSniklas
3412159047fSniklas case 's':
3422159047fSniklas /* arbitrary string, like printf */
3432159047fSniklas fprintf (fp, "%s", va_arg (arg, char *));
3442159047fSniklas break;
3452159047fSniklas
3462159047fSniklas case 'd':
3472159047fSniklas /* integer, like printf */
3482159047fSniklas fprintf (fp, "%d", va_arg (arg, int));
3492159047fSniklas break;
3502159047fSniklas
3512159047fSniklas case 'u':
3522159047fSniklas /* unsigned integer, like printf */
3532159047fSniklas fprintf (fp, "%u", va_arg (arg, unsigned int));
3542159047fSniklas break;
3552159047fSniklas }
3562159047fSniklas }
3572159047fSniklas }
3582159047fSniklas
359c074d1c9Sdrahn if (config.fatal_warnings)
360c074d1c9Sdrahn config.make_executable = FALSE;
361c074d1c9Sdrahn
362c074d1c9Sdrahn if (fatal)
3632159047fSniklas xexit (1);
3642159047fSniklas }
3652159047fSniklas
366c074d1c9Sdrahn /* Wrapper around cplus_demangle. Strips leading underscores and
367c074d1c9Sdrahn other such chars that would otherwise confuse the demangler. */
368c074d1c9Sdrahn
369c074d1c9Sdrahn char *
demangle(const char * name)370007c2a45Smiod demangle (const char *name)
371c074d1c9Sdrahn {
372c074d1c9Sdrahn char *res;
373c074d1c9Sdrahn const char *p;
374c074d1c9Sdrahn
375c074d1c9Sdrahn if (output_bfd != NULL
376c074d1c9Sdrahn && bfd_get_symbol_leading_char (output_bfd) == name[0])
377c074d1c9Sdrahn ++name;
378c074d1c9Sdrahn
379c074d1c9Sdrahn /* This is a hack for better error reporting on XCOFF, PowerPC64-ELF
380c074d1c9Sdrahn or the MS PE format. These formats have a number of leading '.'s
381c074d1c9Sdrahn on at least some symbols, so we remove all dots to avoid
382c074d1c9Sdrahn confusing the demangler. */
383c074d1c9Sdrahn p = name;
384c074d1c9Sdrahn while (*p == '.')
385c074d1c9Sdrahn ++p;
386c074d1c9Sdrahn
387c074d1c9Sdrahn res = cplus_demangle (p, DMGL_ANSI | DMGL_PARAMS);
388c074d1c9Sdrahn if (res)
389c074d1c9Sdrahn {
390c074d1c9Sdrahn size_t dots = p - name;
391c074d1c9Sdrahn
392c074d1c9Sdrahn /* Now put back any stripped dots. */
393c074d1c9Sdrahn if (dots != 0)
394c074d1c9Sdrahn {
395c074d1c9Sdrahn size_t len = strlen (res) + 1;
396c074d1c9Sdrahn char *add_dots = xmalloc (len + dots);
397c074d1c9Sdrahn
398c074d1c9Sdrahn memcpy (add_dots, name, dots);
399c074d1c9Sdrahn memcpy (add_dots + dots, res, len);
400c074d1c9Sdrahn free (res);
401c074d1c9Sdrahn res = add_dots;
402c074d1c9Sdrahn }
403c074d1c9Sdrahn return res;
404c074d1c9Sdrahn }
405c074d1c9Sdrahn return xstrdup (name);
406c074d1c9Sdrahn }
407c074d1c9Sdrahn
4082159047fSniklas /* Format info message and print on stdout. */
4092159047fSniklas
410191aa565Sniklas /* (You would think this should be called just "info", but then you
411007c2a45Smiod would be hosed by LynxOS, which defines that name in its libc.) */
4122159047fSniklas
413191aa565Sniklas void
info_msg(const char * fmt,...)414007c2a45Smiod info_msg (const char *fmt, ...)
4152159047fSniklas {
416007c2a45Smiod va_list arg;
417191aa565Sniklas
418007c2a45Smiod va_start (arg, fmt);
4192159047fSniklas vfinfo (stdout, fmt, arg);
420007c2a45Smiod va_end (arg);
4212159047fSniklas }
4222159047fSniklas
4232159047fSniklas /* ('e' for error.) Format info message and print on stderr. */
4242159047fSniklas
425191aa565Sniklas void
einfo(const char * fmt,...)426007c2a45Smiod einfo (const char *fmt, ...)
4272159047fSniklas {
428007c2a45Smiod va_list arg;
429*49975d48Smillert char buf[BUFSIZ];
430191aa565Sniklas
431*49975d48Smillert setvbuf(stderr, buf, _IOFBF, sizeof(buf));
432007c2a45Smiod va_start (arg, fmt);
4332159047fSniklas vfinfo (stderr, fmt, arg);
434007c2a45Smiod va_end (arg);
435*49975d48Smillert fflush(stderr);
436*49975d48Smillert setvbuf(stderr, NULL, _IONBF, 0);
4372159047fSniklas }
4382159047fSniklas
4392159047fSniklas void
info_assert(const char * file,unsigned int line)440007c2a45Smiod info_assert (const char *file, unsigned int line)
4412159047fSniklas {
442b305b0f1Sespie einfo (_("%F%P: internal error %s %d\n"), file, line);
4432159047fSniklas }
4442159047fSniklas
4452159047fSniklas /* ('m' for map) Format info message and print on map. */
4462159047fSniklas
447191aa565Sniklas void
minfo(const char * fmt,...)448007c2a45Smiod minfo (const char *fmt, ...)
4492159047fSniklas {
450007c2a45Smiod va_list arg;
451191aa565Sniklas
452007c2a45Smiod va_start (arg, fmt);
4532159047fSniklas vfinfo (config.map_file, fmt, arg);
454007c2a45Smiod va_end (arg);
4552159047fSniklas }
4562159047fSniklas
457191aa565Sniklas void
lfinfo(FILE * file,const char * fmt,...)458007c2a45Smiod lfinfo (FILE *file, const char *fmt, ...)
4592159047fSniklas {
460007c2a45Smiod va_list arg;
461191aa565Sniklas
462007c2a45Smiod va_start (arg, fmt);
4632159047fSniklas vfinfo (file, fmt, arg);
464007c2a45Smiod va_end (arg);
4652159047fSniklas }
466191aa565Sniklas
467191aa565Sniklas /* Functions to print the link map. */
4682159047fSniklas
4692159047fSniklas void
print_space(void)470007c2a45Smiod print_space (void)
4712159047fSniklas {
4722159047fSniklas fprintf (config.map_file, " ");
4732159047fSniklas }
474191aa565Sniklas
4752159047fSniklas void
print_nl(void)476007c2a45Smiod print_nl (void)
4772159047fSniklas {
4782159047fSniklas fprintf (config.map_file, "\n");
4792159047fSniklas }
480b305b0f1Sespie
481b305b0f1Sespie /* A more or less friendly abort message. In ld.h abort is defined to
482b305b0f1Sespie call this function. */
483b305b0f1Sespie
484b305b0f1Sespie void
ld_abort(const char * file,int line,const char * fn)485007c2a45Smiod ld_abort (const char *file, int line, const char *fn)
486b305b0f1Sespie {
487b305b0f1Sespie if (fn != NULL)
488b305b0f1Sespie einfo (_("%P: internal error: aborting at %s line %d in %s\n"),
489b305b0f1Sespie file, line, fn);
490b305b0f1Sespie else
491b305b0f1Sespie einfo (_("%P: internal error: aborting at %s line %d\n"),
492b305b0f1Sespie file, line);
493b305b0f1Sespie einfo (_("%P%F: please report this bug\n"));
494b305b0f1Sespie xexit (1);
495b305b0f1Sespie }
496c074d1c9Sdrahn
497c074d1c9Sdrahn bfd_boolean
error_handler(int id,const char * fmt,...)498007c2a45Smiod error_handler (int id, const char *fmt, ...)
499c074d1c9Sdrahn {
500007c2a45Smiod va_list arg;
501c074d1c9Sdrahn
502007c2a45Smiod va_start (arg, fmt);
503007c2a45Smiod
504007c2a45Smiod switch (id)
505007c2a45Smiod {
506007c2a45Smiod default:
507007c2a45Smiod break;
508007c2a45Smiod
509007c2a45Smiod /* We can be called with
510007c2a45Smiod
511007c2a45Smiod error_handler (-LD_DEFINITION_IN_DISCARDED_SECTION, "", 0);
512007c2a45Smiod
513007c2a45Smiod to make this error non-fatal and
514007c2a45Smiod
515007c2a45Smiod error_handler (-LD_DEFINITION_IN_DISCARDED_SECTION, "", 1);
516007c2a45Smiod
517007c2a45Smiod to make this error fatal. */
518007c2a45Smiod case -LD_DEFINITION_IN_DISCARDED_SECTION:
519007c2a45Smiod case LD_DEFINITION_IN_DISCARDED_SECTION:
520007c2a45Smiod {
521007c2a45Smiod static struct bfd_hash_table *hash;
522007c2a45Smiod static int fatal = 1;
523007c2a45Smiod const char *name;
524007c2a45Smiod
525007c2a45Smiod if (id == -LD_DEFINITION_IN_DISCARDED_SECTION)
526007c2a45Smiod {
527007c2a45Smiod fatal = va_arg (arg, int);
528007c2a45Smiod goto out;
529007c2a45Smiod }
530007c2a45Smiod
531007c2a45Smiod name = va_arg (arg, const char *);
532007c2a45Smiod /* Only warn once about a particular undefined symbol. */
533007c2a45Smiod if (hash == NULL)
534007c2a45Smiod {
535007c2a45Smiod hash = xmalloc (sizeof (struct bfd_hash_table));
536007c2a45Smiod if (! bfd_hash_table_init (hash, bfd_hash_newfunc))
537007c2a45Smiod einfo (_("%F%P: bfd_hash_table_init failed: %E\n"));
538007c2a45Smiod }
539007c2a45Smiod
540007c2a45Smiod if (bfd_hash_lookup (hash, name, FALSE, FALSE) != NULL)
541007c2a45Smiod goto out;
542007c2a45Smiod
543007c2a45Smiod if (bfd_hash_lookup (hash, name, TRUE, TRUE) == NULL)
544007c2a45Smiod einfo (_("%F%P: bfd_hash_lookup failed: %E\n"));
545007c2a45Smiod
546007c2a45Smiod if (fatal)
547007c2a45Smiod config.make_executable = FALSE;
548007c2a45Smiod }
549007c2a45Smiod break;
550007c2a45Smiod }
551c074d1c9Sdrahn vfinfo (stderr, fmt, arg);
552007c2a45Smiod
553007c2a45Smiod out:
554007c2a45Smiod va_end (arg);
555c074d1c9Sdrahn return TRUE;
556c074d1c9Sdrahn }
557