Blame SOURCES/dyninst-10.2.1-dbid.patch

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