Blame SOURCES/dyninst-10.2.1-dbid.patch

be296a
Debuginfod is a lightweight web service that indexes ELF/DWARF debugging
be296a
resources by build-id and serves them over HTTP.
be296a
be296a
This patch enables dyninst to query debuginfod servers for a file's
be296a
separate debuginfo when it otherwise cannot be found.
be296a
be296a
This patch also adds a cmake option -DENABLE_DEBUGINFOD to control
be296a
whether dyninst is built with debuginfod support.
be296a
be296a
This requires having the debuginfod client library (libdebuginfod)
be296a
and header installed.
be296a
be296a
Debuginfod is distributed with elfutils, for more information see
be296a
https://sourceware.org/elfutils/Debuginfod.html
be296a
---
be296a
 cmake/ElfUtils.cmake                  | 37 ++++++++---
be296a
 cmake/Modules/FindLibDebuginfod.cmake | 76 +++++++++++++++++++++
be296a
 cmake/options.cmake                   |  2 +
be296a
 elf/CMakeLists.txt                    |  3 +
be296a
 elf/src/Elf_X.C                       | 95 ++++++++++++++++++++-------
be296a
 5 files changed, 178 insertions(+), 35 deletions(-)
be296a
 create mode 100644 cmake/Modules/FindLibDebuginfod.cmake
be296a
be296a
--- dyninst-10.2.1/dyninst-10.2.1/cmake/ElfUtils.cmake
be296a
+++ dyninst-10.2.1/dyninst-10.2.1/cmake/ElfUtils.cmake
be296a
@@ -28,7 +28,7 @@
be296a
 #
be296a
 #======================================================================================
be296a
 
be296a
-if(LibElf_FOUND AND LibDwarf_FOUND)
be296a
+if(LibElf_FOUND AND LibDwarf_FOUND AND (LibDebuginfod_FOUND OR NOT ENABLE_DEBUGINFOD))
be296a
   return()
be296a
 endif()
be296a
 
be296a
@@ -37,7 +37,12 @@ if(NOT UNIX)
be296a
 endif()
be296a
 
be296a
 # Minimum acceptable version of elfutils
be296a
-set(_min_version 0.178)
be296a
+if(ENABLE_DEBUGINFOD)
be296a
+  set(_min_version 0.179)
be296a
+else()
be296a
+  set(_min_version 0.178)
be296a
+endif()
be296a
+
be296a
 set(ElfUtils_MIN_VERSION ${_min_version}
be296a
     CACHE STRING "Minimum acceptable elfutils version")
be296a
 if(${ElfUtils_MIN_VERSION} VERSION_LESS ${_min_version})
be296a
@@ -62,7 +67,7 @@ set(ElfUtils_LIBRARYDIR "${ElfUtils_ROOT_DIR}/lib"
be296a
     CACHE PATH "Hint directory that contains the elfutils library files")
be296a
 
be296a
 # libelf/dwarf-specific directory hints
be296a
-foreach(l LibElf LibDwarf)
be296a
+foreach(l LibElf LibDwarf LibDebuginfod)
be296a
   foreach(d ROOT_DIR INCLUDEDIR LIBRARYDIR)
be296a
     set(${l}_${d} ${ElfUtils_${d}})
be296a
   endforeach()
be296a
@@ -72,18 +77,30 @@ endforeach()
be296a
 
be296a
 find_package(LibElf ${ElfUtils_MIN_VERSION})
be296a
 
be296a
-# Don't search for libdw if we didn't find a suitable libelf
be296a
+# Don't search for libdw or libdebuginfod if we didn't find a suitable libelf
be296a
 if(LibElf_FOUND)
be296a
   find_package(LibDwarf ${ElfUtils_MIN_VERSION})
be296a
+  if (ENABLE_DEBUGINFOD)
be296a
+    find_package(LibDebuginfod ${ElfUtils_MIN_VERSION})
be296a
+  endif()
be296a
 endif()
be296a
 
be296a
 # -------------- SOURCE BUILD -------------------------------------------------
be296a
-if(LibElf_FOUND AND LibDwarf_FOUND)
be296a
-  set(_eu_root ${ElfUtils_ROOT_DIR})
be296a
-  set(_eu_inc_dirs ${LibElf_INCLUDE_DIRS} ${LibDwarf_INCLUDE_DIRS})
be296a
-  set(_eu_lib_dirs ${LibElf_LIBRARY_DIRS} ${LibDwarf_LIBRARY_DIRS})
be296a
-  set(_eu_libs ${LibElf_LIBRARIES} ${LibDwarf_LIBRARIES})
be296a
+if(LibElf_FOUND AND LibDwarf_FOUND AND (NOT ENABLE_DEBUGINFOD OR LibDebuginfod_FOUND))
be296a
+  if(ENABLE_DEBUGINFOD AND LibDebuginfod_FOUND)
be296a
+    set(_eu_root ${ElfUtils_ROOT_DIR})
be296a
+    set(_eu_inc_dirs ${LibElf_INCLUDE_DIRS} ${LibDwarf_INCLUDE_DIRS} ${LibDebuginfod_INCLUDE_DIRS})
be296a
+    set(_eu_lib_dirs ${LibElf_LIBRARY_DIRS} ${LibDwarf_LIBRARY_DIRS} ${LibDebuginfod_LIBRARY_DIRS})
be296a
+    set(_eu_libs ${LibElf_LIBRARIES} ${LibDwarf_LIBRARIES} ${LibDebuginfod_LIBRARIES})
be296a
+  else()
be296a
+    set(_eu_root ${ElfUtils_ROOT_DIR})
be296a
+    set(_eu_inc_dirs ${LibElf_INCLUDE_DIRS} ${LibDwarf_INCLUDE_DIRS})
be296a
+    set(_eu_lib_dirs ${LibElf_LIBRARY_DIRS} ${LibDwarf_LIBRARY_DIRS})
be296a
+    set(_eu_libs ${LibElf_LIBRARIES} ${LibDwarf_LIBRARIES})
be296a
+  endif()
be296a
   add_library(ElfUtils SHARED IMPORTED)
be296a
+elseif(ENABLE_DEBUGINFOD AND NOT LibDebuginfod_FOUND)
be296a
+  message(FATAL_ERROR "Debuginfod enabled but not found")
be296a
 elseif(NOT (LibElf_FOUND AND LibDwarf_FOUND) AND STERILE_BUILD)
be296a
   message(FATAL_ERROR "Elfutils not found and cannot be downloaded because build is sterile.")
be296a
 else()
be296a
7b9c5a
--- /dev/null
7b9c5a
+++ dyninst-10.2.1/dyninst-10.2.1/cmake/Modules/FindLibDebuginfod.cmake
be296a
@@ -0,0 +1,76 @@
be296a
+#========================================================================================
be296a
+# FindDebuginfod
be296a
+# -----------
be296a
+#
be296a
+# Find debuginfod library and headers
be296a
+#
be296a
+# The module defines the following variables:
be296a
+#
be296a
+# This module reads hints about search locations from variables::
be296a
+#
be296a
+#       LibDebuginfod_ROOT_DIR         - Base directory the of libdebuginfod installation
be296a
+#       LibDebuginfod_INCLUDEDIR       - Hint directory that contains the libdebuginfod headers files
be296a
+#       LibDebuginfod_LIBRARYDIR       - Hint directory that contains the libdebuginfod library files
be296a
+#
be296a
+# and saves search results persistently in CMake cache entries::
be296a
+#
be296a
+#       LibDebuginfod_FOUND            - True if headers and requested libraries were found
be296a
+#       LibDebuginfod_INCLUDE_DIRS     - libdebuginfod include directories
be296a
+#       LibDebuginfod_LIBRARY_DIRS     - Link directories for libdebuginfod libraries
be296a
+#       LibDebuginfod_LIBRARIES        - libdebuginfod library files
be296a
+#
be296a
+# Utilize package config (e.g. /usr/lib64/pkgconfig/libdebuginfod.pc) to fetch
be296a
+# version information.
be296a
+#
be296a
+#========================================================================================
be296a
+
be296a
+find_package(PkgConfig QUIET)
be296a
+pkg_check_modules(PC_Debuginfod QUIET REQUIRED libdebuginfod>=${ElfUtils_MIN_VERSION})
be296a
+set(LibDebuginfod_VERSION "${PC_Debuginfod_VERSION}")
be296a
+
be296a
+find_path(LibDebuginfod_INCLUDE_DIRS
be296a
+          NAMES
be296a
+            debuginfod.h
be296a
+          HINTS
be296a
+            ${PC_Debuginfod_INCLUDEDIR}
be296a
+            ${PC_Debuginfod_INCLUDE_DIRS}
be296a
+            ${LibDebuginfod_ROOT_DIR}/include
be296a
+            ${LibDebuginfod_ROOT_DIR}
be296a
+            ${LibDebuginfod_INCLUDEDIR}
be296a
+          PATHS
be296a
+            ${DYNINST_SYSTEM_INCLUDE_PATHS}
be296a
+          PATH_SUFFIXES
be296a
+            ${_path_suffixes}
be296a
+          DOC
be296a
+            "libdebuginfod include directories")
be296a
+
be296a
+find_library(LibDebuginfod_LIBRARIES
be296a
+             NAMES
be296a
+               libdebuginfod.so.1 libdebuginfod.so
be296a
+             HINTS
be296a
+               ${PC_Debuginfod_LIBDIR}
be296a
+               ${PC_Debuginfod_LIBRARY_DIRS}
be296a
+               ${LibDebuginfod_ROOT_DIR}/lib
be296a
+               ${LibDebuginfod_ROOT_DIR}
be296a
+               ${LibDebuginfod_LIBRARYDIR}
be296a
+             PATHS
be296a
+               ${DYNINST_SYSTEM_LIBRARY_PATHS}
be296a
+             PATH_SUFFIXES
be296a
+               ${_path_suffixes})
be296a
+
be296a
+include(FindPackageHandleStandardArgs)
be296a
+find_package_handle_standard_args(LibDebuginfod
be296a
+                                  FOUND_VAR
be296a
+                                    LibDebuginfod_FOUND
be296a
+                                  REQUIRED_VARS
be296a
+                                    LibDebuginfod_INCLUDE_DIRS
be296a
+                                    LibDebuginfod_LIBRARIES
be296a
+                                  VERSION_VAR
be296a
+                                    LibDebuginfod_VERSION)
be296a
+
be296a
+if(LibDebuginfod_FOUND)
be296a
+  set(LibDebuginfod_INCLUDE_DIRS ${LibDebuginfod_INCLUDE_DIRS})
be296a
+  set(LibDebuginfod_LIBRARIES ${LibDebuginfod_LIBRARIES})
be296a
+  get_filename_component(_debuginfod_dir ${LibDebuginfod_LIBRARIES} DIRECTORY)
be296a
+  set(LibDebuginfod_LIBRARY_DIRS ${_debuginfod_dir} "${_debuginfod_dir}/elfutils")
be296a
+endif()
be296a
be296a
--- dyninst-10.2.1/dyninst-10.2.1/cmake/options.cmake
be296a
+++ dyninst-10.2.1/dyninst-10.2.1/cmake/options.cmake
be296a
@@ -16,6 +16,8 @@ option(USE_COTIRE "Enable Cotire precompiled headers")
be296a
 
be296a
 option (ENABLE_LTO "Enable Link-Time Optimization" OFF)
be296a
 
be296a
+option(ENABLE_DEBUGINFOD "Enable debuginfod support" OFF)
be296a
+
be296a
 # Some global on/off switches
be296a
 if (LIGHTWEIGHT_SYMTAB)
be296a
 add_definitions (-DWITHOUT_SYMTAB_API -DWITH_SYMLITE)
be296a
be296a
--- dyninst-10.2.1/dyninst-10.2.1/elf/CMakeLists.txt
be296a
+++ dyninst-10.2.1/dyninst-10.2.1/elf/CMakeLists.txt
be296a
@@ -27,5 +27,8 @@ endif()
be296a
 add_dependencies(dynElf ElfUtils)
be296a
 target_link_private_libraries(dynElf ${ElfUtils_LIBRARIES})
be296a
 
be296a
+if (ENABLE_DEBUGINFOD AND LibDebuginfod_FOUND)
be296a
+  add_definitions(-DDEBUGINFOD_LIB)
be296a
+endif()
be296a
 
be296a
 add_definitions(-DDYNELF_LIB)
be296a
be296a
be296a
--- dyninst-10.2.1/dyninst-10.2.1/elf/src/Elf_X.C
be296a
+++ dyninst-10.2.1/dyninst-10.2.1/elf/src/Elf_X.C
be296a
@@ -47,6 +47,9 @@
be296a
 #include <sstream>
be296a
 #include <libelf.h>
be296a
 
be296a
+#if DEBUGINFOD_LIB
be296a
+#include <elfutils/debuginfod.h>
be296a
+#endif
be296a
 
be296a
 using namespace std;
be296a
 using boost::crc_32_type;
be296a
@@ -1722,37 +1725,79 @@ bool Elf_X::findDebugFile(std::string origfilename, string &output_name, char* &
be296a
      }
be296a
   }
be296a
 
be296a
-  if (debugFileFromDebugLink.empty())
be296a
-     return false;
be296a
+  if (!debugFileFromDebugLink.empty()) {
be296a
+     char *mfPathNameCopy = strdup(origfilename.c_str());
be296a
+     string objectFileDirName = dirname(mfPathNameCopy);
be296a
 
be296a
-  char *mfPathNameCopy = strdup(origfilename.c_str());
be296a
-  string objectFileDirName = dirname(mfPathNameCopy);
be296a
+     vector<string> fnames = list_of
be296a
+       (objectFileDirName + "/" + debugFileFromDebugLink)
be296a
+       (objectFileDirName + "/.debug/" + debugFileFromDebugLink)
be296a
+       ("/usr/lib/debug/" + objectFileDirName + "/" + debugFileFromDebugLink);
be296a
 
be296a
-  vector<string> fnames = list_of
be296a
-    (objectFileDirName + "/" + debugFileFromDebugLink)
be296a
-    (objectFileDirName + "/.debug/" + debugFileFromDebugLink)
be296a
-    ("/usr/lib/debug/" + objectFileDirName + "/" + debugFileFromDebugLink);
be296a
+     free(mfPathNameCopy);
be296a
 
be296a
-  free(mfPathNameCopy);
be296a
+     for(unsigned i = 0; i < fnames.size(); i++) {
be296a
+        bool result = loadDebugFileFromDisk(fnames[i], output_buffer, output_buffer_size);
be296a
+        if (!result)
be296a
+           continue;
be296a
 
be296a
-  for(unsigned i = 0; i < fnames.size(); i++) {
be296a
-     bool result = loadDebugFileFromDisk(fnames[i], output_buffer, output_buffer_size);
be296a
-     if (!result)
be296a
-        continue;
be296a
-    
be296a
-    boost::crc_32_type crcComputer;
be296a
-    crcComputer.process_bytes(output_buffer, output_buffer_size);
be296a
-    if(crcComputer.checksum() != debugFileCrc) {
be296a
-       munmap(output_buffer, output_buffer_size);
be296a
-       continue;
be296a
-    }
be296a
+        boost::crc_32_type crcComputer;
be296a
+        crcComputer.process_bytes(output_buffer, output_buffer_size);
be296a
+        if(crcComputer.checksum() != debugFileCrc) {
be296a
+           munmap(output_buffer, output_buffer_size);
be296a
+           continue;
be296a
+        }
be296a
+
be296a
+        output_name = fnames[i];
be296a
+        cached_debug_buffer = output_buffer;
be296a
+        cached_debug_size = output_buffer_size;
be296a
+        cached_debug_name = output_name;
be296a
+        return true;
be296a
+     }
be296a
+  }
be296a
 
be296a
-    output_name = fnames[i];
be296a
-    cached_debug_buffer = output_buffer;
be296a
-    cached_debug_size = output_buffer_size;
be296a
-    cached_debug_name = output_name;
be296a
-    return true;
be296a
+#ifdef DEBUGINFOD_LIB
be296a
+  if (!debugFileFromBuildID.empty()) {
be296a
+     // Given /usr/lib/debug/.buildid/XX/YYYYYY.debug, isolate XXYYYYYY.
be296a
+     size_t idx1 = debugFileFromBuildID.find_last_of("/");
be296a
+     size_t idx2 = debugFileFromBuildID.find_last_of(".");
be296a
+
be296a
+     if (idx1 == string::npos || idx2 == string::npos
be296a
+         || idx1 < 2 || idx1 > idx2)
be296a
+        return false;
be296a
+
be296a
+     idx1 -= 2;
be296a
+     string buildid(debugFileFromBuildID.substr(idx1, idx2 - idx1));
be296a
+     buildid.erase(2, 1);
be296a
+
be296a
+     debuginfod_client *client = debuginfod_begin();
be296a
+     if (client == NULL)
be296a
+        return false;
be296a
+
be296a
+     char *filename;
be296a
+     int fd = debuginfod_find_debuginfo(client,
be296a
+                                        (const unsigned char *)buildid.c_str(),
be296a
+                                        0, &filename);
be296a
+     debuginfod_end(client);
be296a
+
be296a
+     if (fd >= 0) {
be296a
+        string fname = string(filename);
be296a
+        free(filename);
be296a
+        close(fd);
be296a
+
be296a
+        bool result = loadDebugFileFromDisk(fname,
be296a
+                                            output_buffer,
be296a
+                                            output_buffer_size);
be296a
+        if (result) {
be296a
+           output_name = fname;
be296a
+           cached_debug_buffer = output_buffer;
be296a
+           cached_debug_size = output_buffer_size;
be296a
+           cached_debug_name = output_name;
be296a
+           return true;
be296a
+        }
be296a
+     }
be296a
   }
be296a
+#endif
be296a
 
be296a
   return false;
be296a
 }