Blame SOURCES/dyninst-10.2.1-dbid.patch

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