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