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