LLVM  15.0.0git
Debuginfod.cpp
Go to the documentation of this file.
1 //===-- llvm/Debuginfod/Debuginfod.cpp - Debuginfod client library --------===//
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 ///
11 /// This file defines the fetchInfo function, which retrieves
12 /// any of the three supported artifact types: (executable, debuginfo, source
13 /// file) associated with a build-id from debuginfod servers. If a source file
14 /// is to be fetched, its absolute path must be specified in the Description
15 /// argument to fetchInfo.
16 ///
17 //===----------------------------------------------------------------------===//
18 
20 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Support/Caching.h"
24 #include "llvm/Support/Errc.h"
25 #include "llvm/Support/Error.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/xxhash.h"
29 
30 namespace llvm {
31 static std::string uniqueKey(llvm::StringRef S) { return utostr(xxHash64(S)); }
32 
33 // Returns a binary BuildID as a normalized hex string.
34 // Uses lowercase for compatibility with common debuginfod servers.
35 static std::string buildIDToString(BuildIDRef ID) {
36  return llvm::toHex(ID, /*LowerCase=*/true);
37 }
38 
40  const char *DebuginfodUrlsEnv = std::getenv("DEBUGINFOD_URLS");
41  if (DebuginfodUrlsEnv == nullptr)
42  return SmallVector<StringRef>();
43 
44  SmallVector<StringRef> DebuginfodUrls;
45  StringRef(DebuginfodUrlsEnv).split(DebuginfodUrls, " ");
46  return DebuginfodUrls;
47 }
48 
50  if (const char *CacheDirectoryEnv = std::getenv("DEBUGINFOD_CACHE_PATH"))
51  return CacheDirectoryEnv;
52 
53  SmallString<64> CacheDirectory;
54  if (!sys::path::cache_directory(CacheDirectory))
55  return createStringError(
56  errc::io_error, "Unable to determine appropriate cache directory.");
57  sys::path::append(CacheDirectory, "llvm-debuginfod", "client");
58  return std::string(CacheDirectory);
59 }
60 
61 std::chrono::milliseconds getDefaultDebuginfodTimeout() {
62  long Timeout;
63  const char *DebuginfodTimeoutEnv = std::getenv("DEBUGINFOD_TIMEOUT");
64  if (DebuginfodTimeoutEnv &&
65  to_integer(StringRef(DebuginfodTimeoutEnv).trim(), Timeout, 10))
66  return std::chrono::milliseconds(Timeout * 1000);
67 
68  return std::chrono::milliseconds(90 * 1000);
69 }
70 
71 /// The following functions fetch a debuginfod artifact to a file in a local
72 /// cache and return the cached file path. They first search the local cache,
73 /// followed by the debuginfod servers.
74 
76  StringRef SourceFilePath) {
77  SmallString<64> UrlPath;
78  sys::path::append(UrlPath, sys::path::Style::posix, "buildid",
79  buildIDToString(ID), "source",
80  sys::path::convert_to_slash(SourceFilePath));
81  return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath);
82 }
83 
85  SmallString<64> UrlPath;
86  sys::path::append(UrlPath, sys::path::Style::posix, "buildid",
87  buildIDToString(ID), "executable");
88  return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath);
89 }
90 
92  SmallString<64> UrlPath;
93  sys::path::append(UrlPath, sys::path::Style::posix, "buildid",
94  buildIDToString(ID), "debuginfo");
95  return getCachedOrDownloadArtifact(uniqueKey(UrlPath), UrlPath);
96 }
97 
98 // General fetching function.
100  StringRef UrlPath) {
101  SmallString<10> CacheDir;
102 
104  if (!CacheDirOrErr)
105  return CacheDirOrErr.takeError();
106  CacheDir = *CacheDirOrErr;
107 
108  Expected<SmallVector<StringRef>> DebuginfodUrlsOrErr =
110  if (!DebuginfodUrlsOrErr)
111  return DebuginfodUrlsOrErr.takeError();
112  SmallVector<StringRef> &DebuginfodUrls = *DebuginfodUrlsOrErr;
113  return getCachedOrDownloadArtifact(UniqueKey, UrlPath, CacheDir,
114  DebuginfodUrls,
116 }
117 
118 namespace {
119 
120 /// A simple handler which streams the returned data to a cache file. The cache
121 /// file is only created if a 200 OK status is observed.
122 class StreamedHTTPResponseHandler : public HTTPResponseHandler {
123  using CreateStreamFn =
124  std::function<Expected<std::unique_ptr<CachedFileStream>>()>;
125  CreateStreamFn CreateStream;
126  HTTPClient &Client;
127  std::unique_ptr<CachedFileStream> FileStream;
128 
129 public:
130  StreamedHTTPResponseHandler(CreateStreamFn CreateStream, HTTPClient &Client)
131  : CreateStream(CreateStream), Client(Client) {}
132  virtual ~StreamedHTTPResponseHandler() = default;
133 
134  Error handleBodyChunk(StringRef BodyChunk) override;
135 };
136 
137 } // namespace
138 
139 Error StreamedHTTPResponseHandler::handleBodyChunk(StringRef BodyChunk) {
140  if (!FileStream) {
141  if (Client.responseCode() != 200)
142  return Error::success();
143  Expected<std::unique_ptr<CachedFileStream>> FileStreamOrError =
144  CreateStream();
145  if (!FileStreamOrError)
146  return FileStreamOrError.takeError();
147  FileStream = std::move(*FileStreamOrError);
148  }
149  *FileStream->OS << BodyChunk;
150  return Error::success();
151 }
152 
154  StringRef UniqueKey, StringRef UrlPath, StringRef CacheDirectoryPath,
155  ArrayRef<StringRef> DebuginfodUrls, std::chrono::milliseconds Timeout) {
156  SmallString<64> AbsCachedArtifactPath;
157  sys::path::append(AbsCachedArtifactPath, CacheDirectoryPath,
158  "llvmcache-" + UniqueKey);
159 
160  Expected<FileCache> CacheOrErr =
161  localCache("Debuginfod-client", ".debuginfod-client", CacheDirectoryPath);
162  if (!CacheOrErr)
163  return CacheOrErr.takeError();
164 
165  FileCache Cache = *CacheOrErr;
166  // We choose an arbitrary Task parameter as we do not make use of it.
167  unsigned Task = 0;
168  Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, UniqueKey);
169  if (!CacheAddStreamOrErr)
170  return CacheAddStreamOrErr.takeError();
171  AddStreamFn &CacheAddStream = *CacheAddStreamOrErr;
172  if (!CacheAddStream)
173  return std::string(AbsCachedArtifactPath);
174  // The artifact was not found in the local cache, query the debuginfod
175  // servers.
178  "No working HTTP client is available.");
179 
181  return createStringError(
183  "A working HTTP client is available, but it is not initialized. To "
184  "allow Debuginfod to make HTTP requests, call HTTPClient::initialize() "
185  "at the beginning of main.");
186 
187  HTTPClient Client;
188  Client.setTimeout(Timeout);
189  for (StringRef ServerUrl : DebuginfodUrls) {
190  SmallString<64> ArtifactUrl;
191  sys::path::append(ArtifactUrl, sys::path::Style::posix, ServerUrl, UrlPath);
192 
193  // Perform the HTTP request and if successful, write the response body to
194  // the cache.
195  StreamedHTTPResponseHandler Handler([&]() { return CacheAddStream(Task); },
196  Client);
197  HTTPRequest Request(ArtifactUrl);
198  Error Err = Client.perform(Request, Handler);
199  if (Err)
200  return std::move(Err);
201 
202  if (Client.responseCode() != 200)
203  continue;
204 
205  // Return the path to the artifact on disk.
206  return std::string(AbsCachedArtifactPath);
207  }
208 
209  return createStringError(errc::argument_out_of_domain, "build id not found");
210 }
211 } // namespace llvm
llvm::FileCache
std::function< Expected< AddStreamFn >(unsigned Task, StringRef Key)> FileCache
This is the type of a file cache.
Definition: Caching.h:56
llvm::HTTPClient
A reusable client that can perform HTTPRequests through a network socket.
Definition: HTTPClient.h:50
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::buildIDToString
static std::string buildIDToString(BuildIDRef ID)
Definition: Debuginfod.cpp:35
llvm::lltok::Error
@ Error
Definition: LLToken.h:21
llvm::sys::path::Style::posix
@ posix
StringRef.h
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
llvm::HTTPClient::IsInitialized
static bool IsInitialized
Definition: HTTPClient.h:59
Path.h
llvm::sys::path::convert_to_slash
std::string convert_to_slash(StringRef path, Style style=Style::native)
Replaces backslashes with slashes if Windows.
Definition: Path.cpp:568
llvm::AddStreamFn
std::function< Expected< std::unique_ptr< CachedFileStream > >(unsigned Task)> AddStreamFn
This type defines the callback to add a file that is generated on the fly.
Definition: Caching.h:42
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
Error.h
Errc.h
HTTPClient.h
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::getDefaultDebuginfodTimeout
std::chrono::milliseconds getDefaultDebuginfodTimeout()
Finds a default timeout for debuginfod HTTP requests.
Definition: Debuginfod.cpp:61
llvm::sys::path::cache_directory
bool cache_directory(SmallVectorImpl< char > &result)
Get the directory where installed packages should put their machine-local cache, e....
llvm::sys::path::append
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:456
Caching.h
CachePruning.h
llvm::uniqueKey
static std::string uniqueKey(llvm::StringRef S)
Definition: Debuginfod.cpp:31
llvm::errc::argument_out_of_domain
@ argument_out_of_domain
llvm::StringRef::split
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:749
llvm::getCachedOrDownloadArtifact
Expected< std::string > getCachedOrDownloadArtifact(StringRef UniqueKey, StringRef UrlPath)
Fetches any debuginfod artifact using the default local cache directory and server URLs.
Definition: Debuginfod.cpp:99
llvm::HTTPClient::perform
Error perform(const HTTPRequest &Request, HTTPResponseHandler &Handler)
Performs the Request, passing response data to the Handler.
Definition: HTTPClient.cpp:145
llvm::localCache
Expected< FileCache > localCache(Twine CacheNameRef, Twine TempFilePrefixRef, Twine CacheDirectoryPathRef, AddBufferFn AddBuffer=[](size_t Task, std::unique_ptr< MemoryBuffer > MB) { })
Create a local file system cache which uses the given cache name, temporary file prefix,...
Definition: Caching.cpp:29
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
llvm::SmallString< 64 >
Debuginfod.h
llvm::HTTPClient::responseCode
unsigned responseCode()
Returns the last received response code or zero if none.
Definition: HTTPClient.cpp:150
llvm::symbolize::toHex
static std::string toHex(uint64_t V)
Definition: DIPrinter.cpp:278
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::HTTPClient::isAvailable
static bool isAvailable()
Returns true only if LLVM has been compiled with a working HTTPClient.
Definition: HTTPClient.cpp:137
llvm::HTTPClient::setTimeout
void setTimeout(std::chrono::milliseconds Timeout)
Sets the timeout for the entire request, in milliseconds.
Definition: HTTPClient.cpp:143
llvm::getDefaultDebuginfodCacheDirectory
Expected< std::string > getDefaultDebuginfodCacheDirectory()
Finds a default local file caching directory for the debuginfod client, first checking DEBUGINFOD_CAC...
Definition: Debuginfod.cpp:49
llvm::getCachedOrDownloadExecutable
Expected< std::string > getCachedOrDownloadExecutable(BuildIDRef ID)
Fetches an executable by searching the default local cache directory and server URLs.
Definition: Debuginfod.cpp:84
xxhash.h
FileUtilities.h
llvm::ArrayRef< uint8_t >
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1239
llvm::HTTPRequest
A stateless description of an outbound HTTP request.
Definition: HTTPClient.h:28
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::getDefaultDebuginfodUrls
Expected< SmallVector< StringRef > > getDefaultDebuginfodUrls()
Finds default array of Debuginfod server URLs by checking DEBUGINFOD_URLS environment variable.
Definition: Debuginfod.cpp:39
llvm::errc::io_error
@ io_error
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:597
llvm::getCachedOrDownloadSource
Expected< std::string > getCachedOrDownloadSource(BuildIDRef ID, StringRef SourceFilePath)
Fetches a specified source file by searching the default local cache directory and server URLs.
Definition: Debuginfod.cpp:75
llvm::getCachedOrDownloadDebuginfo
Expected< std::string > getCachedOrDownloadDebuginfo(BuildIDRef ID)
Fetches a debug binary by searching the default local cache directory and server URLs.
Definition: Debuginfod.cpp:91
llvm::xxHash64
uint64_t xxHash64(llvm::StringRef Data)
Definition: xxhash.cpp:70