Blame SOURCES/dyninst-10.2.1-dbid.patch

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