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