/* ldmisc.c
Copyright (C) 1991-2024 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. */
/*
%% literal %
%C clever filename:linenumber with function
%D like %C, but no function name
%E current bfd error or errno
%F error is fatal
%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
*/
case 'F':
/* Error is fatal. */
fatal = true;
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 ();
if (abfd != NULL)
{
if (!bfd_generic_link_read_symbols (abfd))
einfo (_("%F%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);