brintos

brintos / llvm-project-archived public Read only

0
0
Text · 27.2 KiB · c0c26cc Raw
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