[PATCH] ld: support most modifiers for printf() like vfinfo() format specifiers

Jan Beulich jbeulich@suse.com
Tue Nov 18 15:22:39 GMT 2025


Not doing so is pretty error prone: One needs to distinguish e.g.
->einfo() and alike invocations out of libbfd from _bfd_error_handler()
ones. Omit support for * though for now, as that would be more intrusive
to implement.

Use this then to disambiguate x86'es ISA level diagnostic of unknown bits,
where decimal vs hex isn't immediately clear.
---
In fact I wonder whether instead of printing each unknown bit
individually, we wouldn't better accumulate them and report them together
at the end.

--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -4254,7 +4254,7 @@ report_isa_level (struct bfd_link_info *
 	  info->callbacks->einfo ("x86-64-v4");
 	  break;
 	default:
-	  info->callbacks->einfo (_("<unknown: %x>"), bit);
+	  info->callbacks->einfo (_("<unknown: %#x>"), bit);
 	  break;
 	}
       if (bitmask)
--- a/ld/ldmisc.c
+++ b/ld/ldmisc.c
@@ -37,6 +37,27 @@
 #include "ldmain.h"
 #include "ldfile.h"
 
+static size_t
+count_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
@@ -119,6 +140,9 @@ vfinfo (FILE *fp, const char *fmt, va_li
 	      scan += 2;
 	    }
 
+	  /* Skip most modifiers that printf() permits.  */
+	  scan += count_modifiers (scan);
+
 	  arg_type = Bad;
 	  switch (*scan++)
 	    {
@@ -217,6 +241,8 @@ vfinfo (FILE *fp, const char *fmt, va_li
 
       if (*fmt == '%')
 	{
+	  size_t mods;
+
 	  fmt++;
 
 	  arg_no = arg_count;
@@ -226,8 +252,14 @@ vfinfo (FILE *fp, const char *fmt, va_li
 	      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.  */
@@ -514,56 +546,32 @@ vfinfo (FILE *fp, const char *fmt, va_li
 		    }
 		  fprintf (fp, "%s", name);
 		}
-	      else
+	      else /* Native (host) void* pointer, like printf().  */
 		{
-		  /* native (host) void* pointer, like printf */
-		  fprintf (fp, "%p", args[arg_no].p);
+		  /* Fallthru */
+	    case 's': /* Arbitrary string, like printf().  */
+		  cfmt = make_cfmt (fmt - 1 - mods, mods + 1);
+		  fprintf (fp, cfmt, args[arg_no].p);
+		  free (cfmt);
 		  ++arg_count;
 		}
 	      break;
 
-	    case 's':
-	      /* arbitrary string, like printf */
-	      fprintf (fp, "%s", (char *) args[arg_no].p);
-	      ++arg_count;
-	      break;
-
-	    case 'd':
-	      /* integer, like printf */
-	      fprintf (fp, "%d", args[arg_no].i);
-	      ++arg_count;
-	      break;
-
-	    case 'u':
-	      /* unsigned integer, like printf */
-	      fprintf (fp, "%u", args[arg_no].i);
+	    case 'd': /* Integer, like printf().  */
+	    case 'u': /* Unsigned integer, like printf().  */
+	    case 'x': /* Unsigned integer, like printf().  */
+	      cfmt = make_cfmt (fmt - 1 - mods, mods + 1);
+	      fprintf (fp, cfmt, args[arg_no].i);
+	      free (cfmt);
 	      ++arg_count;
 	      break;
 
-	    case 'x':
-	      /* unsigned integer, like printf */
-	      fprintf (fp, "%x", args[arg_no].i);
-	      ++arg_count;
-	      break;
-
-	    case 'l':
-	      if (*fmt == 'd')
-		{
-		  fprintf (fp, "%ld", args[arg_no].l);
-		  ++arg_count;
-		  ++fmt;
-		  break;
-		}
-	      else if (*fmt == 'u')
-		{
-		  fprintf (fp, "%lu", args[arg_no].l);
-		  ++arg_count;
-		  ++fmt;
-		  break;
-		}
-	      else if (*fmt == 'x')
+	    case 'l': /* (Unsigned) long integer, like printf().  */
+	      if (*fmt == 'd' || *fmt == 'u' || *fmt == 'x')
 		{
-		  fprintf (fp, "%lx", args[arg_no].l);
+		  cfmt = make_cfmt (fmt - 1 - mods, mods + 2);
+		  fprintf (fp, cfmt, args[arg_no].l);
+		  free (cfmt);
 		  ++arg_count;
 		  ++fmt;
 		  break;
--- a/ld/testsuite/ld-x86-64/pr31868a.l
+++ b/ld/testsuite/ld-x86-64/pr31868a.l
@@ -1,4 +1,4 @@
-tmpdir/pr31868a.o: x86 ISA needed: x86-64-baseline, x86-64-v3, <unknown: 10>, <unknown: 20>
-tmpdir/pr31868a.o: x86 ISA used: x86-64-v3, x86-64-v4, <unknown: 40>
+tmpdir/pr31868a.o: x86 ISA needed: x86-64-baseline, x86-64-v3, <unknown: 0x10>, <unknown: 0x20>
+tmpdir/pr31868a.o: x86 ISA used: x86-64-v3, x86-64-v4, <unknown: 0x40>
 tmpdir/pr31868b.o: x86 ISA needed: x86-64-baseline, x86-64-v2, x86-64-v3
-tmpdir/pr31868b.o: x86 ISA used: x86-64-baseline, x86-64-v2, x86-64-v4, <unknown: 10>
+tmpdir/pr31868b.o: x86 ISA used: x86-64-baseline, x86-64-v2, x86-64-v4, <unknown: 0x10>
--- a/ld/testsuite/ld-x86-64/pr31868b.l
+++ b/ld/testsuite/ld-x86-64/pr31868b.l
@@ -1,2 +1,2 @@
-tmpdir/pr31868a.o: x86 ISA needed: x86-64-baseline, x86-64-v3, <unknown: 10>, <unknown: 20>
+tmpdir/pr31868a.o: x86 ISA needed: x86-64-baseline, x86-64-v3, <unknown: 0x10>, <unknown: 0x20>
 tmpdir/pr31868b.o: x86 ISA needed: x86-64-baseline, x86-64-v2, x86-64-v3
--- a/ld/testsuite/ld-x86-64/pr31868c.l
+++ b/ld/testsuite/ld-x86-64/pr31868c.l
@@ -1,2 +1,2 @@
-tmpdir/pr31868a.o: x86 ISA used: x86-64-v3, x86-64-v4, <unknown: 40>
-tmpdir/pr31868b.o: x86 ISA used: x86-64-baseline, x86-64-v2, x86-64-v4, <unknown: 10>
+tmpdir/pr31868a.o: x86 ISA used: x86-64-v3, x86-64-v4, <unknown: 0x40>
+tmpdir/pr31868b.o: x86 ISA used: x86-64-baseline, x86-64-v2, x86-64-v4, <unknown: 0x10>


More information about the Binutils mailing list