xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- PlatformWindows.cpp -----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "PlatformWindows.h"
10061da546Spatrick 
11be691f3bSpatrick #include <cstdio>
12*f6aab3d8Srobert #include <optional>
13061da546Spatrick #if defined(_WIN32)
14061da546Spatrick #include "lldb/Host/windows/windows.h"
15061da546Spatrick #include <winsock2.h>
16061da546Spatrick #endif
17061da546Spatrick 
18*f6aab3d8Srobert #include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
19*f6aab3d8Srobert #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
20061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
21061da546Spatrick #include "lldb/Breakpoint/BreakpointSite.h"
22061da546Spatrick #include "lldb/Core/Debugger.h"
23061da546Spatrick #include "lldb/Core/Module.h"
24061da546Spatrick #include "lldb/Core/PluginManager.h"
25*f6aab3d8Srobert #include "lldb/Expression/DiagnosticManager.h"
26*f6aab3d8Srobert #include "lldb/Expression/FunctionCaller.h"
27*f6aab3d8Srobert #include "lldb/Expression/UserExpression.h"
28*f6aab3d8Srobert #include "lldb/Expression/UtilityFunction.h"
29061da546Spatrick #include "lldb/Host/HostInfo.h"
30*f6aab3d8Srobert #include "lldb/Target/DynamicLoader.h"
31061da546Spatrick #include "lldb/Target/Process.h"
32061da546Spatrick #include "lldb/Utility/Status.h"
33061da546Spatrick 
34*f6aab3d8Srobert #include "llvm/ADT/ScopeExit.h"
35*f6aab3d8Srobert #include "llvm/Support/ConvertUTF.h"
36*f6aab3d8Srobert 
37061da546Spatrick using namespace lldb;
38061da546Spatrick using namespace lldb_private;
39061da546Spatrick 
40dda28197Spatrick LLDB_PLUGIN_DEFINE(PlatformWindows)
41dda28197Spatrick 
42061da546Spatrick static uint32_t g_initialize_count = 0;
43061da546Spatrick 
CreateInstance(bool force,const lldb_private::ArchSpec * arch)44061da546Spatrick PlatformSP PlatformWindows::CreateInstance(bool force,
45061da546Spatrick                                            const lldb_private::ArchSpec *arch) {
46061da546Spatrick   // The only time we create an instance is when we are creating a remote
47061da546Spatrick   // windows platform
48061da546Spatrick   const bool is_host = false;
49061da546Spatrick 
50061da546Spatrick   bool create = force;
51061da546Spatrick   if (!create && arch && arch->IsValid()) {
52061da546Spatrick     const llvm::Triple &triple = arch->GetTriple();
53061da546Spatrick     switch (triple.getVendor()) {
54061da546Spatrick     case llvm::Triple::PC:
55061da546Spatrick       create = true;
56061da546Spatrick       break;
57061da546Spatrick 
58061da546Spatrick     case llvm::Triple::UnknownVendor:
59061da546Spatrick       create = !arch->TripleVendorWasSpecified();
60061da546Spatrick       break;
61061da546Spatrick 
62061da546Spatrick     default:
63061da546Spatrick       break;
64061da546Spatrick     }
65061da546Spatrick 
66061da546Spatrick     if (create) {
67061da546Spatrick       switch (triple.getOS()) {
68061da546Spatrick       case llvm::Triple::Win32:
69061da546Spatrick         break;
70061da546Spatrick 
71061da546Spatrick       case llvm::Triple::UnknownOS:
72061da546Spatrick         create = arch->TripleOSWasSpecified();
73061da546Spatrick         break;
74061da546Spatrick 
75061da546Spatrick       default:
76061da546Spatrick         create = false;
77061da546Spatrick         break;
78061da546Spatrick       }
79061da546Spatrick     }
80061da546Spatrick   }
81061da546Spatrick   if (create)
82061da546Spatrick     return PlatformSP(new PlatformWindows(is_host));
83061da546Spatrick   return PlatformSP();
84061da546Spatrick }
85061da546Spatrick 
GetPluginDescriptionStatic(bool is_host)86*f6aab3d8Srobert llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
87061da546Spatrick   return is_host ? "Local Windows user platform plug-in."
88061da546Spatrick                  : "Remote Windows user platform plug-in.";
89061da546Spatrick }
90061da546Spatrick 
Initialize()91061da546Spatrick void PlatformWindows::Initialize() {
92061da546Spatrick   Platform::Initialize();
93061da546Spatrick 
94061da546Spatrick   if (g_initialize_count++ == 0) {
95061da546Spatrick #if defined(_WIN32)
96061da546Spatrick     // Force a host flag to true for the default platform object.
97061da546Spatrick     PlatformSP default_platform_sp(new PlatformWindows(true));
98061da546Spatrick     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
99061da546Spatrick     Platform::SetHostPlatform(default_platform_sp);
100061da546Spatrick #endif
101061da546Spatrick     PluginManager::RegisterPlugin(
102061da546Spatrick         PlatformWindows::GetPluginNameStatic(false),
103061da546Spatrick         PlatformWindows::GetPluginDescriptionStatic(false),
104061da546Spatrick         PlatformWindows::CreateInstance);
105061da546Spatrick   }
106061da546Spatrick }
107061da546Spatrick 
Terminate()108061da546Spatrick void PlatformWindows::Terminate() {
109061da546Spatrick   if (g_initialize_count > 0) {
110061da546Spatrick     if (--g_initialize_count == 0) {
111061da546Spatrick       PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);
112061da546Spatrick     }
113061da546Spatrick   }
114061da546Spatrick 
115061da546Spatrick   Platform::Terminate();
116061da546Spatrick }
117061da546Spatrick 
118061da546Spatrick /// Default Constructor
PlatformWindows(bool is_host)119*f6aab3d8Srobert PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {
120*f6aab3d8Srobert   const auto &AddArch = [&](const ArchSpec &spec) {
121*f6aab3d8Srobert     if (llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) {
122*f6aab3d8Srobert           return spec.IsExactMatch(rhs);
123*f6aab3d8Srobert         }))
124*f6aab3d8Srobert       return;
125*f6aab3d8Srobert     if (spec.IsValid())
126*f6aab3d8Srobert       m_supported_architectures.push_back(spec);
127*f6aab3d8Srobert   };
128*f6aab3d8Srobert   AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
129*f6aab3d8Srobert   AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
130*f6aab3d8Srobert   AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
131*f6aab3d8Srobert }
132061da546Spatrick 
ConnectRemote(Args & args)133061da546Spatrick Status PlatformWindows::ConnectRemote(Args &args) {
134061da546Spatrick   Status error;
135061da546Spatrick   if (IsHost()) {
136*f6aab3d8Srobert     error.SetErrorStringWithFormatv(
137*f6aab3d8Srobert         "can't connect to the host platform '{0}', always connected",
138*f6aab3d8Srobert         GetPluginName());
139061da546Spatrick   } else {
140061da546Spatrick     if (!m_remote_platform_sp)
141061da546Spatrick       m_remote_platform_sp =
142*f6aab3d8Srobert           platform_gdb_server::PlatformRemoteGDBServer::CreateInstance(
143*f6aab3d8Srobert               /*force=*/true, nullptr);
144061da546Spatrick 
145061da546Spatrick     if (m_remote_platform_sp) {
146061da546Spatrick       if (error.Success()) {
147061da546Spatrick         if (m_remote_platform_sp) {
148061da546Spatrick           error = m_remote_platform_sp->ConnectRemote(args);
149061da546Spatrick         } else {
150061da546Spatrick           error.SetErrorString(
151061da546Spatrick               "\"platform connect\" takes a single argument: <connect-url>");
152061da546Spatrick         }
153061da546Spatrick       }
154061da546Spatrick     } else
155061da546Spatrick       error.SetErrorString("failed to create a 'remote-gdb-server' platform");
156061da546Spatrick 
157061da546Spatrick     if (error.Fail())
158061da546Spatrick       m_remote_platform_sp.reset();
159061da546Spatrick   }
160061da546Spatrick 
161061da546Spatrick   return error;
162061da546Spatrick }
163061da546Spatrick 
DoLoadImage(Process * process,const FileSpec & remote_file,const std::vector<std::string> * paths,Status & error,FileSpec * loaded_image)164*f6aab3d8Srobert uint32_t PlatformWindows::DoLoadImage(Process *process,
165*f6aab3d8Srobert                                       const FileSpec &remote_file,
166*f6aab3d8Srobert                                       const std::vector<std::string> *paths,
167*f6aab3d8Srobert                                       Status &error, FileSpec *loaded_image) {
168*f6aab3d8Srobert   DiagnosticManager diagnostics;
169*f6aab3d8Srobert 
170*f6aab3d8Srobert   if (loaded_image)
171*f6aab3d8Srobert     loaded_image->Clear();
172*f6aab3d8Srobert 
173*f6aab3d8Srobert   ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
174*f6aab3d8Srobert   if (!thread) {
175*f6aab3d8Srobert     error.SetErrorString("LoadLibrary error: no thread available to invoke LoadLibrary");
176*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
177*f6aab3d8Srobert   }
178*f6aab3d8Srobert 
179*f6aab3d8Srobert   ExecutionContext context;
180*f6aab3d8Srobert   thread->CalculateExecutionContext(context);
181*f6aab3d8Srobert 
182*f6aab3d8Srobert   Status status;
183*f6aab3d8Srobert   UtilityFunction *loader =
184*f6aab3d8Srobert       process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {
185*f6aab3d8Srobert         return MakeLoadImageUtilityFunction(context, status);
186*f6aab3d8Srobert       });
187*f6aab3d8Srobert   if (loader == nullptr)
188*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
189*f6aab3d8Srobert 
190*f6aab3d8Srobert   FunctionCaller *invocation = loader->GetFunctionCaller();
191*f6aab3d8Srobert   if (!invocation) {
192*f6aab3d8Srobert     error.SetErrorString("LoadLibrary error: could not get function caller");
193*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
194*f6aab3d8Srobert   }
195*f6aab3d8Srobert 
196*f6aab3d8Srobert   /* Convert name */
197*f6aab3d8Srobert   llvm::SmallVector<llvm::UTF16, 261> name;
198*f6aab3d8Srobert   if (!llvm::convertUTF8ToUTF16String(remote_file.GetPath(), name)) {
199*f6aab3d8Srobert     error.SetErrorString("LoadLibrary error: could not convert path to UCS2");
200*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
201*f6aab3d8Srobert   }
202*f6aab3d8Srobert   name.emplace_back(L'\0');
203*f6aab3d8Srobert 
204*f6aab3d8Srobert   /* Inject name paramter into inferior */
205*f6aab3d8Srobert   lldb::addr_t injected_name =
206*f6aab3d8Srobert       process->AllocateMemory(name.size() * sizeof(llvm::UTF16),
207*f6aab3d8Srobert                               ePermissionsReadable | ePermissionsWritable,
208*f6aab3d8Srobert                               status);
209*f6aab3d8Srobert   if (injected_name == LLDB_INVALID_ADDRESS) {
210*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for name: %s",
211*f6aab3d8Srobert                                    status.AsCString());
212*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
213*f6aab3d8Srobert   }
214*f6aab3d8Srobert 
215*f6aab3d8Srobert   auto name_cleanup = llvm::make_scope_exit([process, injected_name]() {
216*f6aab3d8Srobert     process->DeallocateMemory(injected_name);
217*f6aab3d8Srobert   });
218*f6aab3d8Srobert 
219*f6aab3d8Srobert   process->WriteMemory(injected_name, name.data(),
220*f6aab3d8Srobert                        name.size() * sizeof(llvm::UTF16), status);
221*f6aab3d8Srobert   if (status.Fail()) {
222*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: unable to write name: %s",
223*f6aab3d8Srobert                                    status.AsCString());
224*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
225*f6aab3d8Srobert   }
226*f6aab3d8Srobert 
227*f6aab3d8Srobert   /* Inject paths parameter into inferior */
228*f6aab3d8Srobert   lldb::addr_t injected_paths{0x0};
229*f6aab3d8Srobert   std::optional<llvm::detail::scope_exit<std::function<void()>>> paths_cleanup;
230*f6aab3d8Srobert   if (paths) {
231*f6aab3d8Srobert     llvm::SmallVector<llvm::UTF16, 261> search_paths;
232*f6aab3d8Srobert 
233*f6aab3d8Srobert     for (const auto &path : *paths) {
234*f6aab3d8Srobert       if (path.empty())
235*f6aab3d8Srobert         continue;
236*f6aab3d8Srobert 
237*f6aab3d8Srobert       llvm::SmallVector<llvm::UTF16, 261> buffer;
238*f6aab3d8Srobert       if (!llvm::convertUTF8ToUTF16String(path, buffer))
239*f6aab3d8Srobert         continue;
240*f6aab3d8Srobert 
241*f6aab3d8Srobert       search_paths.append(std::begin(buffer), std::end(buffer));
242*f6aab3d8Srobert       search_paths.emplace_back(L'\0');
243*f6aab3d8Srobert     }
244*f6aab3d8Srobert     search_paths.emplace_back(L'\0');
245*f6aab3d8Srobert 
246*f6aab3d8Srobert     injected_paths =
247*f6aab3d8Srobert         process->AllocateMemory(search_paths.size() * sizeof(llvm::UTF16),
248*f6aab3d8Srobert                                 ePermissionsReadable | ePermissionsWritable,
249*f6aab3d8Srobert                                 status);
250*f6aab3d8Srobert     if (injected_paths == LLDB_INVALID_ADDRESS) {
251*f6aab3d8Srobert       error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for paths: %s",
252*f6aab3d8Srobert                                      status.AsCString());
253*f6aab3d8Srobert       return LLDB_INVALID_IMAGE_TOKEN;
254*f6aab3d8Srobert     }
255*f6aab3d8Srobert 
256*f6aab3d8Srobert     paths_cleanup.emplace([process, injected_paths]() {
257*f6aab3d8Srobert       process->DeallocateMemory(injected_paths);
258*f6aab3d8Srobert     });
259*f6aab3d8Srobert 
260*f6aab3d8Srobert     process->WriteMemory(injected_paths, search_paths.data(),
261*f6aab3d8Srobert                          search_paths.size() * sizeof(llvm::UTF16), status);
262*f6aab3d8Srobert     if (status.Fail()) {
263*f6aab3d8Srobert       error.SetErrorStringWithFormat("LoadLibrary error: unable to write paths: %s",
264*f6aab3d8Srobert                                      status.AsCString());
265*f6aab3d8Srobert       return LLDB_INVALID_IMAGE_TOKEN;
266*f6aab3d8Srobert     }
267*f6aab3d8Srobert   }
268*f6aab3d8Srobert 
269*f6aab3d8Srobert   /* Inject wszModulePath into inferior */
270*f6aab3d8Srobert   // FIXME(compnerd) should do something better for the length?
271*f6aab3d8Srobert   // GetModuleFileNameA is likely limited to PATH_MAX rather than the NT path
272*f6aab3d8Srobert   // limit.
273*f6aab3d8Srobert   unsigned injected_length = 261;
274*f6aab3d8Srobert 
275*f6aab3d8Srobert   lldb::addr_t injected_module_path =
276*f6aab3d8Srobert       process->AllocateMemory(injected_length + 1,
277*f6aab3d8Srobert                               ePermissionsReadable | ePermissionsWritable,
278*f6aab3d8Srobert                               status);
279*f6aab3d8Srobert   if (injected_module_path == LLDB_INVALID_ADDRESS) {
280*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for module location: %s",
281*f6aab3d8Srobert                                    status.AsCString());
282*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
283*f6aab3d8Srobert   }
284*f6aab3d8Srobert 
285*f6aab3d8Srobert   auto injected_module_path_cleanup =
286*f6aab3d8Srobert       llvm::make_scope_exit([process, injected_module_path]() {
287*f6aab3d8Srobert     process->DeallocateMemory(injected_module_path);
288*f6aab3d8Srobert   });
289*f6aab3d8Srobert 
290*f6aab3d8Srobert   /* Inject __lldb_LoadLibraryResult into inferior */
291*f6aab3d8Srobert   const uint32_t word_size = process->GetAddressByteSize();
292*f6aab3d8Srobert   lldb::addr_t injected_result =
293*f6aab3d8Srobert       process->AllocateMemory(3 * word_size,
294*f6aab3d8Srobert                               ePermissionsReadable | ePermissionsWritable,
295*f6aab3d8Srobert                               status);
296*f6aab3d8Srobert   if (status.Fail()) {
297*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: could not allocate memory for result: %s",
298*f6aab3d8Srobert                                    status.AsCString());
299*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
300*f6aab3d8Srobert   }
301*f6aab3d8Srobert 
302*f6aab3d8Srobert   auto result_cleanup = llvm::make_scope_exit([process, injected_result]() {
303*f6aab3d8Srobert     process->DeallocateMemory(injected_result);
304*f6aab3d8Srobert   });
305*f6aab3d8Srobert 
306*f6aab3d8Srobert   process->WritePointerToMemory(injected_result + word_size,
307*f6aab3d8Srobert                                 injected_module_path, status);
308*f6aab3d8Srobert   if (status.Fail()) {
309*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: could not initialize result: %s",
310*f6aab3d8Srobert                                    status.AsCString());
311*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
312*f6aab3d8Srobert   }
313*f6aab3d8Srobert 
314*f6aab3d8Srobert   // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
315*f6aab3d8Srobert   process->WriteScalarToMemory(injected_result + 2 * word_size,
316*f6aab3d8Srobert                                Scalar{injected_length}, sizeof(unsigned),
317*f6aab3d8Srobert                                status);
318*f6aab3d8Srobert   if (status.Fail()) {
319*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: could not initialize result: %s",
320*f6aab3d8Srobert                                    status.AsCString());
321*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
322*f6aab3d8Srobert   }
323*f6aab3d8Srobert 
324*f6aab3d8Srobert   /* Setup Formal Parameters */
325*f6aab3d8Srobert   ValueList parameters = invocation->GetArgumentValues();
326*f6aab3d8Srobert   parameters.GetValueAtIndex(0)->GetScalar() = injected_name;
327*f6aab3d8Srobert   parameters.GetValueAtIndex(1)->GetScalar() = injected_paths;
328*f6aab3d8Srobert   parameters.GetValueAtIndex(2)->GetScalar() = injected_result;
329*f6aab3d8Srobert 
330*f6aab3d8Srobert   lldb::addr_t injected_parameters = LLDB_INVALID_ADDRESS;
331*f6aab3d8Srobert   diagnostics.Clear();
332*f6aab3d8Srobert   if (!invocation->WriteFunctionArguments(context, injected_parameters,
333*f6aab3d8Srobert                                           parameters, diagnostics)) {
334*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: unable to write function parameters: %s",
335*f6aab3d8Srobert                                    diagnostics.GetString().c_str());
336*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
337*f6aab3d8Srobert   }
338*f6aab3d8Srobert 
339*f6aab3d8Srobert   auto parameter_cleanup =
340*f6aab3d8Srobert       llvm::make_scope_exit([invocation, &context, injected_parameters]() {
341*f6aab3d8Srobert         invocation->DeallocateFunctionResults(context, injected_parameters);
342*f6aab3d8Srobert       });
343*f6aab3d8Srobert 
344*f6aab3d8Srobert   TypeSystemClangSP scratch_ts_sp =
345*f6aab3d8Srobert       ScratchTypeSystemClang::GetForTarget(process->GetTarget());
346*f6aab3d8Srobert   if (!scratch_ts_sp) {
347*f6aab3d8Srobert     error.SetErrorString("LoadLibrary error: unable to get (clang) type system");
348*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
349*f6aab3d8Srobert   }
350*f6aab3d8Srobert 
351*f6aab3d8Srobert   /* Setup Return Type */
352*f6aab3d8Srobert   CompilerType VoidPtrTy =
353*f6aab3d8Srobert       scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
354*f6aab3d8Srobert 
355*f6aab3d8Srobert   Value value;
356*f6aab3d8Srobert   value.SetCompilerType(VoidPtrTy);
357*f6aab3d8Srobert 
358*f6aab3d8Srobert   /* Invoke expression */
359*f6aab3d8Srobert   EvaluateExpressionOptions options;
360*f6aab3d8Srobert   options.SetExecutionPolicy(eExecutionPolicyAlways);
361*f6aab3d8Srobert   options.SetLanguage(eLanguageTypeC_plus_plus);
362*f6aab3d8Srobert   options.SetIgnoreBreakpoints(true);
363*f6aab3d8Srobert   options.SetUnwindOnError(true);
364*f6aab3d8Srobert   // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
365*f6aab3d8Srobert   // They may potentially throw SEH exceptions which we do not know how to
366*f6aab3d8Srobert   // handle currently.
367*f6aab3d8Srobert   options.SetTrapExceptions(false);
368*f6aab3d8Srobert   options.SetTimeout(process->GetUtilityExpressionTimeout());
369*f6aab3d8Srobert   options.SetIsForUtilityExpr(true);
370*f6aab3d8Srobert 
371*f6aab3d8Srobert   ExpressionResults result =
372*f6aab3d8Srobert       invocation->ExecuteFunction(context, &injected_parameters, options,
373*f6aab3d8Srobert                                   diagnostics, value);
374*f6aab3d8Srobert   if (result != eExpressionCompleted) {
375*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: failed to execute LoadLibrary helper: %s",
376*f6aab3d8Srobert                                    diagnostics.GetString().c_str());
377*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
378*f6aab3d8Srobert   }
379*f6aab3d8Srobert 
380*f6aab3d8Srobert   /* Read result */
381*f6aab3d8Srobert   lldb::addr_t token = process->ReadPointerFromMemory(injected_result, status);
382*f6aab3d8Srobert   if (status.Fail()) {
383*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: could not read the result: %s",
384*f6aab3d8Srobert                                    status.AsCString());
385*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
386*f6aab3d8Srobert   }
387*f6aab3d8Srobert 
388*f6aab3d8Srobert   if (!token) {
389*f6aab3d8Srobert     // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
390*f6aab3d8Srobert     uint64_t error_code =
391*f6aab3d8Srobert         process->ReadUnsignedIntegerFromMemory(injected_result + 2 * word_size + sizeof(unsigned),
392*f6aab3d8Srobert                                                word_size, 0, status);
393*f6aab3d8Srobert     if (status.Fail()) {
394*f6aab3d8Srobert       error.SetErrorStringWithFormat("LoadLibrary error: could not read error status: %s",
395*f6aab3d8Srobert                                      status.AsCString());
396*f6aab3d8Srobert       return LLDB_INVALID_IMAGE_TOKEN;
397*f6aab3d8Srobert     }
398*f6aab3d8Srobert 
399*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary Error: %" PRIu64, error_code);
400*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
401*f6aab3d8Srobert   }
402*f6aab3d8Srobert 
403*f6aab3d8Srobert   std::string module_path;
404*f6aab3d8Srobert   process->ReadCStringFromMemory(injected_module_path, module_path, status);
405*f6aab3d8Srobert   if (status.Fail()) {
406*f6aab3d8Srobert     error.SetErrorStringWithFormat("LoadLibrary error: could not read module path: %s",
407*f6aab3d8Srobert                                    status.AsCString());
408*f6aab3d8Srobert     return LLDB_INVALID_IMAGE_TOKEN;
409*f6aab3d8Srobert   }
410*f6aab3d8Srobert 
411*f6aab3d8Srobert   if (loaded_image)
412*f6aab3d8Srobert     loaded_image->SetFile(module_path, llvm::sys::path::Style::native);
413*f6aab3d8Srobert   return process->AddImageToken(token);
414*f6aab3d8Srobert }
415*f6aab3d8Srobert 
UnloadImage(Process * process,uint32_t image_token)416*f6aab3d8Srobert Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {
417*f6aab3d8Srobert   const addr_t address = process->GetImagePtrFromToken(image_token);
418*f6aab3d8Srobert   if (address == LLDB_INVALID_ADDRESS)
419*f6aab3d8Srobert     return Status("invalid image token");
420*f6aab3d8Srobert 
421*f6aab3d8Srobert   StreamString expression;
422*f6aab3d8Srobert   expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);
423*f6aab3d8Srobert 
424*f6aab3d8Srobert   ValueObjectSP value;
425*f6aab3d8Srobert   Status result =
426*f6aab3d8Srobert       EvaluateLoaderExpression(process, expression.GetData(), value);
427*f6aab3d8Srobert   if (result.Fail())
428*f6aab3d8Srobert     return result;
429*f6aab3d8Srobert 
430*f6aab3d8Srobert   if (value->GetError().Fail())
431*f6aab3d8Srobert     return value->GetError();
432*f6aab3d8Srobert 
433*f6aab3d8Srobert   Scalar scalar;
434*f6aab3d8Srobert   if (value->ResolveValue(scalar)) {
435*f6aab3d8Srobert     if (scalar.UInt(1))
436*f6aab3d8Srobert       return Status("expression failed: \"%s\"", expression.GetData());
437*f6aab3d8Srobert     process->ResetImageToken(image_token);
438*f6aab3d8Srobert   }
439*f6aab3d8Srobert 
440*f6aab3d8Srobert   return Status();
441*f6aab3d8Srobert }
442*f6aab3d8Srobert 
DisconnectRemote()443061da546Spatrick Status PlatformWindows::DisconnectRemote() {
444061da546Spatrick   Status error;
445061da546Spatrick 
446061da546Spatrick   if (IsHost()) {
447*f6aab3d8Srobert     error.SetErrorStringWithFormatv(
448*f6aab3d8Srobert         "can't disconnect from the host platform '{0}', always connected",
449*f6aab3d8Srobert         GetPluginName());
450061da546Spatrick   } else {
451061da546Spatrick     if (m_remote_platform_sp)
452061da546Spatrick       error = m_remote_platform_sp->DisconnectRemote();
453061da546Spatrick     else
454061da546Spatrick       error.SetErrorString("the platform is not currently connected");
455061da546Spatrick   }
456061da546Spatrick   return error;
457061da546Spatrick }
458061da546Spatrick 
DebugProcess(ProcessLaunchInfo & launch_info,Debugger & debugger,Target & target,Status & error)459061da546Spatrick ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
460*f6aab3d8Srobert                                         Debugger &debugger, Target &target,
461061da546Spatrick                                         Status &error) {
462061da546Spatrick   // Windows has special considerations that must be followed when launching or
463061da546Spatrick   // attaching to a process.  The key requirement is that when launching or
464061da546Spatrick   // attaching to a process, you must do it from the same the thread that will
465061da546Spatrick   // go into a permanent loop which will then receive debug events from the
466061da546Spatrick   // process.  In particular, this means we can't use any of LLDB's generic
467061da546Spatrick   // mechanisms to do it for us, because it doesn't have the special knowledge
468061da546Spatrick   // required for setting up the background thread or passing the right flags.
469061da546Spatrick   //
470061da546Spatrick   // Another problem is that that LLDB's standard model for debugging a process
471061da546Spatrick   // is to first launch it, have it stop at the entry point, and then attach to
472061da546Spatrick   // it.  In Windows this doesn't quite work, you have to specify as an
473061da546Spatrick   // argument to CreateProcess() that you're going to debug the process.  So we
474061da546Spatrick   // override DebugProcess here to handle this.  Launch operations go directly
475061da546Spatrick   // to the process plugin, and attach operations almost go directly to the
476061da546Spatrick   // process plugin (but we hijack the events first).  In essence, we
477061da546Spatrick   // encapsulate all the logic of Launching and Attaching in the process
478061da546Spatrick   // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
479061da546Spatrick   // the process plugin.
480061da546Spatrick 
481061da546Spatrick   if (IsRemote()) {
482061da546Spatrick     if (m_remote_platform_sp)
483061da546Spatrick       return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,
484061da546Spatrick                                                 error);
485061da546Spatrick     else
486061da546Spatrick       error.SetErrorString("the platform is not currently connected");
487061da546Spatrick   }
488061da546Spatrick 
489061da546Spatrick   if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
490061da546Spatrick     // This is a process attach.  Don't need to launch anything.
491061da546Spatrick     ProcessAttachInfo attach_info(launch_info);
492*f6aab3d8Srobert     return Attach(attach_info, debugger, &target, error);
493*f6aab3d8Srobert   }
494*f6aab3d8Srobert 
495*f6aab3d8Srobert   ProcessSP process_sp =
496*f6aab3d8Srobert       target.CreateProcess(launch_info.GetListener(),
497*f6aab3d8Srobert                            launch_info.GetProcessPluginName(), nullptr, false);
498*f6aab3d8Srobert 
499*f6aab3d8Srobert   process_sp->HijackProcessEvents(launch_info.GetHijackListener());
500061da546Spatrick 
501061da546Spatrick   // We need to launch and attach to the process.
502061da546Spatrick   launch_info.GetFlags().Set(eLaunchFlagDebug);
503061da546Spatrick   if (process_sp)
504061da546Spatrick     error = process_sp->Launch(launch_info);
505061da546Spatrick 
506061da546Spatrick   return process_sp;
507061da546Spatrick }
508061da546Spatrick 
Attach(ProcessAttachInfo & attach_info,Debugger & debugger,Target * target,Status & error)509061da546Spatrick lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,
510061da546Spatrick                                         Debugger &debugger, Target *target,
511061da546Spatrick                                         Status &error) {
512061da546Spatrick   error.Clear();
513061da546Spatrick   lldb::ProcessSP process_sp;
514061da546Spatrick   if (!IsHost()) {
515061da546Spatrick     if (m_remote_platform_sp)
516061da546Spatrick       process_sp =
517061da546Spatrick           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
518061da546Spatrick     else
519061da546Spatrick       error.SetErrorString("the platform is not currently connected");
520061da546Spatrick     return process_sp;
521061da546Spatrick   }
522061da546Spatrick 
523061da546Spatrick   if (target == nullptr) {
524061da546Spatrick     TargetSP new_target_sp;
525061da546Spatrick     FileSpec emptyFileSpec;
526061da546Spatrick     ArchSpec emptyArchSpec;
527061da546Spatrick 
528061da546Spatrick     error = debugger.GetTargetList().CreateTarget(
529061da546Spatrick         debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
530061da546Spatrick     target = new_target_sp.get();
531061da546Spatrick   }
532061da546Spatrick 
533061da546Spatrick   if (!target || error.Fail())
534061da546Spatrick     return process_sp;
535061da546Spatrick 
536061da546Spatrick   const char *plugin_name = attach_info.GetProcessPluginName();
537061da546Spatrick   process_sp = target->CreateProcess(
538be691f3bSpatrick       attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false);
539061da546Spatrick 
540061da546Spatrick   process_sp->HijackProcessEvents(attach_info.GetHijackListener());
541061da546Spatrick   if (process_sp)
542061da546Spatrick     error = process_sp->Attach(attach_info);
543061da546Spatrick 
544061da546Spatrick   return process_sp;
545061da546Spatrick }
546061da546Spatrick 
GetStatus(Stream & strm)547061da546Spatrick void PlatformWindows::GetStatus(Stream &strm) {
548061da546Spatrick   Platform::GetStatus(strm);
549061da546Spatrick 
550061da546Spatrick #ifdef _WIN32
551061da546Spatrick   llvm::VersionTuple version = HostInfo::GetOSVersion();
552061da546Spatrick   strm << "      Host: Windows " << version.getAsString() << '\n';
553061da546Spatrick #endif
554061da546Spatrick }
555061da546Spatrick 
CanDebugProcess()556061da546Spatrick bool PlatformWindows::CanDebugProcess() { return true; }
557061da546Spatrick 
GetFullNameForDylib(ConstString basename)558061da546Spatrick ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
559061da546Spatrick   if (basename.IsEmpty())
560061da546Spatrick     return basename;
561061da546Spatrick 
562061da546Spatrick   StreamString stream;
563061da546Spatrick   stream.Printf("%s.dll", basename.GetCString());
564061da546Spatrick   return ConstString(stream.GetString());
565061da546Spatrick }
566*f6aab3d8Srobert 
567*f6aab3d8Srobert size_t
GetSoftwareBreakpointTrapOpcode(Target & target,BreakpointSite * bp_site)568*f6aab3d8Srobert PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
569*f6aab3d8Srobert                                                  BreakpointSite *bp_site) {
570*f6aab3d8Srobert   ArchSpec arch = target.GetArchitecture();
571*f6aab3d8Srobert   assert(arch.IsValid());
572*f6aab3d8Srobert   const uint8_t *trap_opcode = nullptr;
573*f6aab3d8Srobert   size_t trap_opcode_size = 0;
574*f6aab3d8Srobert 
575*f6aab3d8Srobert   switch (arch.GetMachine()) {
576*f6aab3d8Srobert   case llvm::Triple::aarch64: {
577*f6aab3d8Srobert     static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
578*f6aab3d8Srobert     trap_opcode = g_aarch64_opcode;
579*f6aab3d8Srobert     trap_opcode_size = sizeof(g_aarch64_opcode);
580*f6aab3d8Srobert 
581*f6aab3d8Srobert     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
582*f6aab3d8Srobert       return trap_opcode_size;
583*f6aab3d8Srobert     return 0;
584*f6aab3d8Srobert   } break;
585*f6aab3d8Srobert 
586*f6aab3d8Srobert   case llvm::Triple::arm:
587*f6aab3d8Srobert   case llvm::Triple::thumb: {
588*f6aab3d8Srobert     static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
589*f6aab3d8Srobert     trap_opcode = g_thumb_opcode;
590*f6aab3d8Srobert     trap_opcode_size = sizeof(g_thumb_opcode);
591*f6aab3d8Srobert 
592*f6aab3d8Srobert     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
593*f6aab3d8Srobert       return trap_opcode_size;
594*f6aab3d8Srobert     return 0;
595*f6aab3d8Srobert   } break;
596*f6aab3d8Srobert 
597*f6aab3d8Srobert   default:
598*f6aab3d8Srobert     return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
599*f6aab3d8Srobert   }
600*f6aab3d8Srobert }
601*f6aab3d8Srobert 
602*f6aab3d8Srobert std::unique_ptr<UtilityFunction>
MakeLoadImageUtilityFunction(ExecutionContext & context,Status & status)603*f6aab3d8Srobert PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
604*f6aab3d8Srobert                                               Status &status) {
605*f6aab3d8Srobert   // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
606*f6aab3d8Srobert   static constexpr const char kLoaderDecls[] = R"(
607*f6aab3d8Srobert extern "C" {
608*f6aab3d8Srobert // errhandlingapi.h
609*f6aab3d8Srobert 
610*f6aab3d8Srobert // `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
611*f6aab3d8Srobert //
612*f6aab3d8Srobert // Directories in the standard search path are not searched. This value cannot
613*f6aab3d8Srobert // be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
614*f6aab3d8Srobert //
615*f6aab3d8Srobert // This value represents the recommended maximum number of directories an
616*f6aab3d8Srobert // application should include in its DLL search path.
617*f6aab3d8Srobert #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
618*f6aab3d8Srobert 
619*f6aab3d8Srobert // WINBASEAPI DWORD WINAPI GetLastError(VOID);
620*f6aab3d8Srobert /* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
621*f6aab3d8Srobert 
622*f6aab3d8Srobert // libloaderapi.h
623*f6aab3d8Srobert 
624*f6aab3d8Srobert // WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
625*f6aab3d8Srobert /* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
626*f6aab3d8Srobert 
627*f6aab3d8Srobert // WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
628*f6aab3d8Srobert /* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
629*f6aab3d8Srobert 
630*f6aab3d8Srobert // WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
631*f6aab3d8Srobert /* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
632*f6aab3d8Srobert 
633*f6aab3d8Srobert // WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
634*f6aab3d8Srobert /* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
635*f6aab3d8Srobert 
636*f6aab3d8Srobert // corecrt_wstring.h
637*f6aab3d8Srobert 
638*f6aab3d8Srobert // _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
639*f6aab3d8Srobert /* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
640*f6aab3d8Srobert 
641*f6aab3d8Srobert // lldb specific code
642*f6aab3d8Srobert 
643*f6aab3d8Srobert struct __lldb_LoadLibraryResult {
644*f6aab3d8Srobert   void *ImageBase;
645*f6aab3d8Srobert   char *ModulePath;
646*f6aab3d8Srobert   unsigned Length;
647*f6aab3d8Srobert   unsigned ErrorCode;
648*f6aab3d8Srobert };
649*f6aab3d8Srobert 
650*f6aab3d8Srobert _Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
651*f6aab3d8Srobert                "__lldb_LoadLibraryResult size mismatch");
652*f6aab3d8Srobert 
653*f6aab3d8Srobert void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
654*f6aab3d8Srobert                                 __lldb_LoadLibraryResult *result) {
655*f6aab3d8Srobert   for (const wchar_t *path = paths; path && *path; ) {
656*f6aab3d8Srobert     (void)AddDllDirectory(path);
657*f6aab3d8Srobert     path += wcslen(path) + 1;
658*f6aab3d8Srobert   }
659*f6aab3d8Srobert 
660*f6aab3d8Srobert   result->ImageBase = LoadLibraryExW(name, nullptr,
661*f6aab3d8Srobert                                      LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
662*f6aab3d8Srobert   if (result->ImageBase == nullptr)
663*f6aab3d8Srobert     result->ErrorCode = GetLastError();
664*f6aab3d8Srobert   else
665*f6aab3d8Srobert     result->Length = GetModuleFileNameA(result->ImageBase, result->ModulePath,
666*f6aab3d8Srobert                                         result->Length);
667*f6aab3d8Srobert 
668*f6aab3d8Srobert   return result->ImageBase;
669*f6aab3d8Srobert }
670*f6aab3d8Srobert }
671*f6aab3d8Srobert   )";
672*f6aab3d8Srobert 
673*f6aab3d8Srobert   static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
674*f6aab3d8Srobert 
675*f6aab3d8Srobert   ProcessSP process = context.GetProcessSP();
676*f6aab3d8Srobert   Target &target = process->GetTarget();
677*f6aab3d8Srobert 
678*f6aab3d8Srobert   auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
679*f6aab3d8Srobert                                                eLanguageTypeC_plus_plus,
680*f6aab3d8Srobert                                                context);
681*f6aab3d8Srobert   if (!function) {
682*f6aab3d8Srobert     std::string error = llvm::toString(function.takeError());
683*f6aab3d8Srobert     status.SetErrorStringWithFormat("LoadLibrary error: could not create utility function: %s",
684*f6aab3d8Srobert                                     error.c_str());
685*f6aab3d8Srobert     return nullptr;
686*f6aab3d8Srobert   }
687*f6aab3d8Srobert 
688*f6aab3d8Srobert   TypeSystemClangSP scratch_ts_sp =
689*f6aab3d8Srobert       ScratchTypeSystemClang::GetForTarget(target);
690*f6aab3d8Srobert   if (!scratch_ts_sp)
691*f6aab3d8Srobert     return nullptr;
692*f6aab3d8Srobert 
693*f6aab3d8Srobert   CompilerType VoidPtrTy =
694*f6aab3d8Srobert       scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
695*f6aab3d8Srobert   CompilerType WCharPtrTy =
696*f6aab3d8Srobert       scratch_ts_sp->GetBasicType(eBasicTypeWChar).GetPointerType();
697*f6aab3d8Srobert 
698*f6aab3d8Srobert   ValueList parameters;
699*f6aab3d8Srobert 
700*f6aab3d8Srobert   Value value;
701*f6aab3d8Srobert   value.SetValueType(Value::ValueType::Scalar);
702*f6aab3d8Srobert 
703*f6aab3d8Srobert   value.SetCompilerType(WCharPtrTy);
704*f6aab3d8Srobert   parameters.PushValue(value);  // name
705*f6aab3d8Srobert   parameters.PushValue(value);  // paths
706*f6aab3d8Srobert 
707*f6aab3d8Srobert   value.SetCompilerType(VoidPtrTy);
708*f6aab3d8Srobert   parameters.PushValue(value);  // result
709*f6aab3d8Srobert 
710*f6aab3d8Srobert   Status error;
711*f6aab3d8Srobert   std::unique_ptr<UtilityFunction> utility{std::move(*function)};
712*f6aab3d8Srobert   utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
713*f6aab3d8Srobert                               error);
714*f6aab3d8Srobert   if (error.Fail()) {
715*f6aab3d8Srobert     status.SetErrorStringWithFormat("LoadLibrary error: could not create function caller: %s",
716*f6aab3d8Srobert                                     error.AsCString());
717*f6aab3d8Srobert     return nullptr;
718*f6aab3d8Srobert   }
719*f6aab3d8Srobert 
720*f6aab3d8Srobert   if (!utility->GetFunctionCaller()) {
721*f6aab3d8Srobert     status.SetErrorString("LoadLibrary error: could not get function caller");
722*f6aab3d8Srobert     return nullptr;
723*f6aab3d8Srobert   }
724*f6aab3d8Srobert 
725*f6aab3d8Srobert   return utility;
726*f6aab3d8Srobert }
727*f6aab3d8Srobert 
EvaluateLoaderExpression(Process * process,const char * expression,ValueObjectSP & value)728*f6aab3d8Srobert Status PlatformWindows::EvaluateLoaderExpression(Process *process,
729*f6aab3d8Srobert                                                  const char *expression,
730*f6aab3d8Srobert                                                  ValueObjectSP &value) {
731*f6aab3d8Srobert   // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
732*f6aab3d8Srobert   static constexpr const char kLoaderDecls[] = R"(
733*f6aab3d8Srobert extern "C" {
734*f6aab3d8Srobert // libloaderapi.h
735*f6aab3d8Srobert 
736*f6aab3d8Srobert // WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
737*f6aab3d8Srobert /* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
738*f6aab3d8Srobert 
739*f6aab3d8Srobert // WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
740*f6aab3d8Srobert /* __declspec(dllimport) */ int __stdcall FreeModule(void *);
741*f6aab3d8Srobert 
742*f6aab3d8Srobert // WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE, LPSTR, DWORD);
743*f6aab3d8Srobert /* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
744*f6aab3d8Srobert 
745*f6aab3d8Srobert // WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
746*f6aab3d8Srobert /* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
747*f6aab3d8Srobert }
748*f6aab3d8Srobert   )";
749*f6aab3d8Srobert 
750*f6aab3d8Srobert   if (DynamicLoader *loader = process->GetDynamicLoader()) {
751*f6aab3d8Srobert     Status result = loader->CanLoadImage();
752*f6aab3d8Srobert     if (result.Fail())
753*f6aab3d8Srobert       return result;
754*f6aab3d8Srobert   }
755*f6aab3d8Srobert 
756*f6aab3d8Srobert   ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
757*f6aab3d8Srobert   if (!thread)
758*f6aab3d8Srobert     return Status("selected thread is invalid");
759*f6aab3d8Srobert 
760*f6aab3d8Srobert   StackFrameSP frame = thread->GetStackFrameAtIndex(0);
761*f6aab3d8Srobert   if (!frame)
762*f6aab3d8Srobert     return Status("frame 0 is invalid");
763*f6aab3d8Srobert 
764*f6aab3d8Srobert   ExecutionContext context;
765*f6aab3d8Srobert   frame->CalculateExecutionContext(context);
766*f6aab3d8Srobert 
767*f6aab3d8Srobert   EvaluateExpressionOptions options;
768*f6aab3d8Srobert   options.SetUnwindOnError(true);
769*f6aab3d8Srobert   options.SetIgnoreBreakpoints(true);
770*f6aab3d8Srobert   options.SetExecutionPolicy(eExecutionPolicyAlways);
771*f6aab3d8Srobert   options.SetLanguage(eLanguageTypeC_plus_plus);
772*f6aab3d8Srobert   // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
773*f6aab3d8Srobert   // They may potentially throw SEH exceptions which we do not know how to
774*f6aab3d8Srobert   // handle currently.
775*f6aab3d8Srobert   options.SetTrapExceptions(false);
776*f6aab3d8Srobert   options.SetTimeout(process->GetUtilityExpressionTimeout());
777*f6aab3d8Srobert 
778*f6aab3d8Srobert   Status error;
779*f6aab3d8Srobert   ExpressionResults result = UserExpression::Evaluate(
780*f6aab3d8Srobert       context, options, expression, kLoaderDecls, value, error);
781*f6aab3d8Srobert   if (result != eExpressionCompleted)
782*f6aab3d8Srobert     return error;
783*f6aab3d8Srobert 
784*f6aab3d8Srobert   if (value->GetError().Fail())
785*f6aab3d8Srobert     return value->GetError();
786*f6aab3d8Srobert 
787*f6aab3d8Srobert   return Status();
788*f6aab3d8Srobert }
789