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);

438 if (I == E || EC)

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 (Bin->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.