20#include "llvm/ADT/StringExtras.h"
21#include "llvm/Support/Endian.h"
22#include "llvm/Support/FileSystem.h"
23#include "llvm/Support/FormatVariadic.h"
24#include "llvm/Support/HTTP/HTTPClient.h"
25#include "llvm/Support/Path.h"
34#define LLDB_PROPERTIES_symbollocatorsymstore
35#include "SymbolLocatorSymStoreProperties.inc"
38#define LLDB_PROPERTIES_symbollocatorsymstore
39#include "SymbolLocatorSymStorePropertiesEnum.inc"
44 static llvm::StringRef GetSettingName() {
49 m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
50 m_collection_sp->Initialize(g_symbollocatorsymstore_properties_def);
53 Args GetURLs()
const {
55 m_collection_sp->GetPropertyAtIndexAsArgs(ePropertySymStoreURLs, urls);
63 static PluginProperties g_settings;
74 llvm::HTTPClient::initialize();
79 debugger, PluginProperties::GetSettingName())) {
80 constexpr bool is_global_setting =
true;
83 "Properties for the SymStore Symbol Locator plug-in.",
90 llvm::HTTPClient::cleanup();
94 return "Symbol locator for PDB in SymStore";
110std::string formatSymStoreKey(
const UUID &uuid) {
111 llvm::ArrayRef<uint8_t> bytes = uuid.
GetBytes();
112 uint32_t age = llvm::support::endian::read32be(bytes.data() + 16);
113 constexpr bool LowerCase =
false;
114 return llvm::toHex(bytes.slice(0, 16), LowerCase) + std::to_string(age);
119class FileDownloadHandler :
public llvm::HTTPResponseHandler {
121 std::error_code m_ec;
122 llvm::raw_fd_ostream m_stream;
125 FileDownloadHandler(llvm::StringRef file) : m_stream(file.str(), m_ec) {}
126 virtual ~FileDownloadHandler() =
default;
128 llvm::Error handleBodyChunk(llvm::StringRef data)
override {
131 return llvm::createStringError(m_ec,
"Failed to open file for writing");
132 m_stream.write(data.data(), data.size());
133 if (std::error_code ec = m_stream.error())
134 return llvm::createStringError(ec,
"Error writing to file");
136 return llvm::Error::success();
140llvm::Error downloadFileHTTP(llvm::StringRef url, FileDownloadHandler dest) {
141 if (!llvm::HTTPClient::isAvailable())
142 return llvm::createStringError(
143 std::make_error_code(std::errc::not_supported),
144 "HTTP client is not available");
145 llvm::HTTPRequest Request(url);
146 Request.FollowRedirects =
true;
148 llvm::HTTPClient Client;
152 Client.setTimeout(std::chrono::seconds(60));
154 if (llvm::Error Err = Client.perform(Request, dest))
157 unsigned ResponseCode = Client.responseCode();
158 if (ResponseCode != 200) {
159 return llvm::createStringError(std::make_error_code(std::errc::io_error),
160 "HTTP request failed with status code " +
161 std::to_string(ResponseCode));
164 return llvm::Error::success();
167bool has_unsafe_characters(llvm::StringRef s) {
168 for (
unsigned char c : s) {
170 if ((c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') ||
171 (c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' || c ==
'_' ||
180 return s ==
"." || s ==
"..";
186std::optional<FileSpec>
187requestFileFromSymStoreServerHTTP(llvm::StringRef base_url, llvm::StringRef key,
188 llvm::StringRef pdb_name) {
189 using namespace llvm::sys;
193 if (has_unsafe_characters(pdb_name)) {
195 "rejecting HTTP lookup for PDB file due to unsafe characters in "
202 llvm::SmallString<128> tmp_file;
203 std::string tmp_file_name =
204 llvm::formatv(
"lldb_symstore_{0}_{1}", key, pdb_name);
205 constexpr bool erase_on_reboot =
true;
206 path::system_temp_directory(erase_on_reboot, tmp_file);
207 path::append(tmp_file, tmp_file_name);
210 std::string source_url =
211 llvm::formatv(
"{0}/{1}/{2}/{1}", base_url, pdb_name, key);
212 if (llvm::Error err = downloadFileHTTP(source_url, tmp_file.str())) {
214 "Failed to download from SymStore '{1}': {0}", source_url);
221std::optional<FileSpec> findFileInLocalSymStore(llvm::StringRef root_dir,
223 llvm::StringRef pdb_name) {
224 llvm::SmallString<256> path;
225 llvm::sys::path::append(path, root_dir, pdb_name, key, pdb_name);
233std::optional<FileSpec> locateSymStoreEntry(llvm::StringRef base_url,
235 llvm::StringRef pdb_name) {
236 if (base_url.starts_with(
"http://") || base_url.starts_with(
"https://"))
237 return requestFileFromSymStoreServerHTTP(base_url, key, pdb_name);
239 if (base_url.starts_with(
"file://"))
240 base_url = base_url.drop_front(7);
242 return findFileInLocalSymStore(base_url, key, pdb_name);
255 std::string pdb_name =
257 if (pdb_name.empty()) {
259 "Failed to resolve symbol PDB module: PDB name empty");
270 std::string key = formatSymStoreKey(uuid);
273 if (
auto spec = locateSymStoreEntry(url.ref(), key, pdb_name)) {
static PluginProperties & GetGlobalPluginProperties()
#define LLDB_LOG_ERROR(log, error,...)
#define LLDB_LOG_VERBOSE(log,...)
#define LLDB_PLUGIN_DEFINE(PluginName)
static PluginProperties & GetGlobalPluginProperties()
A command line argument class.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
A class to manage flag bits.
static void ReportWarning(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report warning events.
const ConstString & GetFilename() const
Filename string const get accessor.
static FileSystem & Instance()
static ModuleListProperties & GetGlobalModuleListProperties()
FileSpec & GetSymbolFileSpec()
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static lldb::OptionValuePropertiesSP GetSettingForSymbolLocatorPlugin(Debugger &debugger, llvm::StringRef setting_name)
static bool UnregisterPlugin(ABICreateInstance create_callback)
static bool CreateSettingForSymbolLocatorPlugin(Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property)
This plugin implements lookup in Microsoft SymStore instances.
static void DebuggerInitialize(Debugger &debugger)
static lldb_private::SymbolLocator * CreateInstance()
static llvm::StringRef GetPluginNameStatic()
static llvm::StringRef GetPluginDescriptionStatic()
static std::optional< FileSpec > LocateExecutableSymbolFile(const ModuleSpec &module_spec, const FileSpecList &default_search_paths)
Represents UUID's of various sizes.
llvm::ArrayRef< uint8_t > GetBytes() const
std::string GetAsString(llvm::StringRef separator="-") const
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.