/* ldmisc.c
- Copyright (C) 1991 Free Software Foundation, Inc.
+ Copyright (C) 1991, 92, 93, 94 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support.
#include "ld.h"
#include "ldmisc.h"
+#include "ldexp.h"
#include "ldlang.h"
+#include "ldgram.h"
#include "ldlex.h"
-/* IMPORTS */
-
-extern char *program_name;
-
-extern FILE *ldlex_input_stack;
-extern char *ldfile_input_filename;
-extern ld_config_type config;
-
-
-extern int errno;
-extern int sys_nerr;
-extern char *sys_errlist[];
+#include "ldmain.h"
+#include "ldfile.h"
/* VARARGS*/
static void finfo ();
+static const char *demangle PARAMS ((const char *string,
+ int remove_underscore));
/*
+ %% literal %
%F error is fatal
- %P print progam name
+ %P print program name
%S print script file and linenumber
%E current bfd error or errno
%I filename from a lang_input_statement_type
%B filename from a bfd
- %T symbol table entry
+ %T symbol name
%X no object output, fail return
%V hex bfd_vma
%v hex bfd_vma, no leading zeros
- %C Clever filename:linenumber
+ %C clever filename:linenumber with function
+ %D like %C, but no function name
%R info about a relent
- %
+ %s arbitrary string, like printf
+ %d integer, like printf
*/
-extern bfd *output_bfd;
-static char *
-demangle(string, remove_underscore)
-char *string;
-int remove_underscore;
+static const char *
+demangle (string, remove_underscore)
+ const char *string;
+ int remove_underscore;
{
- char *res;
+ const char *res;
if (remove_underscore && output_bfd)
{
- if (bfd_get_symbol_leading_char(output_bfd) == string[0])
+ if (bfd_get_symbol_leading_char (output_bfd) == string[0])
string++;
}
/* Note that there's a memory leak here, we keep buying memory
for demangled names, and never free. But if you have so many
errors that you run out of VM with the error messages, then
there's something up */
- res = cplus_demangle(string, DMGL_ANSI|DMGL_PARAMS);
+ res = cplus_demangle (string, DMGL_ANSI|DMGL_PARAMS);
return res ? res : string;
}
va_list arg;
{
boolean fatal = false;
+
while (*fmt)
{
while (*fmt != '%' && *fmt != '\0')
putc(*fmt, fp);
fmt++;
}
+
if (*fmt == '%')
{
fmt ++;
switch (*fmt++)
{
+ default:
+ fprintf(fp,"%%%c", fmt[-1]);
+ break;
+
+ case '%':
+ /* literal % */
+ putc('%', fp);
+ break;
+
case 'X':
+ /* no object output, fail return */
config.make_executable = false;
break;
+
case 'V':
- {
- bfd_vma value = va_arg(arg, bfd_vma);
- fprintf_vma(fp, value);
- }
+ /* hex bfd_vma */
+ {
+ bfd_vma value = va_arg(arg, bfd_vma);
+ fprintf_vma(fp, value);
+ }
break;
+
case 'v':
+ /* hex bfd_vma, no leading zeros */
{
char buf[100];
char *p = buf;
fputs (p, fp);
}
break;
+
case 'T':
- {
- asymbol *symbol = va_arg(arg, asymbol *);
- if (symbol)
- {
-
-
- asection *section = symbol->section;
- char *cplusname = demangle(symbol->name, 1);
- CONST char *section_name = section->name;
- if (section != &bfd_und_section)
- {
- fprintf(fp,"%s (%s)", cplusname, section_name);
- }
- else
- {
- fprintf(fp,"%s", cplusname);
- }
- }
- else
- {
- fprintf(fp,"no symbol");
- }
- }
+ /* Symbol name. */
+ {
+ const char *name = va_arg (arg, const char *);
+
+ if (name != (const char *) NULL)
+ fprintf (fp, "%s", demangle (name, 1));
+ else
+ fprintf (fp, "no symbol");
+ }
break;
+
case 'B':
+ /* filename from a bfd */
{
bfd *abfd = va_arg(arg, bfd *);
if (abfd->my_archive) {
}
else {
fprintf(fp,"%s", abfd->filename);
-
}
}
break;
+
case 'F':
+ /* error is fatal */
fatal = true;
break;
+
case 'P':
+ /* print program name */
fprintf(fp,"%s", program_name);
break;
- case 'E':
- /* Replace with the most recent errno explanation */
-
-
- fprintf(fp, bfd_errmsg(bfd_error));
-
+ case 'E':
+ /* current bfd error or errno */
+ fprintf(fp, bfd_errmsg(bfd_get_error ()));
break;
+
case 'I':
+ /* filename from a lang_input_statement_type */
{
lang_input_statement_type *i =
va_arg(arg,lang_input_statement_type *);
-
+
+ if (i->the_bfd->my_archive)
+ fprintf(fp, "(%s)", i->the_bfd->my_archive->filename);
fprintf(fp,"%s", i->local_sym_name);
}
break;
- case 'S':
- /* Print source script file and line number */
+ case 'S':
+ /* print script file and linenumber */
{
-
-
- extern unsigned int lineno;
- if (ldfile_input_filename == (char *)NULL) {
- fprintf(fp,"command line");
- }
- else {
+ if (ldfile_input_filename) {
fprintf(fp,"%s:%u", ldfile_input_filename, lineno );
}
}
-
break;
case 'R':
}
break;
-
-
-
case 'C':
- {
- CONST char *filename;
- CONST char *functionname;
- char *cplus_name;
-
- unsigned int linenumber;
- bfd *abfd = va_arg(arg, bfd *);
- asection *section = va_arg(arg, asection *);
- asymbol **symbols = va_arg(arg, asymbol **);
- bfd_vma offset = va_arg(arg, bfd_vma);
-
- if (bfd_find_nearest_line(abfd,
- section,
- symbols,
- offset,
- &filename,
- &functionname,
- &linenumber))
- {
- if (filename == (char *)NULL)
- filename = abfd->filename;
- if (functionname != (char *)NULL)
- {
- /* There is no initial '_' to remove here. */
- cplus_name = demangle(functionname, 0);
- fprintf(fp,"%s:%u: (%s)", filename, linenumber, cplus_name);
- }
-
- else if (linenumber != 0)
- fprintf(fp,"%s:%u", filename, linenumber);
- else
- finfo (fp, "%s(%s+0x%v)", filename, section->name, offset);
-
- }
- else
- finfo (fp, "%s(%s+0x%v)", abfd->filename, section->name, offset);
- }
+ case 'D':
+ /* Clever filename:linenumber with function name if possible,
+ or section name as a last resort. The arguments are a BFD,
+ a section, and an offset. */
+ {
+ static char *last_file = NULL;
+ static char *last_function = NULL;
+ bfd *abfd;
+ asection *section;
+ bfd_vma offset;
+ lang_input_statement_type *entry;
+ asymbol **asymbols;
+ const char *filename;
+ const char *functionname;
+ unsigned int linenumber;
+ boolean discard_last;
+
+ abfd = va_arg (arg, bfd *);
+ section = va_arg (arg, asection *);
+ offset = va_arg (arg, bfd_vma);
+
+ entry = (lang_input_statement_type *) abfd->usrdata;
+ if (entry != (lang_input_statement_type *) NULL
+ && entry->asymbols != (asymbol **) NULL)
+ asymbols = entry->asymbols;
+ else
+ {
+ long symsize;
+ long symbol_count;
+
+ symsize = bfd_get_symtab_upper_bound (abfd);
+ if (symsize < 0)
+ einfo ("%B%F: could not read symbols", abfd);
+ asymbols = (asymbol **) xmalloc (symsize);
+ symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
+ if (symbol_count < 0)
+ einfo ("%B%F: could not read symbols", abfd);
+ if (entry != (lang_input_statement_type *) NULL)
+ {
+ entry->asymbols = asymbols;
+ entry->symbol_count = symbol_count;
+ }
+ }
+
+ discard_last = true;
+ if (bfd_find_nearest_line (abfd, section, asymbols, offset,
+ &filename, &functionname, &linenumber))
+ {
+ if (filename == (char *) NULL)
+ filename = abfd->filename;
+
+ if (functionname != NULL && fmt[-1] == 'C')
+ {
+ if (last_file == NULL
+ || last_function == NULL
+ || strcmp (last_file, filename) != 0
+ || strcmp (last_function, functionname) != 0)
+ {
+ fprintf (fp, "%s: In function `%s':\n", filename,
+ demangle (functionname, 1));
+ if (last_file != NULL)
+ free (last_file);
+ last_file = buystring (filename);
+ if (last_function != NULL)
+ free (last_function);
+ last_function = buystring (functionname);
+ }
+ discard_last = false;
+ fprintf (fp, "%s:%u", filename, linenumber);
+ }
+ else if (linenumber != 0)
+ fprintf (fp, "%s:%u", filename, linenumber);
+ else
+ finfo (fp, "%s(%s+0x%v)", filename, section->name, offset);
+ }
+ else
+ finfo (fp, "%s(%s+0x%v)", abfd->filename, section->name, offset);
+
+ if (discard_last)
+ {
+ if (last_file != NULL)
+ {
+ free (last_file);
+ last_file = NULL;
+ }
+ if (last_function != NULL)
+ {
+ free (last_function);
+ last_function = NULL;
+ }
+ }
+ }
break;
case 's':
+ /* arbitrary string, like printf */
fprintf(fp,"%s", va_arg(arg, char *));
break;
+
case 'd':
+ /* integer, like printf */
fprintf(fp,"%d", va_arg(arg, int));
break;
- default:
- fprintf(fp,"%s", va_arg(arg, char *));
- break;
}
}
}
+
if (fatal == true)
- {
- extern char *output_filename;
- if (output_filename)
- {
- char *new = malloc(strlen(output_filename)+2);
- extern bfd *output_bfd;
-
- strcpy(new, output_filename);
- if (output_bfd && output_bfd->iostream)
- fclose((FILE *)(output_bfd->iostream));
- unlink(new);
- }
- exit(1);
- }
+ xexit(1);
}
/* Format info message and print on stdout. */
-void info(va_alist)
-va_dcl
+/* (You would think this should be called just "info", but then you would
+ hosed by LynxOS, which defines that name in its libc.) */
+
+void info_msg(va_alist)
+ va_dcl
{
char *fmt;
va_list arg;
/* ('e' for error.) Format info message and print on stderr. */
void einfo(va_alist)
-va_dcl
+ va_dcl
{
char *fmt;
va_list arg;
void
info_assert(file, line)
-char *file;
-unsigned int line;
+ char *file;
+ unsigned int line;
{
- einfo("%F%P internal error %s %d\n", file,line);
+ einfo("%F%P: internal error %s %d\n", file,line);
}
-/* Return a newly-allocated string
- whose contents concatenate those of S1, S2, S3. */
-
-char *
-concat (s1, s2, s3)
- CONST char *s1;
- CONST char *s2;
- CONST char *s3;
-{
- size_t len1 = strlen (s1);
- size_t len2 = strlen (s2);
- size_t len3 = strlen (s3);
- char *result = ldmalloc (len1 + len2 + len3 + 1);
-
- if (len1 != 0)
- memcpy(result, s1, len1);
- if (len2 != 0)
- memcpy(result+len1, s2, len2);
- if (len3 != 0)
- memcpy(result+len1+len2, s2, len3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
-}
-
-
-PTR
-ldmalloc (size)
- size_t size;
-{
- PTR result = malloc ((int)size);
-
- if (result == (char *)NULL && size != 0)
- einfo("%F%P virtual memory exhausted\n");
-
- return result;
-}
-
-PTR
-xmalloc (size)
- int size;
-{
-return ldmalloc(size);
-}
-
-
-PTR
-ldrealloc (ptr, size)
- PTR ptr;
- size_t size;
-{
- PTR result = realloc (ptr, (int)size);
-
- if (result == (char *)NULL && size != 0)
- einfo("%F%P virtual memory exhausted\n");
-
- return result;
-}
-
-PTR
-xrealloc (ptr, size)
- PTR ptr;
- size_t size;
-{
-return ldrealloc(ptr, size);
-}
-
-
char *
buystring (x)
CONST char *CONST x;
{
size_t l = strlen(x)+1;
- char *r = ldmalloc(l);
+ char *r = xmalloc(l);
memcpy(r, x,l);
return r;
}
/* ('m' for map) Format info message and print on map. */
void minfo(va_alist)
-va_dcl
+ va_dcl
{
char *fmt;
va_list arg;