From 8ddbf3b7f63db40ca2396e7a5eca7cdff2450b99 Mon Sep 17 00:00:00 2001 From: Andreas Ziegler Date: Thu, 29 Apr 2021 12:18:40 +0200 Subject: [PATCH] bcc_elf: add support for debug information from libdebuginfod This change adds debuginfod as a new source for debug information. By using libdebuginfod we can query a server for a file containing debug information for a given ELF binary. The environment variable DEBUGINFOD_URLS has to be defined to an URL for a debuginfod server providing debug information files for your distribution or the federating server provided by the elfutils project: For example, to use the Fedora server, you would need: $ export DEBUGINFOD_URLS="https://debuginfod.fedoraproject.org/" Or for the elfutils server which federates to servers for openSUSE, Void Linux, Debian and Fedora, among others: $ export DEBUGINFOD_URLS="https://debuginfod.elfutils.org/" Calls to the debuginfod_find_debuginfo function from libdebuginfod will fail if the environment variable is not set, otherwise the library will attempt to download debug information for a build ID extracted from the binary in question and store it in a local cache directory. Fixes iovisor/bpftrace#1774 Signed-off-by: Andreas Ziegler --- CMakeLists.txt | 1 + cmake/FindLibDebuginfod.cmake | 55 +++++++++++++++++++++++++++++++++++ src/cc/CMakeLists.txt | 6 ++++ src/cc/bcc_elf.c | 32 ++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 cmake/FindLibDebuginfod.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 720969147241..09707b1f5113 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ if(ENABLE_CLANG_JIT) find_package(BISON) find_package(FLEX) find_package(LibElf REQUIRED) +find_package(LibDebuginfod) if(CLANG_DIR) set(CMAKE_FIND_ROOT_PATH "${CLANG_DIR}") include_directories("${CLANG_DIR}/include") diff --git a/cmake/FindLibDebuginfod.cmake b/cmake/FindLibDebuginfod.cmake new file mode 100644 index 000000000000..df79ce92c705 --- /dev/null +++ b/cmake/FindLibDebuginfod.cmake @@ -0,0 +1,55 @@ +# - Try to find libdebuginfod +# Once done this will define +# +# LIBDEBUGINFOD_FOUND - system has libdebuginfod +# LIBDEBUGINFOD_INCLUDE_DIRS - the libdebuginfod include directory +# LIBDEBUGINFOD_LIBRARIES - Link these to use libdebuginfod +# LIBDEBUGINFOD_DEFINITIONS - Compiler switches required for using libdebuginfod + + +if (LIBDEBUGINFOD_LIBRARIES AND LIBDEBUGINFOD_INCLUDE_DIRS) + set (LibDebuginfod_FIND_QUIETLY TRUE) +endif (LIBDEBUGINFOD_LIBRARIES AND LIBDEBUGINFOD_INCLUDE_DIRS) + +find_path (LIBDEBUGINFOD_INCLUDE_DIRS + NAMES + elfutils/debuginfod.h + PATHS + /usr/include + /usr/include/libelf + /usr/include/elfutils + /usr/local/include + /usr/local/include/libelf + /usr/local/include/elfutils + /opt/local/include + /opt/local/include/libelf + /opt/local/include/elfutils + /sw/include + /sw/include/libelf + /sw/include/elfutils + ENV CPATH) + +find_library (LIBDEBUGINFOD_LIBRARIES + NAMES + debuginfod + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ENV LIBRARY_PATH + ENV LD_LIBRARY_PATH) + +include (FindPackageHandleStandardArgs) + + +# handle the QUIETLY and REQUIRED arguments and set LIBDEBUGINFOD_FOUND to TRUE if all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibDebuginfod DEFAULT_MSG + LIBDEBUGINFOD_LIBRARIES + LIBDEBUGINFOD_INCLUDE_DIRS) + +if (LIBDEBUGINFOD_FOUND) + add_definitions(-DHAVE_LIBDEBUGINFOD) +endif (LIBDEBUGINFOD_FOUND) + +mark_as_advanced(LIBDEBUGINFOD_INCLUDE_DIRS LIBDEBUGINFOD_LIBRARIES) diff --git a/src/cc/CMakeLists.txt b/src/cc/CMakeLists.txt index 931de2d9674c..09e5218b1a4e 100644 --- a/src/cc/CMakeLists.txt +++ b/src/cc/CMakeLists.txt @@ -9,6 +9,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frontends/b) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frontends/clang) include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LIBELF_INCLUDE_DIRS}) +if (LIBDEBUGINFOD_FOUND) + include_directories(${LIBDEBUGINFOD_INCLUDE_DIRS}) +endif (LIBDEBUGINFOD_FOUND) # todo: if check for kernel version if (CMAKE_USE_LIBBPF_PACKAGE AND LIBBPF_FOUND) include_directories(${LIBBPF_INCLUDE_DIRS}) @@ -116,6 +119,9 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${llvm_lib_exclude_f set(bcc_common_libs b_frontend clang_frontend -Wl,--whole-archive ${clang_libs} ${llvm_libs} -Wl,--no-whole-archive ${LIBELF_LIBRARIES}) +if (LIBDEBUGINFOD_FOUND) + list(APPEND bcc_common_libs ${LIBDEBUGINFOD_LIBRARIES}) +endif (LIBDEBUGINFOD_FOUND) set(bcc_common_libs_for_a ${bcc_common_libs}) set(bcc_common_libs_for_s ${bcc_common_libs}) set(bcc_common_libs_for_lua b_frontend clang_frontend diff --git a/src/cc/bcc_elf.c b/src/cc/bcc_elf.c index 7459bfa18b33..e2909d7c92d9 100644 --- a/src/cc/bcc_elf.c +++ b/src/cc/bcc_elf.c @@ -24,6 +24,9 @@ #include #include #include +#ifdef HAVE_LIBDEBUGINFOD +#include +#endif #include #include "bcc_elf.h" @@ -621,6 +624,31 @@ static char *find_debug_via_symfs(Elf *e, const char* path) { return result; } +#ifdef HAVE_LIBDEBUGINFOD +static char *find_debug_via_debuginfod(Elf *e){ + char buildid[128]; + char *debugpath = NULL; + int fd = -1; + + if (!find_buildid(e, buildid)) + return NULL; + + debuginfod_client *client = debuginfod_begin(); + if (!client) + return NULL; + + // In case of an error, the function returns a negative error code and + // debugpath stays NULL. + fd = debuginfod_find_debuginfo(client, (const unsigned char *) buildid, 0, + &debugpath); + if (fd >= 0) + close(fd); + + debuginfod_end(client); + return debugpath; +} +#endif + static char *find_debug_file(Elf* e, const char* path, int check_crc) { char *debug_file = NULL; @@ -635,6 +663,10 @@ static char *find_debug_file(Elf* e, const char* path, int check_crc) { debug_file = find_debug_via_buildid(e); if (!debug_file) debug_file = find_debug_via_debuglink(e, path, check_crc); +#ifdef HAVE_LIBDEBUGINFOD + if (!debug_file) + debug_file = find_debug_via_debuginfod(e); +#endif return debug_file; }