util: Add utility build-id code.
authorMatt Turner <mattst88@gmail.com>
Tue, 14 Feb 2017 15:29:56 +0000 (07:29 -0800)
committerMatt Turner <mattst88@gmail.com>
Wed, 15 Feb 2017 21:59:51 +0000 (13:59 -0800)
Provides the ability to read the .note.gnu.build-id section of ELF
binaries, which is inserted by the --build-id=... flag to ld.

Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Chad Versace <chadversary@chromium.org>
configure.ac
src/util/Makefile.sources
src/util/build_id.c [new file with mode: 0644]
src/util/build_id.h [new file with mode: 0644]

index f001743ea21b216a0d76a177f5c0cb3d354de64e..e4a5b480b18ef428c05ec8cf971ff8a4bba7258d 100644 (file)
@@ -768,6 +768,8 @@ LIBS="$LIBS $DLOPEN_LIBS"
 AC_CHECK_FUNCS([dladdr])
 LIBS="$save_LIBS"
 
+AC_CHECK_FUNC([dl_iterate_phdr], [DEFINES="$DEFINES -DHAVE_DL_ITERATE_PHDR"])
+
 case "$host_os" in
 darwin*)
     ;;
@@ -1773,6 +1775,10 @@ AC_ARG_WITH([vulkan-icddir],
 AC_SUBST([VULKAN_ICD_INSTALL_DIR])
 
 if test -n "$with_vulkan_drivers"; then
+    if test "x$ac_cv_func_dl_iterate_phdr" = xno; then
+        AC_MSG_ERROR([Vulkan drivers require the dl_iterate_phdr function])
+    fi
+
     VULKAN_DRIVERS=`IFS=', '; echo $with_vulkan_drivers`
     for driver in $VULKAN_DRIVERS; do
         case "x$driver" in
index aecb7c294877da7c09d948fe2bed28438159d0ea..08ad7bec3ab3259b2c623cc9e9772c5a637aa15b 100644 (file)
@@ -2,6 +2,8 @@ MESA_UTIL_FILES :=      \
        bitscan.c \
        bitscan.h \
        bitset.h \
+       build_id.c \
+       build_id.h \
        crc32.c \
        crc32.h \
        debug.c \
diff --git a/src/util/build_id.c b/src/util/build_id.c
new file mode 100644 (file)
index 0000000..2993a80
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_DL_ITERATE_PHDR
+#include <link.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "build_id.h"
+
+#define ALIGN(val, align)      (((val) + (align) - 1) & ~((align) - 1))
+
+struct build_id_note {
+   ElfW(Nhdr) nhdr;
+
+   char name[4]; /* Note name for build-id is "GNU\0" */
+   uint8_t build_id[0];
+};
+
+struct callback_data {
+   const char *filename;
+   struct build_id_note *note;
+};
+
+static int
+build_id_find_nhdr_callback(struct dl_phdr_info *info, size_t size, void *data_)
+{
+   struct callback_data *data = data_;
+
+   char *ptr = strstr(info->dlpi_name, data->filename);
+   if (ptr == NULL || ptr[strlen(data->filename)] != '\0')
+      return 0;
+
+   for (unsigned i = 0; i < info->dlpi_phnum; i++) {
+      if (info->dlpi_phdr[i].p_type != PT_NOTE)
+         continue;
+
+      struct build_id_note *note = (void *)(info->dlpi_addr +
+                                            info->dlpi_phdr[i].p_vaddr);
+      ptrdiff_t len = info->dlpi_phdr[i].p_filesz;
+
+      while (len >= sizeof(struct build_id_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 build_id_note *)((char *)note + offset);
+         len -= offset;
+      }
+   }
+
+   return 0;
+}
+
+const struct build_id_note *
+build_id_find_nhdr(const char *filename)
+{
+   struct callback_data data = {
+      .filename = filename,
+      .note = NULL,
+   };
+
+   if (!dl_iterate_phdr(build_id_find_nhdr_callback, &data))
+      return NULL;
+
+   return data.note;
+}
+
+unsigned
+build_id_length(const struct build_id_note *note)
+{
+   return note->nhdr.n_descsz;
+}
+
+void
+build_id_read(const struct build_id_note *note,
+              unsigned char *build_id, size_t n)
+{
+   memcpy(build_id, note->build_id, n);
+}
+
+#endif
diff --git a/src/util/build_id.h b/src/util/build_id.h
new file mode 100644 (file)
index 0000000..39bf9b0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_DL_ITERATE_PHDR
+
+struct build_id_note;
+
+const struct build_id_note *
+build_id_find_nhdr(const char *filename);
+
+unsigned
+build_id_length(const struct build_id_note *note);
+
+void
+build_id_read(const struct build_id_note *note,
+              unsigned char *build_id, size_t n);
+
+#endif