[Mesa-dev] [PATCH 1/2] util: Add utility build-id code.

Chad Versace chadversary at chromium.org
Tue Feb 14 20:30:56 UTC 2017


On Tue 14 Feb 2017, Matt Turner wrote:
> Provides the ability to read the .note.gnu.build-id section of ELF
> binaries, which is inserted by the --build-id=... flag to ld.
> ---
>  configure.ac              |   2 +
>  src/util/Makefile.sources |   2 +
>  src/util/build_id.c       | 109 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/util/build_id.h       |  56 ++++++++++++++++++++++++
>  4 files changed, 169 insertions(+)
>  create mode 100644 src/util/build_id.c
>  create mode 100644 src/util/build_id.h


> +AC_CHECK_FUNC([dl_iterate_phdr], [DEFINES="$DEFINES -DHAVE_DL_ITERATE_PHDR"])

Nice. I wasn't aware of dl_iterate_phdr(). My code for querying the
build-id was less slick. It used open(2) on the library, then manually
parsed the ElfW(Ehdr) and ElfW(Shdr) to find the build-id node.


> diff --git a/src/util/build_id.c b/src/util/build_id.c
> new file mode 100644
> index 0000000..a2e21b7
> --- /dev/null
> +++ b/src/util/build_id.c


> +#define ALIGN(val, align)      (((val) + (align) - 1) & ~((align) - 1))
> +
> +struct note {
> +   ElfW(Nhdr) nhdr;
> +
> +   char name[4];

Because nothing requires ElfW(Nhdr).n_namesz to be 4, please a comment
here explaining that we hardcoded 4 because the note name is "GNU".

> +   uint8_t build_id[0];
> +};
> +
> +struct callback_data {
> +   const char *name;
> +   struct note *note;
> +};
> +
> +static int
> +build_id_find_nhdr_callback(struct dl_phdr_info *info, size_t size, void *data_)
> +{

This function looks correct to me.

> +   struct callback_data *data = data_;
> +
> +   char *ptr = strstr(info->dlpi_name, data->name);
> +   if (ptr == NULL || ptr[strlen(data->name)] != '\0')
> +      return 0;
> +
> +   for (unsigned i = 0; i < info->dlpi_phnum; i++) {
> +      if (info->dlpi_phdr[i].p_type != PT_NOTE)
> +         continue;
> +
> +      struct note *note = (void *)(info->dlpi_addr +
> +                                   info->dlpi_phdr[i].p_vaddr);

> +      ptrdiff_t len = info->dlpi_phdr[i].p_filesz;

I was initially worried that the len should use p_memsz instead of
p_filesz. But the elf manpage says it's ok; if p_memsz > p_filesz, then
the excess bytes are mere padding.

> +
> +      while (len >= sizeof(struct note)) {
> +         if (note->nhdr.n_type == NT_GNU_BUILD_ID &&
> +            note->nhdr.n_descsz != 0 &&
> +            note->nhdr.n_namesz == 4 &&
> +            memcmp(note->name, "GNU", 4) == 0) {
> +            data->note = note;
> +            return 1;
> +         }
> +
> +         size_t offset = sizeof(ElfW(Nhdr)) +
> +                         ALIGN(note->nhdr.n_namesz, 4) +
> +                         ALIGN(note->nhdr.n_descsz, 4);
> +         note = (struct note *)((char *)note + offset);
> +         len -= offset;
> +      }
> +   }
> +
> +   return 0;
> +}
> +
> +const struct note *
> +build_id_find_nhdr(const char *name)

Please rename the 'name' parameter to be clearer. I was confused,
thinking that name was the name of ELF section for the note. It wasn't
until I read patch 2, and saw name="libvulkan.so" instead
name=".note.gnu.build-id" that I was able to understand this patch.

> +{
> +   struct callback_data data = {
> +      .name = name,
> +      .note = NULL,
> +   };
> +
> +   if (dl_iterate_phdr(build_id_find_nhdr_callback, &data)) {
> +      return data.note;
> +   } else {
> +      return NULL;
> +   }
> +}
> +
> +unsigned
> +build_id_length(const struct note *note)
> +{
> +   return note->nhdr.n_descsz;
> +}
> +
> +void
> +build_id_read(const struct note *note, unsigned char *build_id)
> +{

As I explain in patch 2, I think this function needs a 'size' parameter,
à la snprintf, due to Vulkan weirdness regarding restrictons on usage of
malloc.

> +   memcpy(build_id, note->build_id, note->nhdr.n_descsz);
> +}

> diff --git a/src/util/build_id.h b/src/util/build_id.h
> new file mode 100644
> index 0000000..0eaecf9
> --- /dev/null
> +++ b/src/util/build_id.h


> +struct note;

Please namespace struct note. Please :)

My only hard request is the size_t parameter for build_id_read(). My
other comments are just minor nits, that you can ignore.


More information about the mesa-dev mailing list