1 //===-- llvm-debuginfod.cpp - federating debuginfod server ----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file contains the llvm-debuginfod tool, which serves the debuginfod 11 /// protocol over HTTP. The tool periodically scans zero or more filesystem 12 /// directories for ELF binaries to serve, and federates requests for unknown 13 /// build IDs to the debuginfod servers set in the DEBUGINFOD_URLS environment 14 /// variable. 15 /// 16 //===----------------------------------------------------------------------===// 17 18 #include "llvm/Debuginfod/Debuginfod.h" 19 #include "llvm/Debuginfod/HTTPClient.h" 20 #include "llvm/Support/CommandLine.h" 21 #include "llvm/Support/InitLLVM.h" 22 #include "llvm/Support/ThreadPool.h" 23 24 using namespace llvm; 25 26 cl::OptionCategory DebuginfodCategory("llvm-debuginfod Options"); 27 28 static cl::list<std::string> ScanPaths(cl::Positional, 29 cl::desc("<Directories to scan>"), 30 cl::cat(DebuginfodCategory)); 31 32 static cl::opt<unsigned> 33 Port("p", cl::init(0), 34 cl::desc("Port to listen on. Set to 0 to bind to any available port."), 35 cl::cat(DebuginfodCategory)); 36 37 static cl::opt<std::string> 38 HostInterface("i", cl::init("0.0.0.0"), 39 cl::desc("Host interface to bind to."), 40 cl::cat(DebuginfodCategory)); 41 42 static cl::opt<int> 43 ScanInterval("t", cl::init(300), 44 cl::desc("Number of seconds to wait between subsequent " 45 "automated scans of the filesystem."), 46 cl::cat(DebuginfodCategory)); 47 48 static cl::opt<double> MinInterval( 49 "m", cl::init(10), 50 cl::desc( 51 "Minimum number of seconds to wait before an on-demand update can be " 52 "triggered by a request for a buildid which is not in the collection."), 53 cl::cat(DebuginfodCategory)); 54 55 static cl::opt<size_t> 56 MaxConcurrency("c", cl::init(0), 57 cl::desc("Maximum number of files to scan concurrently. If " 58 "0, use the hardware concurrency."), 59 cl::cat(DebuginfodCategory)); 60 61 static cl::opt<bool> VerboseLogging("v", cl::init(false), 62 cl::desc("Enable verbose logging."), 63 cl::cat(DebuginfodCategory)); 64 65 ExitOnError ExitOnErr; 66 67 int main(int argc, char **argv) { 68 InitLLVM X(argc, argv); 69 HTTPClient::initialize(); 70 cl::HideUnrelatedOptions({&DebuginfodCategory}); 71 cl::ParseCommandLineOptions(argc, argv); 72 73 SmallVector<StringRef, 1> Paths; 74 for (const std::string &Path : ScanPaths) 75 Paths.push_back(Path); 76 77 ThreadPool Pool(hardware_concurrency(MaxConcurrency)); 78 DebuginfodLog Log; 79 DebuginfodCollection Collection(Paths, Log, Pool, MinInterval); 80 DebuginfodServer Server(Log, Collection); 81 82 if (!Port) 83 Port = ExitOnErr(Server.Server.bind(HostInterface.c_str())); 84 else 85 ExitOnErr(Server.Server.bind(Port, HostInterface.c_str())); 86 87 Log.push("Listening on port " + Twine(Port).str()); 88 89 Pool.async([&]() { ExitOnErr(Server.Server.listen()); }); 90 Pool.async([&]() { 91 while (true) { 92 DebuginfodLogEntry Entry = Log.pop(); 93 if (VerboseLogging) { 94 outs() << Entry.Message << "\n"; 95 outs().flush(); 96 } 97 } 98 }); 99 if (Paths.size()) 100 ExitOnErr(Collection.updateForever(std::chrono::seconds(ScanInterval))); 101 Pool.wait(); 102 llvm_unreachable("The ThreadPool should never finish running its tasks."); 103 } 104