Wolfgang Thallergcc16 merge934c3885 months agoHistory
887 lines · 19.3 KB · C
RawDownload
/* ldmisc.c   Copyright (C) 1991-2026 Free Software Foundation, Inc.   Written by Steve Chamberlain of Cygnus Support.    This file is part of the GNU Binutils.    This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.    This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.    You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,   MA 02110-1301, USA.  */ #include "sysdep.h"#include "bfd.h"#include "bfdlink.h"#include "libiberty.h"#include "ctf-api.h"#include "safe-ctype.h"#include "filenames.h"#include "demangle.h"#include <stdarg.h>#include "ld.h"#include "ldmisc.h"#include "ldexp.h"#include "ldlang.h"#include <ldgram.h>#include "ldlex.h"#include "ldmain.h"#include "ldfile.h" static size_tcount_modifiers (const char *scan){  size_t mods = strspn (scan, "-+ #0");   while (scan[mods] != '0' && ISDIGIT (scan[mods]))    ++mods;  if (scan[mods] == '.')    ++mods;  while (scan[mods] != '0' && ISDIGIT (scan[mods]))    ++mods;   return mods;} static char *make_cfmt (const char *fmt, int nr){  return xasprintf ("%%%.*s", nr, fmt);} /* %% literal % %C clever filename:linenumber with function %D like %C, but no function name %E current bfd error or errno %G like %D, but only function name %H like %C but in addition emit section+offset %P print program name %V hex bfd_vma %W hex bfd_vma with 0x with no leading zeros taking up 10 spaces %X no object output, fail return %d integer, like printf %ld long, like printf %lu unsigned long, like printf %lx unsigned long, like printf %p native (host) void* pointer, like printf %pA section name from a section %pB filename from a bfd %pI filename from a lang_input_statement_type %pR info about a relent %pS print script file and linenumber from etree_type. %pT symbol name %pU print script file without linenumber from etree_type. %s arbitrary string, like printf %u integer, like printf %v hex bfd_vma, no leading zeros %x integer, like printf*/ voidvfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning){  const char *scan;  int arg_type;  unsigned int arg_count = 0;  unsigned int arg_no;  union vfinfo_args  {    int i;    long l;    long long ll;    void *p;    bfd_vma v;    struct {      bfd *abfd;      asection *sec;      bfd_vma off;    } reladdr;    enum      {	Bad,	Int,	Long,	LongLong,	Ptr,	Vma,	RelAddr      } type;  } args[9];   if (is_warning && config.no_warnings)    return;    for (arg_no = 0; arg_no < sizeof (args) / sizeof (args[0]); arg_no++)    args[arg_no].type = Bad;   arg_count = 0;  scan = fmt;  while (*scan != '\0')    {      while (*scan != '%' && *scan != '\0')	scan++;       if (*scan == '%')	{	  scan++; 	  arg_no = arg_count;	  if (*scan != '0' && ISDIGIT (*scan) && scan[1] == '$')	    {	      arg_no = *scan - '1';	      scan += 2;	    } 	  /* Skip most modifiers that printf() permits.  */	  scan += count_modifiers (scan); 	  arg_type = Bad;	  switch (*scan++)	    {	    case '\0':	      --scan;	      break; 	    case 'V':	    case 'v':	    case 'W':	      arg_type = Vma;	      break; 	    case 's':	      arg_type = Ptr;	      break; 	    case 'p':	      if (*scan == 'A' || *scan == 'B' || *scan == 'I'		  || *scan == 'R' || *scan == 'S' || *scan ==  'T')		scan++;	      arg_type = Ptr;	      break; 	    case 'C':	    case 'D':	    case 'G':	    case 'H':	      arg_type = RelAddr;	      break; 	    case 'd':	    case 'u':	    case 'x':	      arg_type = Int;	      break; 	    case 'l':	      {		bool ll_type = false;		if (*scan == 'l')		  {		    ll_type = true;		    ++scan;		  }		if (*scan == 'd' || *scan == 'u' || *scan == 'x')		  {		    ++scan;		    arg_type = (ll_type ? LongLong : Long);		  }	      }	      break; 	    default:	      break;	    }	  if (arg_type != Bad)	    {	      if (arg_no >= sizeof (args) / sizeof (args[0]))		abort ();	      args[arg_no].type = arg_type;	      ++arg_count;	    }	}    }   for (arg_no = 0; arg_no < arg_count; arg_no++)    {      switch (args[arg_no].type)	{	case Int:	  args[arg_no].i = va_arg (ap, int);	  break;	case Long:	  args[arg_no].l = va_arg (ap, long);	  break;	case LongLong:	  args[arg_no].ll = va_arg (ap, long long);	  break;	case Ptr:	  args[arg_no].p = va_arg (ap, void *);	  break;	case Vma:	  args[arg_no].v = va_arg (ap, bfd_vma);	  break;	case RelAddr:	  args[arg_no].reladdr.abfd = va_arg (ap, bfd *);	  args[arg_no].reladdr.sec = va_arg (ap, asection *);	  args[arg_no].reladdr.off = va_arg (ap, bfd_vma);	  break;	default:	  abort ();	}    }   arg_count = 0;  while (*fmt != '\0')    {      const char *str = fmt;      while (*fmt != '%' && *fmt != '\0')	fmt++;      if (fmt != str)	if (fwrite (str, 1, fmt - str, fp))	  {	    /* Ignore.  */	  }       if (*fmt == '%')	{	  size_t mods; 	  fmt++; 	  arg_no = arg_count;	  if (*fmt != '0' && ISDIGIT (*fmt) && fmt[1] == '$')	    {	      arg_no = *fmt - '1';	      fmt += 2;	    } 	  /* Record modifiers that printf() permits and that we support.  */	  mods = count_modifiers (fmt);	  fmt += mods; 	  switch (*fmt++)	    {	      char *cfmt; 	    case '\0':	      --fmt;	      /* Fall through.  */ 	    case '%':	      /* literal % */	      putc ('%', fp);	      break; 	    case 'X':	      /* no object output, fail return */	      config.make_executable = false;	      break; 	    case 'V':	      /* hex bfd_vma */	      {		char buf[32];		bfd_vma value; 		value = args[arg_no].v;		++arg_count;		bfd_sprintf_vma (link_info.output_bfd, buf, value);		fprintf (fp, "%s", buf);	      }	      break; 	    case 'v':	      /* hex bfd_vma, no leading zeros */	      {		uint64_t value = args[arg_no].v;		++arg_count;		fprintf (fp, "%" PRIx64, value);	      }	      break; 	    case 'W':	      /* hex bfd_vma with 0x with no leading zeroes taking up		 10 spaces (including the 0x).  */	      {		char buf[32];		uint64_t value; 		value = args[arg_no].v;		++arg_count;		sprintf (buf, "0x%" PRIx64, value);		fprintf (fp, "%10s", buf);	      }	      break; 	    case 'P':	      /* Print program name.  */	      fprintf (fp, "%s", program_name);	      break; 	    case 'E':	      /* current bfd error or errno */	      fprintf (fp, "%s", bfd_errmsg (bfd_get_error ()));	      break; 	    case 'C':	    case 'D':	    case 'G':	    case 'H':	      /* Clever filename:linenumber with function name if possible.		 The arguments are a BFD, a section, and an offset.  */	      {		static bfd *last_bfd;		static char *last_file;		static char *last_function;		bfd *abfd;		asection *section;		bfd_vma offset;		asymbol **asymbols = NULL;		const char *filename;		const char *functionname;		unsigned int linenumber;		bool discard_last;		bool done;		bfd_error_type last_bfd_error = bfd_get_error (); 		abfd = args[arg_no].reladdr.abfd;		section = args[arg_no].reladdr.sec;		offset = args[arg_no].reladdr.off;		++arg_count; 		if (abfd != NULL)		  {		    if (!bfd_generic_link_read_symbols (abfd))		      fatal (_("%P: %pB: could not read symbols: %E\n"), abfd); 		    asymbols = bfd_get_outsymbols (abfd);		  } 		/* The GNU Coding Standard requires that error messages		   be of the form: 		     source-file-name:lineno: message 		   We do not always have a line number available so if		   we cannot find them we print out the section name and		   offset instead.  */		discard_last = true;		if (abfd != NULL		    && bfd_find_nearest_line (abfd, section, asymbols, offset,					      &filename, &functionname,					      &linenumber))		  {		    if (functionname != NULL			&& (fmt[-1] == 'C' || fmt[-1] == 'H'))		      {			/* Detect the case where we are printing out a			   message for the same function as the last			   call to vinfo ("%C").  In this situation do			   not print out the ABFD filename or the			   function name again.  Note - we do still			   print out the source filename, as this will			   allow programs that parse the linker's output			   (eg emacs) to correctly locate multiple			   errors in the same source file.  */			if (last_bfd == NULL			    || last_function == NULL			    || last_bfd != abfd			    || (last_file == NULL) != (filename == NULL)			    || (filename != NULL				&& filename_cmp (last_file, filename) != 0)			    || strcmp (last_function, functionname) != 0)			  {			    lfinfo (fp, _("%pB: in function `%pT':\n"),				    abfd, functionname); 			    last_bfd = abfd;			    free (last_file);			    last_file = NULL;			    if (filename)			      last_file = xstrdup (filename);			    free (last_function);			    last_function = xstrdup (functionname);			  }			discard_last = false;		      }		    else		      lfinfo (fp, "%pB:", abfd); 		    if (filename != NULL)		      fprintf (fp, "%s:", filename); 		    done = fmt[-1] != 'H';		    if (functionname != NULL && fmt[-1] == 'G')		      lfinfo (fp, "%pT", functionname);		    else if (filename != NULL && linenumber != 0)		      fprintf (fp, "%u%s", linenumber, done ? "" : ":");		    else		      done = false;		  }		else		  {		    lfinfo (fp, "%pB:", abfd);		    done = false;		  }		if (!done)		  lfinfo (fp, "(%pA+0x%v)", section, offset);		bfd_set_error (last_bfd_error); 		if (discard_last)		  {		    last_bfd = NULL;		    free (last_file);		    last_file = NULL;		    free (last_function);		    last_function = NULL;		  }	      }	      break; 	    case 'p':	      if (*fmt == 'A')		{		  /* section name from a section */		  asection *sec;		  bfd *abfd; 		  fmt++;		  sec = (asection *) args[arg_no].p;		  ++arg_count;		  fprintf (fp, "%s", sec->name);		  abfd = sec->owner;		  if (abfd != NULL)		    {		      const char *group = bfd_group_name (abfd, sec);		      if (group != NULL)			fprintf (fp, "[%s]", group);		    }		}	      else if (*fmt == 'B')		{		  /* filename from a bfd */		  bfd *abfd = (bfd *) args[arg_no].p; 		  fmt++;		  ++arg_count;		  if (abfd == NULL)		    fprintf (fp, "%s generated", program_name);		  else if (abfd->my_archive != NULL			   && !bfd_is_thin_archive (abfd->my_archive))		    fprintf (fp, "%s(%s)",			     bfd_get_filename (abfd->my_archive),			     bfd_get_filename (abfd));		  else		    fprintf (fp, "%s", bfd_get_filename (abfd));		}	      else if (*fmt == 'I')		{		  /* filename from a lang_input_statement_type */		  lang_input_statement_type *i; 		  fmt++;		  i = (lang_input_statement_type *) args[arg_no].p;		  ++arg_count;		  if (i->the_bfd != NULL		      && i->the_bfd->my_archive != NULL		      && !bfd_is_thin_archive (i->the_bfd->my_archive))		    fprintf (fp, "(%s)%s",			     bfd_get_filename (i->the_bfd->my_archive),			     i->local_sym_name);

Lines 1–500 of 887.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t