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