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