xref: /llvm-project/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp (revision 6a8a4d51a4415aa453b79f999bed411bad6c3723)
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 #include <optional>
13 #if defined(_WIN32)
14 #include "lldb/Host/windows/windows.h"
15 #include <winsock2.h>
16 #endif
17 
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 
37 using namespace lldb;
38 using namespace lldb_private;
39 
40 LLDB_PLUGIN_DEFINE(PlatformWindows)
41 
42 static uint32_t g_initialize_count = 0;
43 
44 PlatformSP PlatformWindows::CreateInstance(bool force,
45                                            const lldb_private::ArchSpec *arch) {
46   // The only time we create an instance is when we are creating a remote
47   // windows platform
48   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 
86 llvm::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 
91 void 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 #endif
101     PluginManager::RegisterPlugin(
102         PlatformWindows::GetPluginNameStatic(false),
103         PlatformWindows::GetPluginDescriptionStatic(false),
104         PlatformWindows::CreateInstance);
105   }
106 }
107 
108 void 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 Constructor
119 PlatformWindows::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 
133 Status 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     } else
155       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 
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 = 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 path
278   // 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 to
378   // 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 
432 Status 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 
460 Status 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     else
471       error =
472           Status::FromErrorString("the platform is not currently connected");
473   }
474   return error;
475 }
476 
477 ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
478                                         Debugger &debugger, Target &target,
479                                         Status &error) {
480   // Windows has special considerations that must be followed when launching or
481   // attaching to a process.  The key requirement is that when launching or
482   // attaching to a process, you must do it from the same the thread that will
483   // go into a permanent loop which will then receive debug events from the
484   // process.  In particular, this means we can't use any of LLDB's generic
485   // mechanisms to do it for us, because it doesn't have the special knowledge
486   // 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 process
489   // is to first launch it, have it stop at the entry point, and then attach to
490   // it.  In Windows this doesn't quite work, you have to specify as an
491   // argument to CreateProcess() that you're going to debug the process.  So we
492   // override DebugProcess here to handle this.  Launch operations go directly
493   // to the process plugin, and attach operations almost go directly to the
494   // process plugin (but we hijack the events first).  In essence, we
495   // encapsulate all the logic of Launching and Attaching in the process
496   // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
497   // 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     else
504       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 
528 lldb::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     else
538       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 
567 void PlatformWindows::GetStatus(Stream &strm) {
568   Platform::GetStatus(strm);
569 
570 #ifdef _WIN32
571   llvm::VersionTuple version = HostInfo::GetOSVersion();
572   strm << "      Host: Windows " << version.getAsString() << '\n';
573 #endif
574 }
575 
576 bool PlatformWindows::CanDebugProcess() { return true; }
577 
578 ConstString 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 
587 size_t
588 PlatformWindows::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 #0xf000
598     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 #0xfe
609     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 
622 std::unique_ptr<UtilityFunction>
623 PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
624                                               Status &status) {
625   // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
626   static constexpr const char kLoaderDecls[] = R"(
627 extern "C" {
628 // errhandlingapi.h
629 
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 cannot
633 // be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
634 //
635 // This value represents the recommended maximum number of directories an
636 // application should include in its DLL search path.
637 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
638 
639 // WINBASEAPI DWORD WINAPI GetLastError(VOID);
640 /* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
641 
642 // libloaderapi.h
643 
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.h
657 
658 // _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
659 /* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
660 
661 // lldb specific code
662 
663 struct __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 
673 void * __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   else
685     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);  // name
726   parameters.PushValue(value);  // paths
727 
728   value.SetCompilerType(VoidPtrTy);
729   parameters.PushValue(value);  // result
730 
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 
751 Status 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"(
756 extern "C" {
757 // libloaderapi.h
758 
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 to
797   // 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