Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[llvm] [Debuginfo] Add llvm-debuginfod-find tool and end-to-end-tests.
This implements the `llvm-debuginfod-find` tool, which wraps the Debuginfod library (D112758) to query debuginfod servers for artifacts according to the [[ https://www.mankier.com/8/debuginfod#Webapi | specification ]]. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D112759
- Loading branch information
Showing
9 changed files
with
198 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
llvm/test/tools/llvm-debuginfod-find/Inputs/buildid/abcdef/debuginfo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
fake_debuginfo |
1 change: 1 addition & 0 deletions
1
llvm/test/tools/llvm-debuginfod-find/Inputs/buildid/abcdef/executable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
fake_executable |
1 change: 1 addition & 0 deletions
1
llvm/test/tools/llvm-debuginfod-find/Inputs/buildid/abcdef/source/directory/file.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
int foo = 0; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# REQUIRES: curl | ||
# RUN: rm -rf %t | ||
# RUN: mkdir %t | ||
# # Query the python server for artifacts | ||
# RUN: DEBUGINFOD_CACHE_PATH=%t python %s --server-path %S/Inputs \ | ||
# RUN: --tool-cmd 'llvm-debuginfod-find --dump --executable abcdef' | \ | ||
# RUN: FileCheck %s --check-prefix=EXECUTABLE | ||
# RUN: DEBUGINFOD_CACHE_PATH=%t python %s --server-path %S/Inputs \ | ||
# RUN: --tool-cmd 'llvm-debuginfod-find --dump --source=/directory/file.c abcdef' | \ | ||
# RUN: FileCheck %s --check-prefix=SOURCE | ||
# RUN: DEBUGINFOD_CACHE_PATH=%t python %s --server-path %S/Inputs \ | ||
# RUN: --tool-cmd 'llvm-debuginfod-find --dump --debuginfo abcdef' | \ | ||
# RUN: FileCheck %s --check-prefix=DEBUGINFO | ||
|
||
# EXECUTABLE: fake_executable | ||
# SOURCE: int foo = 0; | ||
# DEBUGINFO: fake_debuginfo | ||
|
||
# # The artifacts should still be present in the cache without needing to query | ||
# # the server. | ||
# RUN: DEBUGINFOD_CACHE_PATH=%t llvm-debuginfod-find --dump --executable abcdef | \ | ||
# RUN: FileCheck %s --check-prefix=EXECUTABLE | ||
# RUN: DEBUGINFOD_CACHE_PATH=%t llvm-debuginfod-find --dump \ | ||
# RUN: --source=/directory/file.c abcdef | \ | ||
# RUN: FileCheck %s --check-prefix=SOURCE | ||
# RUN: DEBUGINFOD_CACHE_PATH=%t llvm-debuginfod-find --dump --debuginfo abcdef | \ | ||
# RUN: FileCheck %s --check-prefix=DEBUGINFO | ||
|
||
|
||
# This script is used to test the debuginfod client within a host tool. | ||
# It first stands up a Python HTTP static file server and then executes the tool. | ||
# This way the tool 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, 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}'}) | ||
code = process.wait() | ||
if code != 0: | ||
print(f'nontrivial return code {code}') | ||
return 1 | ||
finally: | ||
httpd.shutdown() | ||
thread.join() | ||
return 0 | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('--server-path', default='./') | ||
parser.add_argument('--tool-cmd', required=True, type=str) | ||
args = parser.parse_args() | ||
result = test_tool(args.server_path, | ||
args.tool_cmd.split()) | ||
sys.exit(result) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
set(LLVM_LINK_COMPONENTS | ||
Debuginfod | ||
Support | ||
) | ||
add_llvm_tool(llvm-debuginfod-find | ||
llvm-debuginfod-find.cpp | ||
) | ||
if(LLVM_INSTALL_BINUTILS_SYMLINKS) | ||
add_llvm_tool_symlink(debuginfod-find llvm-debuginfod-find) | ||
endif() |
101 changes: 101 additions & 0 deletions
101
llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
//===-- llvm-debuginfod-find.cpp - Simple CLI for libdebuginfod-client ----===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
/// | ||
/// \file | ||
/// This file contains the llvm-debuginfod-find tool. This tool | ||
/// queries the debuginfod servers in the DEBUGINFOD_URLS environment | ||
/// variable (delimited by space (" ")) for the executable, | ||
/// debuginfo, or specified source file of the binary matching the | ||
/// given build-id. | ||
/// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/Debuginfod/Debuginfod.h" | ||
#include "llvm/Debuginfod/HTTPClient.h" | ||
#include "llvm/Support/CommandLine.h" | ||
#include "llvm/Support/InitLLVM.h" | ||
|
||
using namespace llvm; | ||
|
||
cl::opt<std::string> InputBuildID(cl::Positional, cl::Required, | ||
cl::desc("<input build_id>"), cl::init("-")); | ||
|
||
static cl::opt<bool> | ||
FetchExecutable("executable", cl::init(false), | ||
cl::desc("If set, fetch a binary file associated with this " | ||
"build id, containing the executable sections.")); | ||
|
||
static cl::opt<bool> | ||
FetchDebuginfo("debuginfo", cl::init(false), | ||
cl::desc("If set, fetch a binary file associated with this " | ||
"build id, containing the debuginfo sections.")); | ||
|
||
static cl::opt<std::string> FetchSource( | ||
"source", cl::init(""), | ||
cl::desc("Fetch a source file associated with this build id, which is at " | ||
"this relative path relative to the compilation directory.")); | ||
|
||
static cl::opt<bool> | ||
DumpToStdout("dump", cl::init(false), | ||
cl::desc("If set, dumps the contents of the fetched artifact " | ||
"to standard output. Otherwise, dumps the absolute " | ||
"path to the cached artifact on disk.")); | ||
|
||
[[noreturn]] static void helpExit() { | ||
errs() << "Must specify exactly one of --executable, " | ||
"--source=/path/to/file, or --debuginfo."; | ||
exit(1); | ||
} | ||
|
||
ExitOnError ExitOnErr; | ||
|
||
int main(int argc, char **argv) { | ||
InitLLVM X(argc, argv); | ||
HTTPClient::initialize(); | ||
|
||
cl::ParseCommandLineOptions( | ||
argc, argv, | ||
"llvm-debuginfod-find: Fetch debuginfod artifacts\n\n" | ||
"This program is a frontend to the debuginfod client library. The cache " | ||
"directory, request timeout (in seconds), and debuginfod server urls are " | ||
"set by these environment variables:\n" | ||
"DEBUGINFOD_CACHE_PATH (default set by sys::path::cache_directory)\n" | ||
"DEBUGINFOD_TIMEOUT (defaults to 90s)\n" | ||
"DEBUGINFOD_URLS=[comma separated URLs] (defaults to empty)\n"); | ||
|
||
if (FetchExecutable + FetchDebuginfo + (FetchSource != "") != 1) | ||
helpExit(); | ||
|
||
std::string IDString; | ||
if (!tryGetFromHex(InputBuildID, IDString)) { | ||
errs() << "Build ID " << InputBuildID << " is not a hex string.\n"; | ||
exit(1); | ||
} | ||
BuildID ID(IDString.begin(), IDString.end()); | ||
|
||
std::string Path; | ||
if (FetchSource != "") | ||
Path = ExitOnErr(getCachedOrDownloadSource(ID, FetchSource)); | ||
else if (FetchExecutable) | ||
Path = ExitOnErr(getCachedOrDownloadExecutable(ID)); | ||
else if (FetchDebuginfo) | ||
Path = ExitOnErr(getCachedOrDownloadDebuginfo(ID)); | ||
else | ||
llvm_unreachable("We have already checked that exactly one of the above " | ||
"conditions is true."); | ||
|
||
if (DumpToStdout) { | ||
// Print the contents of the artifact. | ||
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile( | ||
Path, /*IsText=*/false, /*RequiresNullTerminator=*/false); | ||
ExitOnErr(errorCodeToError(Buf.getError())); | ||
outs() << Buf.get()->getBuffer(); | ||
} else | ||
// Print the path to the cached artifact file. | ||
outs() << Path << "\n"; | ||
} |