55 return llvm::toHex(
ID,
true);
63 const char *DebuginfodUrlsEnv = std::getenv(
"DEBUGINFOD_URLS");
64 if (DebuginfodUrlsEnv ==
nullptr)
69 return DebuginfodUrls;
75 if (
const char *CacheDirectoryEnv = std::getenv(
"DEBUGINFOD_CACHE_PATH"))
76 return CacheDirectoryEnv;
81 errc::io_error,
"Unable to determine appropriate cache directory.");
83 return std::string(CacheDirectory);
88 const char *DebuginfodTimeoutEnv = std::getenv(
"DEBUGINFOD_TIMEOUT");
89 if (DebuginfodTimeoutEnv &&
90 to_integer(
StringRef(DebuginfodTimeoutEnv).trim(), Timeout, 10))
91 return std::chrono::milliseconds(Timeout * 1000);
93 return std::chrono::milliseconds(90 * 1000);
131 CacheDir = *CacheDirOrErr;
142class StreamedHTTPResponseHandler :
public HTTPResponseHandler {
143 using CreateStreamFn =
144 std::function<Expected<std::unique_ptr<CachedFileStream>>()>;
145 CreateStreamFn CreateStream;
147 std::unique_ptr<CachedFileStream> FileStream;
150 StreamedHTTPResponseHandler(CreateStreamFn CreateStream, HTTPClient &Client)
151 : CreateStream(CreateStream), Client(Client) {}
152 virtual ~StreamedHTTPResponseHandler() =
default;
154 Error handleBodyChunk(StringRef BodyChunk)
override;
159Error StreamedHTTPResponseHandler::handleBodyChunk(StringRef BodyChunk) {
161 unsigned Code = Client.responseCode();
162 if (Code && Code != 200)
164 Expected<std::unique_ptr<CachedFileStream>> FileStreamOrError =
166 if (!FileStreamOrError)
167 return FileStreamOrError.takeError();
168 FileStream = std::move(*FileStreamOrError);
170 *FileStream->OS << BodyChunk;
181 return all_of(
Name, [](
char C) {
return llvm::isPrint(
C) &&
C !=
' '; }) &&
182 all_of(
Value, [](
char C) {
return llvm::isPrint(
C) ||
C ==
'\t'; });
186 const char *Filename = getenv(
"DEBUGINFOD_HEADERS_FILE");
196 for (
StringRef Line : llvm::split((*HeadersFile)->getBuffer(),
'\n')) {
198 if (!Line.empty() && Line.back() ==
'\r')
199 Line = Line.drop_back();
201 if (!
all_of(Line, llvm::isSpace))
203 <<
"could not parse debuginfod header: " << Filename <<
':'
204 << LineNumber <<
'\n';
217 "llvmcache-" + UniqueKey);
220 localCache(
"Debuginfod-client",
".debuginfod-client", CacheDirectoryPath);
228 if (!CacheAddStreamOrErr)
230 AddStreamFn &CacheAddStream = *CacheAddStreamOrErr;
232 return std::string(AbsCachedArtifactPath);
237 "No working HTTP client is available.");
242 "A working HTTP client is available, but it is not initialized. To "
243 "allow Debuginfod to make HTTP requests, call HTTPClient::initialize() "
244 "at the beginning of main.");
248 for (
StringRef ServerUrl : DebuginfodUrls) {
255 StreamedHTTPResponseHandler Handler(
256 [&]() {
return CacheAddStream(Task,
""); }, Client);
261 return std::move(Err);
264 if (Code && Code != 200)
270 if (!PruningPolicyOrErr)
272 pruneCache(CacheDirectoryPath, *PruningPolicyOrErr);
275 return std::string(AbsCachedArtifactPath);
282 : Message(Message.str()) {}
290 std::lock_guard<std::mutex> Guard(QueueMutex);
291 LogEntryQueue.push(Entry);
293 QueueCondition.notify_one();
298 std::unique_lock<std::mutex> Guard(QueueMutex);
300 QueueCondition.wait(Guard, [&] {
return !LogEntryQueue.empty(); });
302 std::lock_guard<std::mutex> Guard(QueueMutex);
303 if (!LogEntryQueue.size())
314 : Log(Log), Pool(Pool), MinInterval(MinInterval) {
320 std::lock_guard<sys::Mutex> Guard(UpdateMutex);
324 for (
const std::string &Path : Paths) {
325 Log.
push(
"Updating binaries at path " + Path);
326 if (
Error Err = findBinaries(Path))
329 Log.
push(
"Updated collection");
340 if (Time < MinInterval)
343 return std::move(Err);
351 std::this_thread::sleep_for(
Interval);
373Error DebuginfodCollection::findBinaries(StringRef Path) {
375 sys::fs::recursive_directory_iterator
I(Twine(Path), EC),
E;
376 std::mutex IteratorMutex;
377 ThreadPoolTaskGroup IteratorGroup(Pool);
378 for (
unsigned WorkerIndex = 0; WorkerIndex < Pool.
getThreadCount();
380 IteratorGroup.async([&,
this]() ->
void {
381 std::string FilePath;
385 std::lock_guard<std::mutex> Guard(IteratorMutex);
390 FilePath =
I->path();
398 Expected<object::OwningBinary<object::Binary>> BinOrErr =
405 object::Binary *
Bin = std::move(BinOrErr.get().getBinary());
406 if (!
Bin->isObject())
410 object::ELFObjectFileBase *
Object =
411 dyn_cast<object::ELFObjectFileBase>(
Bin);
420 if (
Object->hasDebugInfo()) {
421 std::lock_guard<sys::RWMutex> DebugBinariesGuard(DebugBinariesMutex);
422 (void)DebugBinaries.
try_emplace(IDString, std::move(FilePath));
424 std::lock_guard<sys::RWMutex> BinariesGuard(BinariesMutex);
425 (void)Binaries.
try_emplace(IDString, std::move(FilePath));
430 IteratorGroup.wait();
431 std::unique_lock<std::mutex> Guard(IteratorMutex);
437Expected<std::optional<std::string>>
438DebuginfodCollection::getBinaryPath(BuildIDRef
ID) {
440 std::shared_lock<sys::RWMutex> Guard(BinariesMutex);
442 if (Loc != Binaries.
end()) {
443 std::string
Path = Loc->getValue();
449Expected<std::optional<std::string>>
450DebuginfodCollection::getDebugBinaryPath(BuildIDRef
ID) {
452 std::shared_lock<sys::RWMutex> Guard(DebugBinariesMutex);
454 if (Loc != DebugBinaries.
end()) {
455 std::string
Path = Loc->getValue();
467 std::optional<std::string> Path = *PathOrErr;
474 PathOrErr = getBinaryPath(
ID);
498 std::optional<std::string> Path = *PathOrErr;
505 PathOrErr = getBinaryPath(
ID);
520 : Log(Log), Collection(Collection) {
523 Log.push("GET " + Request.UrlPath);
524 std::string IDString;
525 if (!tryGetFromHex(Request.UrlPathMatches[0], IDString)) {
527 {404,
"text/plain",
"Build ID is not a hex string\n"});
532 if (
Error Err = PathOrErr.takeError()) {
533 consumeError(std::move(Err));
534 Request.setResponse({404,
"text/plain",
"Build ID not found\n"});
540 Server.get(R
"(/buildid/(.*)/executable)", [&](HTTPServerRequest Request) {
541 Log.push("GET " + Request.UrlPath);
542 std::string IDString;
543 if (!tryGetFromHex(Request.UrlPathMatches[0], IDString)) {
545 {404,
"text/plain",
"Build ID is not a hex string\n"});
548 object::BuildID ID(IDString.begin(), IDString.end());
549 Expected<std::string> PathOrErr = Collection.findBinaryPath(ID);
550 if (Error Err = PathOrErr.takeError()) {
551 consumeError(std::move(Err));
552 Request.setResponse({404,
"text/plain",
"Build ID not found\n"});
This file declares a library for handling Build IDs and using them to find debug info.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains several declarations for the debuginfod client and server.
This file contains the declarations of the HTTPClient library for issuing HTTP requests and handling ...
Tracks a collection of debuginfod artifacts on the local filesystem.
DebuginfodCollection(ArrayRef< StringRef > Paths, DebuginfodLog &Log, ThreadPool &Pool, double MinInterval)
Expected< std::string > findBinaryPath(object::BuildIDRef)
Error updateForever(std::chrono::milliseconds Interval)
Expected< std::string > findDebugBinaryPath(object::BuildIDRef)
void push(DebuginfodLogEntry Entry)
Represents either an error or a value T.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
A reusable client that can perform HTTPRequests through a network socket.
static bool isAvailable()
Returns true only if LLVM has been compiled with a working HTTPClient.
static bool IsInitialized
unsigned responseCode()
Returns the last received response code or zero if none.
Error perform(const HTTPRequest &Request, HTTPResponseHandler &Handler)
Performs the Request, passing response data to the Handler.
void setTimeout(std::chrono::milliseconds Timeout)
Sets the timeout for the entire request, in milliseconds.
Error get(StringRef UrlPathPattern, HTTPRequestHandler Handler)
Registers a URL pattern routing rule.
Interval Class - An Interval is a set of nodes defined such that every node in the interval has all o...
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
iterator find(StringRef Key)
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
A ThreadPool for asynchronous parallel execution on a defined number of threads.
unsigned getThreadCount() const
double getWallTime() const
bool isRunning() const
Check if the timer is currently running.
void stopTimer()
Stop the timer.
void clear()
Clear the timer state.
void startTimer()
Start the timer running.
TimeRecord getTotalTime() const
Return the duration for which this timer has been running.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
static raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
std::optional< BuildIDRef > getBuildID(const ObjectFile *Obj)
Returns the build ID, if any, contained in the given object file.
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
bool cache_directory(SmallVectorImpl< char > &result)
Get the directory where installed packages should put their machine-local cache, e....
std::string convert_to_slash(StringRef path, Style style=Style::native)
Replaces backslashes with slashes if Windows.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
This is an optimization pass for GlobalISel generic memory operations.
file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
static std::string uniqueKey(llvm::StringRef S)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Expected< std::string > getCachedOrDownloadExecutable(object::BuildIDRef ID)
Fetches an executable by searching the default local cache directory and server URLs.
static bool isHeader(StringRef S)
SmallVector< StringRef > getDefaultDebuginfodUrls()
Finds default array of Debuginfod server URLs by checking DEBUGINFOD_URLS environment variable.
std::function< Expected< std::unique_ptr< CachedFileStream > >(unsigned Task, const Twine &ModuleName)> AddStreamFn
This type defines the callback to add a file that is generated on the fly.
Expected< std::string > getCachedOrDownloadDebuginfo(object::BuildIDRef ID)
Fetches a debug binary by searching the default local cache directory and server URLs.
static std::string buildIDToString(BuildIDRef ID)
Expected< CachePruningPolicy > parseCachePruningPolicy(StringRef PolicyStr)
Parse the given string as a cache pruning policy.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Expected< std::string > getCachedOrDownloadArtifact(StringRef UniqueKey, StringRef UrlPath)
Fetches any debuginfod artifact using the default local cache directory and server URLs.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Expected< std::string > getCachedOrDownloadSource(object::BuildIDRef ID, StringRef SourceFilePath)
Fetches a specified source file by searching the default local cache directory and server URLs.
bool pruneCache(StringRef Path, CachePruningPolicy Policy, const std::vector< std::unique_ptr< MemoryBuffer > > &Files={})
Peform pruning using the supplied policy, returns true if pruning occurred, i.e.
std::chrono::milliseconds getDefaultDebuginfodTimeout()
Finds a default timeout for debuginfod HTTP requests.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
static bool hasELFMagic(StringRef FilePath)
bool streamFile(HTTPServerRequest &Request, StringRef FilePath)
Sets the response to stream the file at FilePath, if available, and otherwise an HTTP 404 error respo...
static SmallVector< std::string, 0 > getHeaders()
std::function< Expected< AddStreamFn >(unsigned Task, StringRef Key, const Twine &ModuleName)> FileCache
This is the type of a file cache.
void consumeError(Error Err)
Consume a Error without doing anything.
Expected< FileCache > localCache(const Twine &CacheNameRef, const Twine &TempFilePrefixRef, const Twine &CacheDirectoryPathRef, AddBufferFn AddBuffer=[](size_t Task, const Twine &ModuleName, std::unique_ptr< MemoryBuffer > MB) {})
Create a local file system cache which uses the given cache name, temporary file prefix,...
bool canUseDebuginfod()
Returns false if a debuginfod lookup can be determined to have no chance of succeeding.
Expected< std::string > getDefaultDebuginfodCacheDirectory()
Finds a default local file caching directory for the debuginfod client, first checking DEBUGINFOD_CAC...
uint64_t xxHash64(llvm::StringRef Data)
DebuginfodLogEntry()=default
DebuginfodServer(DebuginfodLog &Log, DebuginfodCollection &Collection)
DebuginfodCollection & Collection
A stateless description of an outbound HTTP request.
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
@ elf_relocatable
ELF Relocatable object file.
@ elf_shared_object
ELF dynamically linked shared lib.
@ elf_executable
ELF Executable image.
@ elf_core
ELF core image.