From 99847db8ea741f895d79b9312114c13ccb660d83 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 15 Nov 2017 11:35:21 +1030 Subject: [PATCH] ld einfo positional arg support To allow translators to reorder values in translated strings. This should mean that all binutils messages now have support for reordering. Note to translators: Not all % letters take arguments, so for example the following only has two arguments, the two %s strings. "%P%F: output format %s cannot represent section called %s: %E\n" You could reorder this if you liked to: "%P%F: %E: section %2$s cannot be represented in output format %1$s\n" einfo lacks support for flags, field width, precision and length modifier (apart from %ld and %lu) so don't try to use them in translations. Both ld and bfd lack support to use a positional arg twice. These features could be added if needed.. * ldmisc.c (vfinfo): Support up to 9 positional args. --- ld/ChangeLog | 4 + ld/ldmisc.c | 205 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 185 insertions(+), 24 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index a012c023526..97bc8fb01a0 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,7 @@ +2017-11-15 Alan Modra + + * ldmisc.c (vfinfo): Support up to 9 positional args. + 2017-11-14 Jim Wilson * testsuite/ld-elf/compress1-alt.s: New. diff --git a/ld/ldmisc.c b/ld/ldmisc.c index 420ddb13c18..da499e97d0c 100644 --- a/ld/ldmisc.c +++ b/ld/ldmisc.c @@ -23,6 +23,7 @@ #include "bfd.h" #include "bfdlink.h" #include "libiberty.h" +#include "safe-ctype.h" #include "filenames.h" #include "demangle.h" #include @@ -65,10 +66,140 @@ */ void -vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) +vfinfo (FILE *fp, const char *fmt, va_list ap, bfd_boolean is_warning) { bfd_boolean fatal = FALSE; + const char *scan; + int arg_type; + unsigned int arg_count = 0; + unsigned int arg_no; + union vfinfo_args + { + int i; + long l; + void *p; + bfd_vma v; + struct { + bfd *abfd; + asection *sec; + bfd_vma off; + } reladdr; + enum + { + Bad, + Int, + Long, + Ptr, + Vma, + RelAddr + } type; + } args[9]; + + 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; + } + + arg_type = Bad; + switch (*scan++) + { + case '\0': + --scan; + break; + + case 'V': + case 'v': + case 'W': + arg_type = Vma; + break; + + case 'T': + case 'A': + case 'B': + case 'I': + case 'S': + case 'R': + case 'p': + case 's': + arg_type = Ptr; + break; + + case 'C': + case 'D': + case 'G': + case 'H': + arg_type = RelAddr; + break; + + case 'd': + case 'u': + arg_type = Int; + break; + + case 'l': + if (*scan == 'd' || *scan == 'u') + { + ++scan; + arg_type = 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 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; @@ -83,8 +214,20 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) if (*fmt == '%') { fmt++; + + arg_no = arg_count; + if (*fmt != '0' && ISDIGIT (*fmt) && fmt[1] == '$') + { + arg_no = *fmt - '1'; + fmt += 2; + } + switch (*fmt++) { + case '\0': + --fmt; + /* Fall through. */ + case '%': /* literal % */ putc ('%', fp); @@ -98,7 +241,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) case 'V': /* hex bfd_vma */ { - bfd_vma value = va_arg (arg, bfd_vma); + bfd_vma value = args[arg_no].v; + ++arg_count; fprintf_vma (fp, value); } break; @@ -108,7 +252,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) { char buf[100]; char *p = buf; - bfd_vma value = va_arg (arg, bfd_vma); + bfd_vma value = args[arg_no].v; + ++arg_count; sprintf_vma (p, value); while (*p == '0') p++; @@ -127,7 +272,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) char *p; int len; - value = va_arg (arg, bfd_vma); + value = args[arg_no].v; + ++arg_count; sprintf_vma (buf, value); for (p = buf; *p == '0'; ++p) ; @@ -146,8 +292,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) case 'T': /* Symbol name. */ { - const char *name = va_arg (arg, const char *); - + const char *name = (const char *) args[arg_no].p; + ++arg_count; if (name == NULL || *name == 0) { fprintf (fp, _("no symbol")); @@ -173,11 +319,14 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) case 'A': /* section name from a section */ { - asection *sec = va_arg (arg, asection *); - bfd *abfd = sec->owner; + asection *sec; + bfd *abfd; const char *group = NULL; struct coff_comdat_info *ci; + sec = (asection *) args[arg_no].p; + ++arg_count; + abfd = sec->owner; fprintf (fp, "%s", sec->name); if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour @@ -197,8 +346,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) case 'B': /* filename from a bfd */ { - bfd *abfd = va_arg (arg, bfd *); - + bfd *abfd = (bfd *) args[arg_no].p; + ++arg_count; if (abfd == NULL) fprintf (fp, "%s generated", program_name); else if (abfd->my_archive != NULL @@ -230,7 +379,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) { lang_input_statement_type *i; - i = va_arg (arg, lang_input_statement_type *); + i = (lang_input_statement_type *) args[arg_no].p; + ++arg_count; if (i->the_bfd->my_archive != NULL && !bfd_is_thin_archive (i->the_bfd->my_archive)) fprintf (fp, "(%s)", @@ -247,8 +397,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) /* Print script file and linenumber. */ { etree_type node; - etree_type *tp = va_arg (arg, etree_type *); - + etree_type *tp = (etree_type *) args[arg_no].p; + ++arg_count; if (tp == NULL) { tp = &node; @@ -263,8 +413,8 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) case 'R': /* Print all that's interesting about a relent. */ { - arelent *relent = va_arg (arg, arelent *); - + arelent *relent = (arelent *) args[arg_no].p; + ++arg_count; lfinfo (fp, "%s+0x%v (type %s)", (*(relent->sym_ptr_ptr))->name, relent->addend, @@ -292,9 +442,10 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) bfd_boolean discard_last; bfd_boolean done; - abfd = va_arg (arg, bfd *); - section = va_arg (arg, asection *); - offset = va_arg (arg, bfd_vma); + abfd = args[arg_no].reladdr.abfd; + section = args[arg_no].reladdr.sec; + offset = args[arg_no].reladdr.off; + ++arg_count; if (abfd != NULL) { @@ -394,34 +545,40 @@ vfinfo (FILE *fp, const char *fmt, va_list arg, bfd_boolean is_warning) case 'p': /* native (host) void* pointer, like printf */ - fprintf (fp, "%p", va_arg (arg, void *)); + fprintf (fp, "%p", args[arg_no].p); + ++arg_count; break; case 's': /* arbitrary string, like printf */ - fprintf (fp, "%s", va_arg (arg, char *)); + fprintf (fp, "%s", (char *) args[arg_no].p); + ++arg_count; break; case 'd': /* integer, like printf */ - fprintf (fp, "%d", va_arg (arg, int)); + fprintf (fp, "%d", args[arg_no].i); + ++arg_count; break; case 'u': /* unsigned integer, like printf */ - fprintf (fp, "%u", va_arg (arg, unsigned int)); + fprintf (fp, "%u", args[arg_no].i); + ++arg_count; break; case 'l': if (*fmt == 'd') { - fprintf (fp, "%ld", va_arg (arg, long)); + fprintf (fp, "%ld", args[arg_no].l); + ++arg_count; ++fmt; break; } else if (*fmt == 'u') { - fprintf (fp, "%lu", va_arg (arg, unsigned long)); + fprintf (fp, "%lu", args[arg_no].l); + ++arg_count; ++fmt; break; } -- 2.39.2