Blame SOURCES/dyninst-10.2.1-dbid.patch

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