[PATCH] ld: Add --encoded-package-metadata

Benjamin Drung benjamin.drung@canonical.com
Tue Jul 16 08:32:56 GMT 2024


On Tue, 2024-07-16 at 08:19 +0200, Jan Beulich wrote:
> On 15.07.2024 20:43, Benjamin Drung wrote:
> > Specifying the compiler flag `-Wl,--package-metadata=<JSON>` might not
> > work, because the shells might eat the quotation marks and the compiler
> > splits the JSON at the commas.
> > 
> > Ubuntu tried to using a specs file to set `--package-metadata` but that
> > turned out to be too fragile. autopkgtests might use the compiler flags
> > but the needed environment variables are not set in the test
> > environment. Debugging a crash of an application build with the -spec
> > parameter lacks the environment variables. People like to iteratively
> > continue building the software in the build directory while hacking on
> > the package and then have no environment variable set.
> > 
> > So introduce a `--encoded-package-metadata` linker flag that takes a
> > percent-encoded JSON. Percent-encoding is used because it is a
> > standard and simple to implement.
> > 
> > Bug-Ubutru: https://bugs.launchpad.net/bugs/2071468
> > Signed-off-by: Benjamin Drung <benjamin.drung@canonical.com>
> 
> Fundamentally fine, but please add a testcase (even if it's a contrived one).
> And there are a number of style issues (see below).
> 

I am working on a test case, but I'll send the reformatted code as patch
v2 for allowing to review the formatting changes. While writing the
code, I tried to follow what the existing code did, but failed horribly.

> > --- a/ld/emultempl/elf.em
> > +++ b/ld/emultempl/elf.em
> > @@ -813,6 +813,7 @@ EOF
> >  fi
> >  fragment <<EOF
> >      {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
> > +    {"encoded-package-metadata", optional_argument, NULL, OPTION_ENCODED_PACKAGE_METADATA},
> >      {"package-metadata", optional_argument, NULL, OPTION_PACKAGE_METADATA},
> >      {"compress-debug-sections", required_argument, NULL, OPTION_COMPRESS_DEBUG},
> >      {"rosegment", no_argument, NULL, OPTION_ROSEGMENT},
> > @@ -864,6 +865,23 @@ gld${EMULATION_NAME}_handle_option (int optc)
> >  	ldelf_emit_note_gnu_build_id = xstrdup (optarg);
> >        break;
> >  
> > +    case OPTION_ENCODED_PACKAGE_METADATA:
> > +      free ((char *) ldelf_emit_note_fdo_package_metadata);
> 
> This is, I think, the common GNU way of writing casts. I wouldn't insist on
> the blank after the closing paren here if it was missing, yet further down
> it is. My minimal request is: Please be consistent within a patch.
> 

That code line is used identical some lines below.

> > +      ldelf_emit_note_fdo_package_metadata = NULL;
> > +      if (optarg != NULL) {
> 
> Opening brace placement is wrong thoughout the entire patch.
> 

Hopefully fixed everywhere.

> > +	size_t len = strlen(optarg);
> 
> Blank missing ahead of the opening paren (also elsewhere).
> 
> > +	if (len > 0) {
> > +	  ldelf_emit_note_fdo_package_metadata = xmalloc (len + 1);
> > +	  int len = percent_decode (optarg,
> > +	                           ldelf_emit_note_fdo_package_metadata);
> > +	  if (len < 0) {
> > +	    einfo (_ ("%F%P: Failed to decode percent-encoded package metadata"
> > +	          " \`%s'\n"), optarg);
> 
> Yes, there are three examples of "_ (" in ld sources. The canonical spelling
> is "_(" though, unlike function calls.
> 
> > --- a/ld/ldmisc.c
> > +++ b/ld/ldmisc.c
> > @@ -770,3 +770,53 @@ ld_abort (const char *file, int line, const char *fn)
> >    einfo (_("%F%P: please report this bug\n"));
> >    xexit (1);
> >  }
> > +
> > +/* Decode a hexadecimal character. Return -1 on error. */
> > +static int
> > +hexdecode(char c) {
> > +  if ('0' <= c && c <= '9') {
> > +    return c - '0';
> > +  }
> > +  if ('A' <= c && c <= 'F') {
> > +    return c - 'A' + 10;
> > +  }
> > +  if ('a' <= c && c <= 'f') {
> > +    return c - 'a' + 10;
> > +  }
> > +  return -1;
> > +}
> > +
> > +/* Decode a percent-encoded string. dst must be at least the same size as src.
> > +   It can be converted in place. Returns the lenght of the decoded string
> > +   (without training null character) or -1 on error. */
> > +int
> > +percent_decode(char *src, char *dst) {
> 
> "const char *" for "src" please.
> 

Changed.

> > +  int length = 0;
> > +  while (*src != '\0') {
> > +    char c = *src++;
> > +    if (c != '%') {
> > +      *dst++ = c;
> > +      length += 1;
> > +      continue;
> > +    }
> > +    char next1 = *src++;
> > +    if (next1 == '%') {
> > +      // Encoded %
> > +      *dst++ = c;
> > +      length += 1;
> > +      continue;
> > +    }
> > +    int hex1 = hexdecode(next1);
> > +    if (hex1 == -1) {
> > +      return -1;
> > +    }
> > +    int hex2 = hexdecode(*src++);
> > +    if (hex2 == -1) {
> > +      return -1;
> > +    }
> > +    *dst++ = ((char)hex1 << 4) + (char)hex2;
> 
> I'm curious: What use are the casts here? Especially the left one does,
> afaict, absolutely nothing: hex1 is converted to char (without changing the
> value, given what hexdecode() can return) just to then be promoted back to
> int.

I changed it to do the char conversion after the full calculation.

-- 
Benjamin Drung
Debian & Ubuntu Developer


More information about the Binutils mailing list