811 lines · cpp
1//===-- PlatformWindows.cpp -----------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "PlatformWindows.h"10 11#include <cstdio>12#include <optional>13#if defined(_WIN32)14#include "lldb/Host/windows/windows.h"15#include <winsock2.h>16#endif17 18#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"19#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"20#include "lldb/Breakpoint/BreakpointLocation.h"21#include "lldb/Breakpoint/BreakpointSite.h"22#include "lldb/Core/Debugger.h"23#include "lldb/Core/Module.h"24#include "lldb/Core/PluginManager.h"25#include "lldb/Expression/DiagnosticManager.h"26#include "lldb/Expression/FunctionCaller.h"27#include "lldb/Expression/UserExpression.h"28#include "lldb/Expression/UtilityFunction.h"29#include "lldb/Host/HostInfo.h"30#include "lldb/Target/DynamicLoader.h"31#include "lldb/Target/Process.h"32#include "lldb/Utility/Status.h"33 34#include "llvm/ADT/ScopeExit.h"35#include "llvm/Support/ConvertUTF.h"36 37using namespace lldb;38using namespace lldb_private;39 40LLDB_PLUGIN_DEFINE(PlatformWindows)41 42static uint32_t g_initialize_count = 0;43 44PlatformSP PlatformWindows::CreateInstance(bool force,45 const lldb_private::ArchSpec *arch) {46 // The only time we create an instance is when we are creating a remote47 // windows platform48 const bool is_host = false;49 50 bool create = force;51 if (!create && arch && arch->IsValid()) {52 const llvm::Triple &triple = arch->GetTriple();53 switch (triple.getVendor()) {54 case llvm::Triple::PC:55 create = true;56 break;57 58 case llvm::Triple::UnknownVendor:59 create = !arch->TripleVendorWasSpecified();60 break;61 62 default:63 break;64 }65 66 if (create) {67 switch (triple.getOS()) {68 case llvm::Triple::Win32:69 break;70 71 case llvm::Triple::UnknownOS:72 create = arch->TripleOSWasSpecified();73 break;74 75 default:76 create = false;77 break;78 }79 }80 }81 if (create)82 return PlatformSP(new PlatformWindows(is_host));83 return PlatformSP();84}85 86llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {87 return is_host ? "Local Windows user platform plug-in."88 : "Remote Windows user platform plug-in.";89}90 91void PlatformWindows::Initialize() {92 Platform::Initialize();93 94 if (g_initialize_count++ == 0) {95#if defined(_WIN32)96 // Force a host flag to true for the default platform object.97 PlatformSP default_platform_sp(new PlatformWindows(true));98 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());99 Platform::SetHostPlatform(default_platform_sp);100#endif101 PluginManager::RegisterPlugin(102 PlatformWindows::GetPluginNameStatic(false),103 PlatformWindows::GetPluginDescriptionStatic(false),104 PlatformWindows::CreateInstance);105 }106}107 108void PlatformWindows::Terminate() {109 if (g_initialize_count > 0) {110 if (--g_initialize_count == 0) {111 PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);112 }113 }114 115 Platform::Terminate();116}117 118/// Default Constructor119PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {120 const auto &AddArch = [&](const ArchSpec &spec) {121 if (llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) {122 return spec.IsExactMatch(rhs);123 }))124 return;125 if (spec.IsValid())126 m_supported_architectures.push_back(spec);127 };128 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));129 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));130 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));131}132 133Status PlatformWindows::ConnectRemote(Args &args) {134 Status error;135 if (IsHost()) {136 error = Status::FromErrorStringWithFormatv(137 "can't connect to the host platform '{0}', always connected",138 GetPluginName());139 } else {140 if (!m_remote_platform_sp)141 m_remote_platform_sp =142 platform_gdb_server::PlatformRemoteGDBServer::CreateInstance(143 /*force=*/true, nullptr);144 145 if (m_remote_platform_sp) {146 if (error.Success()) {147 if (m_remote_platform_sp) {148 error = m_remote_platform_sp->ConnectRemote(args);149 } else {150 error = Status::FromErrorString(151 "\"platform connect\" takes a single argument: <connect-url>");152 }153 }154 } else155 error = Status::FromErrorString(156 "failed to create a 'remote-gdb-server' platform");157 158 if (error.Fail())159 m_remote_platform_sp.reset();160 }161 162 return error;163}164 165uint32_t PlatformWindows::DoLoadImage(Process *process,166 const FileSpec &remote_file,167 const std::vector<std::string> *paths,168 Status &error, FileSpec *loaded_image) {169 DiagnosticManager diagnostics;170 171 if (loaded_image)172 loaded_image->Clear();173 174 ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();175 if (!thread) {176 error = Status::FromErrorString(177 "LoadLibrary error: no thread available to invoke LoadLibrary");178 return LLDB_INVALID_IMAGE_TOKEN;179 }180 181 ExecutionContext context;182 thread->CalculateExecutionContext(context);183 184 Status status;185 UtilityFunction *loader =186 process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {187 return MakeLoadImageUtilityFunction(context, status);188 });189 if (loader == nullptr)190 return LLDB_INVALID_IMAGE_TOKEN;191 192 FunctionCaller *invocation = loader->GetFunctionCaller();193 if (!invocation) {194 error = Status::FromErrorString(195 "LoadLibrary error: could not get function caller");196 return LLDB_INVALID_IMAGE_TOKEN;197 }198 199 /* Convert name */200 llvm::SmallVector<llvm::UTF16, 261> name;201 if (!llvm::convertUTF8ToUTF16String(remote_file.GetPath(), name)) {202 error = Status::FromErrorString(203 "LoadLibrary error: could not convert path to UCS2");204 return LLDB_INVALID_IMAGE_TOKEN;205 }206 name.emplace_back(L'\0');207 208 /* Inject name paramter into inferior */209 lldb::addr_t injected_name =210 process->AllocateMemory(name.size() * sizeof(llvm::UTF16),211 ePermissionsReadable | ePermissionsWritable,212 status);213 if (injected_name == LLDB_INVALID_ADDRESS) {214 error = Status::FromErrorStringWithFormat(215 "LoadLibrary error: unable to allocate memory for name: %s",216 status.AsCString());217 return LLDB_INVALID_IMAGE_TOKEN;218 }219 220 auto name_cleanup = llvm::make_scope_exit([process, injected_name]() {221 process->DeallocateMemory(injected_name);222 });223 224 process->WriteMemory(injected_name, name.data(),225 name.size() * sizeof(llvm::UTF16), status);226 if (status.Fail()) {227 error = Status::FromErrorStringWithFormat(228 "LoadLibrary error: unable to write name: %s", status.AsCString());229 return LLDB_INVALID_IMAGE_TOKEN;230 }231 232 /* Inject paths parameter into inferior */233 lldb::addr_t injected_paths{0x0};234 std::optional<llvm::detail::scope_exit<std::function<void()>>> paths_cleanup;235 if (paths) {236 llvm::SmallVector<llvm::UTF16, 261> search_paths;237 238 for (const auto &path : *paths) {239 if (path.empty())240 continue;241 242 llvm::SmallVector<llvm::UTF16, 261> buffer;243 if (!llvm::convertUTF8ToUTF16String(path, buffer))244 continue;245 246 search_paths.append(std::begin(buffer), std::end(buffer));247 search_paths.emplace_back(L'\0');248 }249 search_paths.emplace_back(L'\0');250 251 injected_paths =252 process->AllocateMemory(search_paths.size() * sizeof(llvm::UTF16),253 ePermissionsReadable | ePermissionsWritable,254 status);255 if (injected_paths == LLDB_INVALID_ADDRESS) {256 error = Status::FromErrorStringWithFormat(257 "LoadLibrary error: unable to allocate memory for paths: %s",258 status.AsCString());259 return LLDB_INVALID_IMAGE_TOKEN;260 }261 262 paths_cleanup.emplace([process, injected_paths]() {263 process->DeallocateMemory(injected_paths);264 });265 266 process->WriteMemory(injected_paths, search_paths.data(),267 search_paths.size() * sizeof(llvm::UTF16), status);268 if (status.Fail()) {269 error = Status::FromErrorStringWithFormat(270 "LoadLibrary error: unable to write paths: %s", status.AsCString());271 return LLDB_INVALID_IMAGE_TOKEN;272 }273 }274 275 /* Inject wszModulePath into inferior */276 // FIXME(compnerd) should do something better for the length?277 // GetModuleFileNameA is likely limited to PATH_MAX rather than the NT path278 // limit.279 unsigned injected_length = 261;280 281 lldb::addr_t injected_module_path =282 process->AllocateMemory(injected_length + 1,283 ePermissionsReadable | ePermissionsWritable,284 status);285 if (injected_module_path == LLDB_INVALID_ADDRESS) {286 error = Status::FromErrorStringWithFormat(287 "LoadLibrary error: unable to allocate memory for module location: %s",288 status.AsCString());289 return LLDB_INVALID_IMAGE_TOKEN;290 }291 292 auto injected_module_path_cleanup =293 llvm::make_scope_exit([process, injected_module_path]() {294 process->DeallocateMemory(injected_module_path);295 });296 297 /* Inject __lldb_LoadLibraryResult into inferior */298 const uint32_t word_size = process->GetAddressByteSize();299 lldb::addr_t injected_result =300 process->AllocateMemory(3 * word_size,301 ePermissionsReadable | ePermissionsWritable,302 status);303 if (status.Fail()) {304 error = Status::FromErrorStringWithFormat(305 "LoadLibrary error: could not allocate memory for result: %s",306 status.AsCString());307 return LLDB_INVALID_IMAGE_TOKEN;308 }309 310 auto result_cleanup = llvm::make_scope_exit([process, injected_result]() {311 process->DeallocateMemory(injected_result);312 });313 314 process->WritePointerToMemory(injected_result + word_size,315 injected_module_path, status);316 if (status.Fail()) {317 error = Status::FromErrorStringWithFormat(318 "LoadLibrary error: could not initialize result: %s",319 status.AsCString());320 return LLDB_INVALID_IMAGE_TOKEN;321 }322 323 // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?324 process->WriteScalarToMemory(injected_result + 2 * word_size,325 Scalar{injected_length}, sizeof(unsigned),326 status);327 if (status.Fail()) {328 error = Status::FromErrorStringWithFormat(329 "LoadLibrary error: could not initialize result: %s",330 status.AsCString());331 return LLDB_INVALID_IMAGE_TOKEN;332 }333 334 /* Setup Formal Parameters */335 ValueList parameters = invocation->GetArgumentValues();336 parameters.GetValueAtIndex(0)->GetScalar() = injected_name;337 parameters.GetValueAtIndex(1)->GetScalar() = injected_paths;338 parameters.GetValueAtIndex(2)->GetScalar() = injected_result;339 340 lldb::addr_t injected_parameters = LLDB_INVALID_ADDRESS;341 diagnostics.Clear();342 if (!invocation->WriteFunctionArguments(context, injected_parameters,343 parameters, diagnostics)) {344 error = Status::FromError(diagnostics.GetAsError(345 eExpressionSetupError,346 "LoadLibrary error: unable to write function parameters:"));347 return LLDB_INVALID_IMAGE_TOKEN;348 }349 350 auto parameter_cleanup =351 llvm::make_scope_exit([invocation, &context, injected_parameters]() {352 invocation->DeallocateFunctionResults(context, injected_parameters);353 });354 355 TypeSystemClangSP scratch_ts_sp =356 ScratchTypeSystemClang::GetForTarget(process->GetTarget());357 if (!scratch_ts_sp) {358 error = Status::FromErrorString(359 "LoadLibrary error: unable to get (clang) type system");360 return LLDB_INVALID_IMAGE_TOKEN;361 }362 363 /* Setup Return Type */364 CompilerType VoidPtrTy =365 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();366 367 Value value;368 value.SetCompilerType(VoidPtrTy);369 370 /* Invoke expression */371 EvaluateExpressionOptions options;372 options.SetExecutionPolicy(eExecutionPolicyAlways);373 options.SetLanguage(eLanguageTypeC_plus_plus);374 options.SetIgnoreBreakpoints(true);375 options.SetUnwindOnError(true);376 // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.377 // They may potentially throw SEH exceptions which we do not know how to378 // handle currently.379 options.SetTrapExceptions(false);380 options.SetTimeout(process->GetUtilityExpressionTimeout());381 options.SetIsForUtilityExpr(true);382 383 ExpressionResults result =384 invocation->ExecuteFunction(context, &injected_parameters, options,385 diagnostics, value);386 if (result != eExpressionCompleted) {387 error = Status::FromError(diagnostics.GetAsError(388 eExpressionSetupError,389 "LoadLibrary error: failed to execute LoadLibrary helper:"));390 return LLDB_INVALID_IMAGE_TOKEN;391 }392 393 /* Read result */394 lldb::addr_t token = process->ReadPointerFromMemory(injected_result, status);395 if (status.Fail()) {396 error = Status::FromErrorStringWithFormat(397 "LoadLibrary error: could not read the result: %s", status.AsCString());398 return LLDB_INVALID_IMAGE_TOKEN;399 }400 401 if (!token) {402 // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?403 uint64_t error_code =404 process->ReadUnsignedIntegerFromMemory(injected_result + 2 * word_size + sizeof(unsigned),405 word_size, 0, status);406 if (status.Fail()) {407 error = Status::FromErrorStringWithFormat(408 "LoadLibrary error: could not read error status: %s",409 status.AsCString());410 return LLDB_INVALID_IMAGE_TOKEN;411 }412 413 error = Status::FromErrorStringWithFormat("LoadLibrary Error: %" PRIu64,414 error_code);415 return LLDB_INVALID_IMAGE_TOKEN;416 }417 418 std::string module_path;419 process->ReadCStringFromMemory(injected_module_path, module_path, status);420 if (status.Fail()) {421 error = Status::FromErrorStringWithFormat(422 "LoadLibrary error: could not read module path: %s",423 status.AsCString());424 return LLDB_INVALID_IMAGE_TOKEN;425 }426 427 if (loaded_image)428 loaded_image->SetFile(module_path, llvm::sys::path::Style::native);429 return process->AddImageToken(token);430}431 432Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {433 const addr_t address = process->GetImagePtrFromToken(image_token);434 if (address == LLDB_INVALID_IMAGE_TOKEN)435 return Status::FromErrorString("invalid image token");436 437 StreamString expression;438 expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);439 440 ValueObjectSP value;441 Status result =442 EvaluateLoaderExpression(process, expression.GetData(), value);443 if (result.Fail())444 return result;445 446 if (value->GetError().Fail())447 return value->GetError().Clone();448 449 Scalar scalar;450 if (value->ResolveValue(scalar)) {451 if (scalar.UInt(1))452 return Status::FromErrorStringWithFormat("expression failed: \"%s\"",453 expression.GetData());454 process->ResetImageToken(image_token);455 }456 457 return Status();458}459 460Status PlatformWindows::DisconnectRemote() {461 Status error;462 463 if (IsHost()) {464 error = Status::FromErrorStringWithFormatv(465 "can't disconnect from the host platform '{0}', always connected",466 GetPluginName());467 } else {468 if (m_remote_platform_sp)469 error = m_remote_platform_sp->DisconnectRemote();470 else471 error =472 Status::FromErrorString("the platform is not currently connected");473 }474 return error;475}476 477ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,478 Debugger &debugger, Target &target,479 Status &error) {480 // Windows has special considerations that must be followed when launching or481 // attaching to a process. The key requirement is that when launching or482 // attaching to a process, you must do it from the same the thread that will483 // go into a permanent loop which will then receive debug events from the484 // process. In particular, this means we can't use any of LLDB's generic485 // mechanisms to do it for us, because it doesn't have the special knowledge486 // required for setting up the background thread or passing the right flags.487 //488 // Another problem is that LLDB's standard model for debugging a process489 // is to first launch it, have it stop at the entry point, and then attach to490 // it. In Windows this doesn't quite work, you have to specify as an491 // argument to CreateProcess() that you're going to debug the process. So we492 // override DebugProcess here to handle this. Launch operations go directly493 // to the process plugin, and attach operations almost go directly to the494 // process plugin (but we hijack the events first). In essence, we495 // encapsulate all the logic of Launching and Attaching in the process496 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to497 // the process plugin.498 499 if (IsRemote()) {500 if (m_remote_platform_sp)501 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,502 error);503 else504 error =505 Status::FromErrorString("the platform is not currently connected");506 }507 508 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {509 // This is a process attach. Don't need to launch anything.510 ProcessAttachInfo attach_info(launch_info);511 return Attach(attach_info, debugger, &target, error);512 }513 514 ProcessSP process_sp =515 target.CreateProcess(launch_info.GetListener(),516 launch_info.GetProcessPluginName(), nullptr, false);517 518 process_sp->HijackProcessEvents(launch_info.GetHijackListener());519 520 // We need to launch and attach to the process.521 launch_info.GetFlags().Set(eLaunchFlagDebug);522 if (process_sp)523 error = process_sp->Launch(launch_info);524 525 return process_sp;526}527 528lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,529 Debugger &debugger, Target *target,530 Status &error) {531 error.Clear();532 lldb::ProcessSP process_sp;533 if (!IsHost()) {534 if (m_remote_platform_sp)535 process_sp =536 m_remote_platform_sp->Attach(attach_info, debugger, target, error);537 else538 error =539 Status::FromErrorString("the platform is not currently connected");540 return process_sp;541 }542 543 if (target == nullptr) {544 TargetSP new_target_sp;545 FileSpec emptyFileSpec;546 ArchSpec emptyArchSpec;547 548 error = debugger.GetTargetList().CreateTarget(549 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);550 target = new_target_sp.get();551 }552 553 if (!target || error.Fail())554 return process_sp;555 556 process_sp =557 target->CreateProcess(attach_info.GetListenerForProcess(debugger),558 attach_info.GetProcessPluginName(), nullptr, false);559 560 process_sp->HijackProcessEvents(attach_info.GetHijackListener());561 if (process_sp)562 error = process_sp->Attach(attach_info);563 564 return process_sp;565}566 567void PlatformWindows::GetStatus(Stream &strm) {568 Platform::GetStatus(strm);569 570#ifdef _WIN32571 llvm::VersionTuple version = HostInfo::GetOSVersion();572 strm << " Host: Windows " << version.getAsString() << '\n';573#endif574}575 576bool PlatformWindows::CanDebugProcess() { return true; }577 578ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {579 if (basename.IsEmpty())580 return basename;581 582 StreamString stream;583 stream.Printf("%s.dll", basename.GetCString());584 return ConstString(stream.GetString());585}586 587size_t588PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,589 BreakpointSite *bp_site) {590 ArchSpec arch = target.GetArchitecture();591 assert(arch.IsValid());592 const uint8_t *trap_opcode = nullptr;593 size_t trap_opcode_size = 0;594 595 switch (arch.GetMachine()) {596 case llvm::Triple::aarch64: {597 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000598 trap_opcode = g_aarch64_opcode;599 trap_opcode_size = sizeof(g_aarch64_opcode);600 601 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))602 return trap_opcode_size;603 return 0;604 } break;605 606 case llvm::Triple::arm:607 case llvm::Triple::thumb: {608 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe609 trap_opcode = g_thumb_opcode;610 trap_opcode_size = sizeof(g_thumb_opcode);611 612 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))613 return trap_opcode_size;614 return 0;615 } break;616 617 default:618 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);619 }620}621 622std::unique_ptr<UtilityFunction>623PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,624 Status &status) {625 // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?626 static constexpr const char kLoaderDecls[] = R"(627extern "C" {628// errhandlingapi.h629 630// `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`631//632// Directories in the standard search path are not searched. This value cannot633// be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.634//635// This value represents the recommended maximum number of directories an636// application should include in its DLL search path.637#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000638 639// WINBASEAPI DWORD WINAPI GetLastError(VOID);640/* __declspec(dllimport) */ uint32_t __stdcall GetLastError();641 642// libloaderapi.h643 644// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);645/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);646 647// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);648/* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);649 650// WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);651/* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);652 653// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);654/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);655 656// corecrt_wstring.h657 658// _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);659/* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);660 661// lldb specific code662 663struct __lldb_LoadLibraryResult {664 void *ImageBase;665 char *ModulePath;666 unsigned Length;667 unsigned ErrorCode;668};669 670_Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),671 "__lldb_LoadLibraryResult size mismatch");672 673void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,674 __lldb_LoadLibraryResult *result) {675 for (const wchar_t *path = paths; path && *path; ) {676 (void)AddDllDirectory(path);677 path += wcslen(path) + 1;678 }679 680 result->ImageBase = LoadLibraryExW(name, nullptr,681 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);682 if (result->ImageBase == nullptr)683 result->ErrorCode = GetLastError();684 else685 result->Length = GetModuleFileNameA(result->ImageBase, result->ModulePath,686 result->Length);687 688 return result->ImageBase;689}690}691 )";692 693 static constexpr const char kName[] = "__lldb_LoadLibraryHelper";694 695 ProcessSP process = context.GetProcessSP();696 Target &target = process->GetTarget();697 698 auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,699 eLanguageTypeC_plus_plus,700 context);701 if (!function) {702 std::string error = llvm::toString(function.takeError());703 status = Status::FromErrorStringWithFormat(704 "LoadLibrary error: could not create utility function: %s",705 error.c_str());706 return nullptr;707 }708 709 TypeSystemClangSP scratch_ts_sp =710 ScratchTypeSystemClang::GetForTarget(target);711 if (!scratch_ts_sp)712 return nullptr;713 714 CompilerType VoidPtrTy =715 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();716 CompilerType WCharPtrTy =717 scratch_ts_sp->GetBasicType(eBasicTypeWChar).GetPointerType();718 719 ValueList parameters;720 721 Value value;722 value.SetValueType(Value::ValueType::Scalar);723 724 value.SetCompilerType(WCharPtrTy);725 parameters.PushValue(value); // name726 parameters.PushValue(value); // paths727 728 value.SetCompilerType(VoidPtrTy);729 parameters.PushValue(value); // result730 731 Status error;732 std::unique_ptr<UtilityFunction> utility{std::move(*function)};733 utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),734 error);735 if (error.Fail()) {736 status = Status::FromErrorStringWithFormat(737 "LoadLibrary error: could not create function caller: %s",738 error.AsCString());739 return nullptr;740 }741 742 if (!utility->GetFunctionCaller()) {743 status = Status::FromErrorString(744 "LoadLibrary error: could not get function caller");745 return nullptr;746 }747 748 return utility;749}750 751Status PlatformWindows::EvaluateLoaderExpression(Process *process,752 const char *expression,753 ValueObjectSP &value) {754 // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?755 static constexpr const char kLoaderDecls[] = R"(756extern "C" {757// libloaderapi.h758 759// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);760/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);761 762// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);763/* __declspec(dllimport) */ int __stdcall FreeModule(void *);764 765// WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE, LPSTR, DWORD);766/* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);767 768// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);769/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);770}771 )";772 773 if (DynamicLoader *loader = process->GetDynamicLoader()) {774 Status result = loader->CanLoadImage();775 if (result.Fail())776 return result;777 }778 779 ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();780 if (!thread)781 return Status::FromErrorString("selected thread is invalid");782 783 StackFrameSP frame = thread->GetStackFrameAtIndex(0);784 if (!frame)785 return Status::FromErrorString("frame 0 is invalid");786 787 ExecutionContext context;788 frame->CalculateExecutionContext(context);789 790 EvaluateExpressionOptions options;791 options.SetUnwindOnError(true);792 options.SetIgnoreBreakpoints(true);793 options.SetExecutionPolicy(eExecutionPolicyAlways);794 options.SetLanguage(eLanguageTypeC_plus_plus);795 // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.796 // They may potentially throw SEH exceptions which we do not know how to797 // handle currently.798 options.SetTrapExceptions(false);799 options.SetTimeout(process->GetUtilityExpressionTimeout());800 801 ExpressionResults result = UserExpression::Evaluate(802 context, options, expression, kLoaderDecls, value);803 if (result != eExpressionCompleted)804 return value ? value->GetError().Clone() : Status("unknown error");805 806 if (value && value->GetError().Fail())807 return value->GetError().Clone();808 809 return Status();810}811