Index: llvm/lib/DebugInfo/Symbolize/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/Symbolize/CMakeLists.txt +++ llvm/lib/DebugInfo/Symbolize/CMakeLists.txt @@ -9,6 +9,7 @@ LINK_COMPONENTS DebugInfoDWARF DebugInfoPDB + Debuginfod Object Support Demangle Index: llvm/lib/DebugInfo/Symbolize/Symbolize.cpp =================================================================== --- llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -20,6 +20,7 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBContext.h" +#include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Object/COFF.h" #include "llvm/Object/MachO.h" @@ -384,7 +385,14 @@ } } } - return false; + // Try debuginfod client cache and known servers. + Expected PathOrErr = getCachedOrDownloadDebuginfo(BuildID); + if (!PathOrErr) { + consumeError(PathOrErr.takeError()); + return false; + } + Result = *PathOrErr; + return true; } } // end anonymous namespace Index: llvm/test/lit.cfg.py =================================================================== --- llvm/test/lit.cfg.py +++ llvm/test/lit.cfg.py @@ -394,6 +394,9 @@ if config.have_libxml2: config.available_features.add('libxml2') +if config.have_curl: + config.available_features.add('curl') + if config.have_opt_viewer_modules: config.available_features.add('have_opt_viewer_modules') Index: llvm/test/lit.site.cfg.py.in =================================================================== --- llvm/test/lit.site.cfg.py.in +++ llvm/test/lit.site.cfg.py.in @@ -39,6 +39,7 @@ config.have_zlib = @LLVM_ENABLE_ZLIB@ config.have_libxar = @LLVM_HAVE_LIBXAR@ config.have_libxml2 = @LLVM_ENABLE_LIBXML2@ +config.have_curl = @LLVM_ENABLE_CURL@ config.have_dia_sdk = @LLVM_ENABLE_DIA_SDK@ config.enable_ffi = @LLVM_ENABLE_FFI@ config.build_examples = @LLVM_BUILD_EXAMPLES@ Index: llvm/test/tools/llvm-symbolizer/debuginfod-cache.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-symbolizer/debuginfod-cache.test @@ -0,0 +1,20 @@ +# This test uses the local cache only and does not require Curl. +RUN: rm -rf %t +RUN: mkdir %t +RUN: llvm-objcopy --strip-debug %p/Inputs/addr.exe %t/addr.exe +RUN: mkdir -p %t/buildid/127da749021c1fc1a58cba734a1f542cbe2b7ce4/ +# Symbolizing a stripped binary should fail. +RUN: DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d | FileCheck %s --check-prefix=NOTFOUND +NOTFOUND: 0x40054d +NOTFOUND: main +NOTFOUND: ??:0:0 + +RUN: llvm-objcopy --keep-section=.debug_info %p/Inputs/addr.exe \ +RUN: %t/llvmcache-9800707741016212219 + +# Should find debuginfo in the cache: +RUN: DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d | FileCheck %s --check-prefix=FOUND +FOUND: 0x40054d +FOUND: {{[/\]+}}tmp{{[/\]+}}x.c:14:0 Index: llvm/test/tools/llvm-symbolizer/debuginfod.py =================================================================== --- /dev/null +++ llvm/test/tools/llvm-symbolizer/debuginfod.py @@ -0,0 +1,48 @@ +# This script is used to test the debuginfod client functionality of the symbolizer. +# It first stands up a Python HTTP static file server and then executes the client. +# This way the client can make debuginfod HTTP requests to the static file server. +import argparse +import threading +import http.server +import functools +import subprocess +import sys +import os + + +# Serves files at the server_path, then runs the tool with specified args. +# Sets the DEBUGINFOD_CACHE_PATH env var to point at the given cache_directory. +# Sets the DEBUGINFOD_URLS env var to point at the local server. +def test_tool(server_path, cache_directory, tool_args): + httpd = http.server.ThreadingHTTPServer( + ('',0), functools.partial( + http.server.SimpleHTTPRequestHandler, + directory=server_path)) + port = httpd.server_port + thread = threading.Thread(target=httpd.serve_forever) + try: + thread.start() + process = subprocess.Popen( + tool_args, env={**os.environ, + 'DEBUGINFOD_URLS': f'http://localhost:{port}', + 'DEBUGINFOD_CACHE_PATH': cache_directory}) + if process.wait() != 0: + print('process returned nontrivial error code') + return 1 + finally: + httpd.shutdown() + thread.join() + return 0 + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--server-path', default='./') + parser.add_argument('--cache-directory', default='./') + parser.add_argument('--tool-cmd', required=True, type=str) + args = parser.parse_args() + result = test_tool(args.server_path, args.cache_directory, + args.tool_cmd.split()) + sys.exit(result) + +if __name__ == '__main__': + main() Index: llvm/test/tools/llvm-symbolizer/debuginfod.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-symbolizer/debuginfod.test @@ -0,0 +1,35 @@ +REQUIRES: curl +# Uses source program from llvm/test/tools/llvm-symbolizer/split-debug.test +RUN: rm -rf %t +RUN: mkdir %t +RUN: llvm-objcopy --strip-debug %p/Inputs/addr.exe %t/addr.exe +RUN: mkdir -p %t/buildid/127da749021c1fc1a58cba734a1f542cbe2b7ce4/ +# Symbolizing a stripped binary should fail. +RUN: DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d | FileCheck %s --check-prefix=NOTFOUND +NOTFOUND: 0x40054d +NOTFOUND: main +NOTFOUND: ??:0:0 + +# debuginfod.py stands up a debuginfod server and sets the DEBUGINFOD_URLS +# before running llvm-symbolizer +# Now it should symbolize successfully. +RUN: llvm-objcopy --keep-section=.debug_info %p/Inputs/addr.exe \ +RUN: %t/buildid/127da749021c1fc1a58cba734a1f542cbe2b7ce4/debuginfo +RUN: DEBUGINFOD_CACHE_PATH=%t python %S/debuginfod.py --server-path %t \ +RUN: --cache-directory %t --tool-cmd 'llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d' | FileCheck %s --check-prefix=FOUND +FOUND: 0x40054d +FOUND: {{[/\]+}}tmp{{[/\]+}}x.c:14:0 + +# Should still find debuginfo in the cache: +RUN: DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d | FileCheck %s --check-prefix=FOUND +RUN: rm %t/buildid/127da749021c1fc1a58cba734a1f542cbe2b7ce4/debuginfo +RUN: DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d | FileCheck %s --check-prefix=FOUND + +# Delete the cache, should not find debuginfo: +RUN: rm %t/llvmcache* +RUN: DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer --print-address \ +RUN: --obj=%t/addr.exe 0x40054d | FileCheck %s --check-prefix=NOTFOUND