LLVM: lib/Debuginfod/Debuginfod.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
42
43#include
44#include
45#include
46
47namespace llvm {
48
50
51namespace {
52std::optional<SmallVector> DebuginfodUrls;
53
55}
56
60
61
62
66
70
72 std::shared_lockllvm::sys::RWMutex ReadGuard(UrlsMutex);
73 if (!DebuginfodUrls) {
74
75
76 ReadGuard.unlock();
77 std::unique_lockllvm::sys::RWMutex WriteGuard(UrlsMutex);
79 if (const char *DebuginfodUrlsEnv = std::getenv("DEBUGINFOD_URLS")) {
81 .split(DebuginfodUrls.value(), " ", -1, false);
82 }
83 WriteGuard.unlock();
84 ReadGuard.lock();
85 }
86 return DebuginfodUrls.value();
87}
88
89
91 std::unique_lockllvm::sys::RWMutex WriteGuard(UrlsMutex);
92 DebuginfodUrls = URLs;
93}
94
95
96
98 if (const char *CacheDirectoryEnv = std::getenv("DEBUGINFOD_CACHE_PATH"))
99 return CacheDirectoryEnv;
100
104 errc::io_error, "Unable to determine appropriate cache directory.");
106 return std::string(CacheDirectory);
107}
108
111 const char *DebuginfodTimeoutEnv = std::getenv("DEBUGINFOD_TIMEOUT");
112 if (DebuginfodTimeoutEnv &&
114 return std::chrono::milliseconds(Timeout * 1000);
115
116 return std::chrono::milliseconds(90 * 1000);
117}
118
119
120
121
122
129 return std::string(UrlPath);
130}
131
137
142 return std::string(UrlPath);
143}
144
149
154 return std::string(UrlPath);
155}
156
161
162
166
168 if (!CacheDirOrErr)
169 return CacheDirOrErr.takeError();
170 CacheDir = *CacheDirOrErr;
171
175}
176
177namespace {
178
179
180
181class StreamedHTTPResponseHandler : public HTTPResponseHandler {
182 using CreateStreamFn =
183 std::function<Expected<std::unique_ptr>()>;
184 CreateStreamFn CreateStream;
185 HTTPClient &Client;
186 std::unique_ptr FileStream;
187
188public:
189 StreamedHTTPResponseHandler(CreateStreamFn CreateStream, HTTPClient &Client)
190 : CreateStream(CreateStream), Client(Client) {}
191
192
193
195
196 virtual ~StreamedHTTPResponseHandler() = default;
197
198 Error handleBodyChunk(StringRef BodyChunk) override;
199};
200
201}
202
203Error StreamedHTTPResponseHandler::handleBodyChunk(StringRef BodyChunk) {
204 if (!FileStream) {
206 if (Code && Code != 200)
207 return Error::success();
208 Expected<std::unique_ptr> FileStreamOrError =
209 CreateStream();
210 if (!FileStreamOrError)
211 return FileStreamOrError.takeError();
212 FileStream = std::move(*FileStreamOrError);
213 }
214 *FileStream->OS << BodyChunk;
215 return Error::success();
216}
217
218Error StreamedHTTPResponseHandler::commit() {
219 if (FileStream)
220 return FileStream->commit();
221 return Error::success();
222}
223
224
228 std::tie(Name, Value) = S.split(':');
229 if (Name.empty() || Value.empty())
230 return false;
233}
234
236 const char *Filename = getenv("DEBUGINFOD_HEADERS_FILE");
237 if (!Filename)
238 return {};
241 if (!HeadersFile)
242 return {};
243
247 LineNumber++;
248 Line.consume_back("\r");
252 << "could not parse debuginfod header: " << Filename << ':'
253 << LineNumber << '\n';
254 continue;
255 }
257 }
258 return Headers;
259}
260
266 "llvmcache-" + UniqueKey);
267
269 localCache("Debuginfod-client", ".debuginfod-client", CacheDirectoryPath);
270 if (!CacheOrErr)
272
274
275 unsigned Task = 0;
277 if (!CacheAddStreamOrErr)
278 return CacheAddStreamOrErr.takeError();
279 AddStreamFn &CacheAddStream = *CacheAddStreamOrErr;
280 if (!CacheAddStream)
281 return std::string(AbsCachedArtifactPath);
282
283
286 "No working HTTP client is available.");
287
291 "A working HTTP client is available, but it is not initialized. To "
292 "allow Debuginfod to make HTTP requests, call HTTPClient::initialize() "
293 "at the beginning of main.");
294
297 for (StringRef ServerUrl : DebuginfodUrls) {
300
301
302
303 {
304 StreamedHTTPResponseHandler Handler(
305 [&]() { return CacheAddStream(Task, ""); }, Client);
308 Error Err = Client.perform(Request, Handler);
309 if (Err)
310 return std::move(Err);
311 if ((Err = Handler.commit()))
312 return std::move(Err);
313
315 if (Code && Code != 200)
316 continue;
317 }
318
321 if (!PruningPolicyOrErr)
322 return PruningPolicyOrErr.takeError();
323 pruneCache(CacheDirectoryPath, *PruningPolicyOrErr);
324
325
326 return std::string(AbsCachedArtifactPath);
327 }
328
330}
331
334
338
340 {
341 std::lock_guardstd::mutex Guard(QueueMutex);
342 LogEntryQueue.push(Entry);
343 }
344 QueueCondition.notify_one();
345}
346
348 {
349 std::unique_lockstd::mutex Guard(QueueMutex);
350
351 QueueCondition.wait(Guard, [&] { return !LogEntryQueue.empty(); });
352 }
353 std::lock_guardstd::mutex Guard(QueueMutex);
354 if (!LogEntryQueue.size())
356
358 LogEntryQueue.pop();
359 return Entry;
360}
361
365 double MinInterval)
366 : Log(Log), Pool(Pool), MinInterval(MinInterval) {
368 Paths.push_back(Path.str());
369}
370
372 std::lock_guardsys::Mutex Guard(UpdateMutex);
373 if (UpdateTimer.isRunning())
374 UpdateTimer.stopTimer();
375 UpdateTimer.clear();
376 for (const std::string &Path : Paths) {
377 Log.push("Updating binaries at path " + Path);
378 if (Error Err = findBinaries(Path))
379 return Err;
380 }
381 Log.push("Updated collection");
382 UpdateTimer.startTimer();
384}
385
386Expected DebuginfodCollection::updateIfStale() {
388 return false;
392 if (Time < MinInterval)
393 return false;
395 return std::move(Err);
396 return true;
397}
398
400 while (true) {
402 return Err;
403 std::this_thread::sleep_for(Interval);
404 }
406}
407
411 if (EC)
412 return false;
413 switch (Type) {
419 return true;
420 default:
421 return false;
422 }
423}
424
425Error DebuginfodCollection::findBinaries(StringRef Path) {
426 std::error_code EC;
427 sys::fs::recursive_directory_iterator I(Twine(Path), EC), E;
428 std::mutex IteratorMutex;
429 ThreadPoolTaskGroup IteratorGroup(Pool);
430 for (unsigned WorkerIndex = 0; WorkerIndex < Pool.getMaxConcurrency();
431 WorkerIndex++) {
432 IteratorGroup.async([&, this]() -> void {
433 std::string FilePath;
434 while (true) {
435 {
436
437 std::lock_guardstd::mutex Guard(IteratorMutex);
439 return;
440
441
442 FilePath = I->path();
443 I.increment(EC);
444 }
445
446
448 continue;
449
450 Expected<object::OwningBinaryobject::Binary> BinOrErr =
452
453 if (!BinOrErr) {
455 continue;
456 }
457 object::Binary *Bin = std::move(BinOrErr.get().getBinary());
458 if (->isObject())
459 continue;
460
461
462 object::ELFObjectFileBase *Object =
464 if (!Object)
465 continue;
466
468 if (ID.empty())
469 continue;
470
472 if (Object->hasDebugInfo()) {
473 std::lock_guardsys::RWMutex DebugBinariesGuard(DebugBinariesMutex);
474 (void)DebugBinaries.try_emplace(IDString, std::move(FilePath));
475 } else {
476 std::lock_guardsys::RWMutex BinariesGuard(BinariesMutex);
477 (void)Binaries.try_emplace(IDString, std::move(FilePath));
478 }
479 }
480 });
481 }
482 IteratorGroup.wait();
483 std::unique_lockstd::mutex Guard(IteratorMutex);
484 if (EC)
487}
488
490DebuginfodCollection::getBinaryPath(BuildIDRef ID) {
492 std::shared_locksys::RWMutex Guard(BinariesMutex);
494 if (Loc != Binaries.end()) {
495 std::string Path = Loc->getValue();
497 }
498 return std::nullopt;
499}
500
502DebuginfodCollection::getDebugBinaryPath(BuildIDRef ID) {
503 Log.push("getting debug binary path of ID " + buildIDToString(ID));
504 std::shared_locksys::RWMutex Guard(DebugBinariesMutex);
506 if (Loc != DebugBinaries.end()) {
507 std::string Path = Loc->getValue();
509 }
510 return std::nullopt;
511}
512
514 {
515
517 if (!PathOrErr)
519 std::optionalstd::string Path = *PathOrErr;
520 if (!Path) {
522 if (!UpdatedOrErr)
524 if (*UpdatedOrErr) {
525
526 PathOrErr = getBinaryPath(ID);
527 if (!PathOrErr)
529 Path = *PathOrErr;
530 }
531 }
532 if (Path)
533 return *Path;
534 }
535
536
538 if (!PathOrErr)
540
541
543}
544
546
548 if (!PathOrErr)
550 std::optionalstd::string Path = *PathOrErr;
551 if (!Path) {
553 if (!UpdatedOrErr)
555 if (*UpdatedOrErr) {
556
557 PathOrErr = getBinaryPath(ID);
558 if (!PathOrErr)
560 Path = *PathOrErr;
561 }
562 }
563 if (Path)
564 return *Path;
565
566
568}
569
575 Log.push("GET " + Request.UrlPath);
576 std::string IDString;
577 if (!tryGetFromHex(Request.UrlPathMatches[0], IDString)) {
578 Request.setResponse(
579 {404, "text/plain", "Build ID is not a hex string\n"});
580 return;
581 }
584 if (Error Err = PathOrErr.takeError()) {
585 consumeError(std::move(Err));
586 Request.setResponse({404, "text/plain", "Build ID not found\n"});
587 return;
588 }
590 }));
591 cantFail(
592 Server.get(R"(/buildid/(.*)/executable)", [&](HTTPServerRequest Request) {
593 Log.push("GET " + Request.UrlPath);
594 std::string IDString;
595 if (!tryGetFromHex(Request.UrlPathMatches[0], IDString)) {
596 Request.setResponse(
597 {404, "text/plain", "Build ID is not a hex string\n"});
598 return;
599 }
600 object::BuildID ID(IDString.begin(), IDString.end());
601 Expectedstd::string PathOrErr = Collection.findBinaryPath(ID);
602 if (Error Err = PathOrErr.takeError()) {
603 consumeError(std::move(Err));
604 Request.setResponse({404, "text/plain", "Build ID not found\n"});
605 return;
606 }
608 }));
609}
610
611}
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 ...
std::pair< uint64_t, uint64_t > Interval
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Tracks a collection of debuginfod artifacts on the local filesystem.
DebuginfodCollection(ArrayRef< StringRef > Paths, DebuginfodLog &Log, ThreadPoolInterface &Pool, double MinInterval)
Definition Debuginfod.cpp:362
Expected< std::string > findBinaryPath(object::BuildIDRef)
Definition Debuginfod.cpp:513
Error updateForever(std::chrono::milliseconds Interval)
Definition Debuginfod.cpp:399
Error update()
Definition Debuginfod.cpp:371
Expected< std::string > findDebugBinaryPath(object::BuildIDRef)
Definition Debuginfod.cpp:545
DebuginfodLogEntry pop()
Definition Debuginfod.cpp:347
void push(DebuginfodLogEntry Entry)
Definition Debuginfod.cpp:339
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.
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
This defines the abstract base interface for a ThreadPool allowing asynchronous parallel execution on...
virtual unsigned getMaxConcurrency() const =0
Returns the maximum number of worker this pool can eventually grow to.
double getWallTime() const
bool isRunning() const
Check if the timer is currently running.
LLVM_ABI void stopTimer()
Stop the timer.
LLVM_ABI 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 LLVM_ABI 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.
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
LLVM_ABI BuildIDRef getBuildID(const ObjectFile *Obj)
Returns the build ID, if any, contained in the given object file.
ArrayRef< uint8_t > BuildIDRef
A reference to a BuildID in binary form.
LLVM_ABI Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
NodeAddr< CodeNode * > Code
LLVM_ABI bool cache_directory(SmallVectorImpl< char > &result)
Get the directory where installed packages should put their machine-local cache, e....
LLVM_ABI std::string convert_to_slash(StringRef path, Style style=Style::native)
Replaces backslashes with slashes if Windows.
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
SmartRWMutex< false > RWMutex
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
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.
Definition Debuginfod.cpp:145
std::string getDebuginfodCacheKey(StringRef UrlPath)
Returns the cache key for a given debuginfod URL path.
Definition Debuginfod.cpp:57
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
LLVM_ABI uint64_t xxh3_64bits(ArrayRef< uint8_t > data)
static bool isHeader(StringRef S)
Definition Debuginfod.cpp:225
SmallVector< StringRef > getDefaultDebuginfodUrls()
Finds default array of Debuginfod server URLs by checking DEBUGINFOD_URLS environment variable.
Definition Debuginfod.cpp:71
std::string getDebuginfodSourceUrlPath(object::BuildIDRef ID, StringRef SourceFilePath)
Get the full URL path for a source request of a given BuildID and file path.
Definition Debuginfod.cpp:123
Expected< std::string > getCachedOrDownloadDebuginfo(object::BuildIDRef ID)
Fetches a debug binary by searching the default local cache directory and server URLs.
Definition Debuginfod.cpp:157
std::string utostr(uint64_t X, bool isNeg=false)
static std::string buildIDToString(BuildIDRef ID)
Definition Debuginfod.cpp:63
std::string getDebuginfodExecutableUrlPath(object::BuildIDRef ID)
Get the full URL path for an executable request of a given BuildID.
Definition Debuginfod.cpp:138
LLVM_ABI 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.
Definition Debuginfod.cpp:163
std::string getDebuginfodDebuginfoUrlPath(object::BuildIDRef ID)
Get the full URL path for a debug binary request of a given BuildID.
Definition Debuginfod.cpp:150
iterator_range< SplittingIterator > split(StringRef Str, StringRef Separator)
Split the specified string over a separator and return a range-compatible iterable over its partition...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Timeout
Reached timeout while waiting for the owner to release the lock.
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.
Definition Debuginfod.cpp:132
LLVM_ABI 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.
Definition Debuginfod.cpp:109
void toHex(ArrayRef< uint8_t > Input, bool LowerCase, SmallVectorImpl< char > &Output)
Convert buffer Input to its hexadecimal representation. The returned string is double the size of Inp...
bool isPrint(char C)
Checks whether character C is printable.
bool isSpace(char C)
Checks whether character C is whitespace in the "C" locale.
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
static bool hasELFMagic(StringRef FilePath)
Definition Debuginfod.cpp:408
bool streamFile(HTTPServerRequest &Request, StringRef FilePath)
Sets the response to stream the file at FilePath, if available, and otherwise an HTTP 404 error respo...
bool to_integer(StringRef S, N &Num, unsigned Base=0)
Convert the string S to an integer of the specified type using the radix Base. If Base is 0,...
static SmallVector< std::string, 0 > getHeaders()
Definition Debuginfod.cpp:235
void setDefaultDebuginfodUrls(const SmallVector< StringRef > &URLs)
Sets the list of debuginfod server URLs to query.
Definition Debuginfod.cpp:90
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.
void consumeError(Error Err)
Consume a Error without doing anything.
LLVM_ABI 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.
Definition Debuginfod.cpp:67
Expected< std::string > getDefaultDebuginfodCacheDirectory()
Finds a default local file caching directory for the debuginfod client, first checking DEBUGINFOD_CAC...
Definition Debuginfod.cpp:97
DebuginfodLogEntry()=default
DebuginfodServer(DebuginfodLog &Log, DebuginfodCollection &Collection)
Definition Debuginfod.cpp:570
DebuginfodCollection & Collection
This type represents a file cache system that manages caching of files.
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.