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: %" PRIu64, 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   }
492 
493   ProcessSP process_sp =
494       target.CreateProcess(launch_info.GetListener(),
495                            launch_info.GetProcessPluginName(), nullptr, false);
496 
497   process_sp->HijackProcessEvents(launch_info.GetHijackListener());
498 
499   // We need to launch and attach to the process.
500   launch_info.GetFlags().Set(eLaunchFlagDebug);
501   if (process_sp)
502     error = process_sp->Launch(launch_info);
503 
504   return process_sp;
505 }
506 
507 lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,
508                                         Debugger &debugger, Target *target,
509                                         Status &error) {
510   error.Clear();
511   lldb::ProcessSP process_sp;
512   if (!IsHost()) {
513     if (m_remote_platform_sp)
514       process_sp =
515           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
516     else
517       error.SetErrorString("the platform is not currently connected");
518     return process_sp;
519   }
520 
521   if (target == nullptr) {
522     TargetSP new_target_sp;
523     FileSpec emptyFileSpec;
524     ArchSpec emptyArchSpec;
525 
526     error = debugger.GetTargetList().CreateTarget(
527         debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
528     target = new_target_sp.get();
529   }
530 
531   if (!target || error.Fail())
532     return process_sp;
533 
534   const char *plugin_name = attach_info.GetProcessPluginName();
535   process_sp = target->CreateProcess(
536       attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false);
537 
538   process_sp->HijackProcessEvents(attach_info.GetHijackListener());
539   if (process_sp)
540     error = process_sp->Attach(attach_info);
541 
542   return process_sp;
543 }
544 
545 void PlatformWindows::GetStatus(Stream &strm) {
546   Platform::GetStatus(strm);
547 
548 #ifdef _WIN32
549   llvm::VersionTuple version = HostInfo::GetOSVersion();
550   strm << "      Host: Windows " << version.getAsString() << '\n';
551 #endif
552 }
553 
554 bool PlatformWindows::CanDebugProcess() { return true; }
555 
556 ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
557   if (basename.IsEmpty())
558     return basename;
559 
560   StreamString stream;
561   stream.Printf("%s.dll", basename.GetCString());
562   return ConstString(stream.GetString());
563 }
564 
565 size_t
566 PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
567                                                  BreakpointSite *bp_site) {
568   ArchSpec arch = target.GetArchitecture();
569   assert(arch.IsValid());
570   const uint8_t *trap_opcode = nullptr;
571   size_t trap_opcode_size = 0;
572 
573   switch (arch.GetMachine()) {
574   case llvm::Triple::aarch64: {
575     static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
576     trap_opcode = g_aarch64_opcode;
577     trap_opcode_size = sizeof(g_aarch64_opcode);
578 
579     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
580       return trap_opcode_size;
581     return 0;
582   } break;
583 
584   case llvm::Triple::arm:
585   case llvm::Triple::thumb: {
586     static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
587     trap_opcode = g_thumb_opcode;
588     trap_opcode_size = sizeof(g_thumb_opcode);
589 
590     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
591       return trap_opcode_size;
592     return 0;
593   } break;
594 
595   default:
596     return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
597   }
598 }
599 
600 std::unique_ptr<UtilityFunction>
601 PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
602                                               Status &status) {
603   // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
604   static constexpr const char kLoaderDecls[] = R"(
605 extern "C" {
606 // errhandlingapi.h
607 
608 // `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
609 //
610 // Directories in the standard search path are not searched. This value cannot
611 // be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
612 //
613 // This value represents the recommended maximum number of directories an
614 // application should include in its DLL search path.
615 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
616 
617 // WINBASEAPI DWORD WINAPI GetLastError(VOID);
618 /* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
619 
620 // libloaderapi.h
621 
622 // WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
623 /* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
624 
625 // WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
626 /* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
627 
628 // WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
629 /* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
630 
631 // WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
632 /* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
633 
634 // corecrt_wstring.h
635 
636 // _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
637 /* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
638 
639 // lldb specific code
640 
641 struct __lldb_LoadLibraryResult {
642   void *ImageBase;
643   char *ModulePath;
644   unsigned Length;
645   unsigned ErrorCode;
646 };
647 
648 _Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
649                "__lldb_LoadLibraryResult size mismatch");
650 
651 void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
652                                 __lldb_LoadLibraryResult *result) {
653   for (const wchar_t *path = paths; path; ) {
654     (void)AddDllDirectory(path);
655     path += wcslen(path) + 1;
656   }
657 
658   result->ImageBase = LoadLibraryExW(name, nullptr,
659                                      LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
660   if (result->ImageBase == nullptr)
661     result->ErrorCode = GetLastError();
662   else
663     result->Length = GetModuleFileNameA(result->ImageBase, result->ModulePath,
664                                         result->Length);
665 
666   return result->ImageBase;
667 }
668 }
669   )";
670 
671   static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
672 
673   ProcessSP process = context.GetProcessSP();
674   Target &target = process->GetTarget();
675 
676   auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
677                                                eLanguageTypeC_plus_plus,
678                                                context);
679   if (!function) {
680     std::string error = llvm::toString(function.takeError());
681     status.SetErrorStringWithFormat("LoadLibrary error: could not create utility function: %s",
682                                     error.c_str());
683     return nullptr;
684   }
685 
686   TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget(target);
687   if (!ast)
688     return nullptr;
689 
690   CompilerType VoidPtrTy = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
691   CompilerType WCharPtrTy = ast->GetBasicType(eBasicTypeWChar).GetPointerType();
692 
693   ValueList parameters;
694 
695   Value value;
696   value.SetValueType(Value::ValueType::Scalar);
697 
698   value.SetCompilerType(WCharPtrTy);
699   parameters.PushValue(value);  // name
700   parameters.PushValue(value);  // paths
701 
702   value.SetCompilerType(VoidPtrTy);
703   parameters.PushValue(value);  // result
704 
705   Status error;
706   std::unique_ptr<UtilityFunction> utility{std::move(*function)};
707   utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
708                               error);
709   if (error.Fail()) {
710     status.SetErrorStringWithFormat("LoadLibrary error: could not create function caller: %s",
711                                     error.AsCString());
712     return nullptr;
713   }
714 
715   if (!utility->GetFunctionCaller()) {
716     status.SetErrorString("LoadLibrary error: could not get function caller");
717     return nullptr;
718   }
719 
720   return utility;
721 }
722 
723 Status PlatformWindows::EvaluateLoaderExpression(Process *process,
724                                                  const char *expression,
725                                                  ValueObjectSP &value) {
726   // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
727   static constexpr const char kLoaderDecls[] = R"(
728 extern "C" {
729 // libloaderapi.h
730 
731 // WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
732 /* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
733 
734 // WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
735 /* __declspec(dllimport) */ int __stdcall FreeModule(void *);
736 
737 // WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE, LPSTR, DWORD);
738 /* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
739 
740 // WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
741 /* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
742 }
743   )";
744 
745   if (DynamicLoader *loader = process->GetDynamicLoader()) {
746     Status result = loader->CanLoadImage();
747     if (result.Fail())
748       return result;
749   }
750 
751   ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
752   if (!thread)
753     return Status("selected thread is invalid");
754 
755   StackFrameSP frame = thread->GetStackFrameAtIndex(0);
756   if (!frame)
757     return Status("frame 0 is invalid");
758 
759   ExecutionContext context;
760   frame->CalculateExecutionContext(context);
761 
762   EvaluateExpressionOptions options;
763   options.SetUnwindOnError(true);
764   options.SetIgnoreBreakpoints(true);
765   options.SetExecutionPolicy(eExecutionPolicyAlways);
766   options.SetLanguage(eLanguageTypeC_plus_plus);
767   // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
768   // They may potentially throw SEH exceptions which we do not know how to
769   // handle currently.
770   options.SetTrapExceptions(false);
771   options.SetTimeout(process->GetUtilityExpressionTimeout());
772 
773   Status error;
774   ExpressionResults result = UserExpression::Evaluate(
775       context, options, expression, kLoaderDecls, value, error);
776   if (result != eExpressionCompleted)
777     return error;
778 
779   if (value->GetError().Fail())
780     return value->GetError();
781 
782   return Status();
783 }
784