180814287SRaphael Isemann //===-- PlatformWindows.cpp -----------------------------------------------===//
2a0154f98SDeepak Panickal //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a0154f98SDeepak Panickal //
7a0154f98SDeepak Panickal //===----------------------------------------------------------------------===//
8a0154f98SDeepak Panickal
9a0154f98SDeepak Panickal #include "PlatformWindows.h"
10a0154f98SDeepak Panickal
1176e47d48SRaphael Isemann #include <cstdio>
12a0154f98SDeepak Panickal #if defined(_WIN32)
13b4bc6496SHafiz Abid Qadeer #include "lldb/Host/windows/windows.h"
14a0154f98SDeepak Panickal #include <winsock2.h>
15a0154f98SDeepak Panickal #endif
16a0154f98SDeepak Panickal
17af921006SPavel Labath #include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
18af921006SPavel Labath #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
19a0154f98SDeepak Panickal #include "lldb/Breakpoint/BreakpointLocation.h"
20fc858813SZachary Turner #include "lldb/Breakpoint/BreakpointSite.h"
21b9c1b51eSKate Stone #include "lldb/Core/Debugger.h"
22b9c1b51eSKate Stone #include "lldb/Core/Module.h"
23b9c1b51eSKate Stone #include "lldb/Core/PluginManager.h"
24f1585a4bSSaleem Abdulrasool #include "lldb/Expression/DiagnosticManager.h"
25f1585a4bSSaleem Abdulrasool #include "lldb/Expression/FunctionCaller.h"
26f1585a4bSSaleem Abdulrasool #include "lldb/Expression/UserExpression.h"
27f1585a4bSSaleem Abdulrasool #include "lldb/Expression/UtilityFunction.h"
28b9c1b51eSKate Stone #include "lldb/Host/HostInfo.h"
29f1585a4bSSaleem Abdulrasool #include "lldb/Target/DynamicLoader.h"
30fc858813SZachary Turner #include "lldb/Target/Process.h"
3197206d57SZachary Turner #include "lldb/Utility/Status.h"
32a0154f98SDeepak Panickal
33f1585a4bSSaleem Abdulrasool #include "llvm/ADT/ScopeExit.h"
34f1585a4bSSaleem Abdulrasool #include "llvm/Support/ConvertUTF.h"
35f1585a4bSSaleem Abdulrasool
36a0154f98SDeepak Panickal using namespace lldb;
37a0154f98SDeepak Panickal using namespace lldb_private;
38a0154f98SDeepak Panickal
39bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(PlatformWindows)
40fbb4d1e4SJonas Devlieghere
41a0154f98SDeepak Panickal static uint32_t g_initialize_count = 0;
42a0154f98SDeepak Panickal
CreateInstance(bool force,const lldb_private::ArchSpec * arch)43b9c1b51eSKate Stone PlatformSP PlatformWindows::CreateInstance(bool force,
44b9c1b51eSKate Stone const lldb_private::ArchSpec *arch) {
45a0154f98SDeepak Panickal // The only time we create an instance is when we are creating a remote
46a0154f98SDeepak Panickal // windows platform
47a0154f98SDeepak Panickal const bool is_host = false;
48a0154f98SDeepak Panickal
49a0154f98SDeepak Panickal bool create = force;
50a6682a41SJonas Devlieghere if (!create && arch && arch->IsValid()) {
51a0154f98SDeepak Panickal const llvm::Triple &triple = arch->GetTriple();
52b9c1b51eSKate Stone switch (triple.getVendor()) {
53a0154f98SDeepak Panickal case llvm::Triple::PC:
54a0154f98SDeepak Panickal create = true;
55a0154f98SDeepak Panickal break;
56a0154f98SDeepak Panickal
57926b7c71SEric Christopher case llvm::Triple::UnknownVendor:
58a0154f98SDeepak Panickal create = !arch->TripleVendorWasSpecified();
59a0154f98SDeepak Panickal break;
60a0154f98SDeepak Panickal
61a0154f98SDeepak Panickal default:
62a0154f98SDeepak Panickal break;
63a0154f98SDeepak Panickal }
64a0154f98SDeepak Panickal
65b9c1b51eSKate Stone if (create) {
66b9c1b51eSKate Stone switch (triple.getOS()) {
67a0154f98SDeepak Panickal case llvm::Triple::Win32:
68a0154f98SDeepak Panickal break;
69a0154f98SDeepak Panickal
70a0154f98SDeepak Panickal case llvm::Triple::UnknownOS:
71a0154f98SDeepak Panickal create = arch->TripleOSWasSpecified();
72a0154f98SDeepak Panickal break;
73a0154f98SDeepak Panickal
74a0154f98SDeepak Panickal default:
75a0154f98SDeepak Panickal create = false;
76a0154f98SDeepak Panickal break;
77a0154f98SDeepak Panickal }
78a0154f98SDeepak Panickal }
79a0154f98SDeepak Panickal }
80a0154f98SDeepak Panickal if (create)
81615eb7e6SGreg Clayton return PlatformSP(new PlatformWindows(is_host));
82615eb7e6SGreg Clayton return PlatformSP();
83a0154f98SDeepak Panickal }
84a0154f98SDeepak Panickal
GetPluginDescriptionStatic(bool is_host)85a458ef4fSPavel Labath llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
86b9c1b51eSKate Stone return is_host ? "Local Windows user platform plug-in."
87b9c1b51eSKate Stone : "Remote Windows user platform plug-in.";
88a0154f98SDeepak Panickal }
89a0154f98SDeepak Panickal
Initialize()90b9c1b51eSKate Stone void PlatformWindows::Initialize() {
913c4f89d7STamas Berghammer Platform::Initialize();
923c4f89d7STamas Berghammer
93b9c1b51eSKate Stone if (g_initialize_count++ == 0) {
94a0154f98SDeepak Panickal #if defined(_WIN32)
95a0154f98SDeepak Panickal // Force a host flag to true for the default platform object.
96a0154f98SDeepak Panickal PlatformSP default_platform_sp(new PlatformWindows(true));
9713b18261SZachary Turner default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
98615eb7e6SGreg Clayton Platform::SetHostPlatform(default_platform_sp);
99a0154f98SDeepak Panickal #endif
100b9c1b51eSKate Stone PluginManager::RegisterPlugin(
101b9c1b51eSKate Stone PlatformWindows::GetPluginNameStatic(false),
102a0154f98SDeepak Panickal PlatformWindows::GetPluginDescriptionStatic(false),
103a0154f98SDeepak Panickal PlatformWindows::CreateInstance);
104a0154f98SDeepak Panickal }
105a0154f98SDeepak Panickal }
106a0154f98SDeepak Panickal
Terminate()107f8a74c18SAaron Smith void PlatformWindows::Terminate() {
108b9c1b51eSKate Stone if (g_initialize_count > 0) {
109b9c1b51eSKate Stone if (--g_initialize_count == 0) {
110a0154f98SDeepak Panickal PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);
111a0154f98SDeepak Panickal }
112a0154f98SDeepak Panickal }
1133c4f89d7STamas Berghammer
1143c4f89d7STamas Berghammer Platform::Terminate();
115a0154f98SDeepak Panickal }
116a0154f98SDeepak Panickal
117a0154f98SDeepak Panickal /// Default Constructor
PlatformWindows(bool is_host)1181b468f1cSPavel Labath PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {
1191b468f1cSPavel Labath const auto &AddArch = [&](const ArchSpec &spec) {
1201b468f1cSPavel Labath if (llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) {
1211b468f1cSPavel Labath return spec.IsExactMatch(rhs);
1221b468f1cSPavel Labath }))
1231b468f1cSPavel Labath return;
1241b468f1cSPavel Labath if (spec.IsValid())
1251b468f1cSPavel Labath m_supported_architectures.push_back(spec);
1261b468f1cSPavel Labath };
1271b468f1cSPavel Labath AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
1281b468f1cSPavel Labath AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
1291b468f1cSPavel Labath AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
1301b468f1cSPavel Labath }
131a0154f98SDeepak Panickal
ConnectRemote(Args & args)13297206d57SZachary Turner Status PlatformWindows::ConnectRemote(Args &args) {
13397206d57SZachary Turner Status error;
134b9c1b51eSKate Stone if (IsHost()) {
135a3939e15SPavel Labath error.SetErrorStringWithFormatv(
136a3939e15SPavel Labath "can't connect to the host platform '{0}', always connected",
137a3939e15SPavel Labath GetPluginName());
138b9c1b51eSKate Stone } else {
139a0154f98SDeepak Panickal if (!m_remote_platform_sp)
140b9c1b51eSKate Stone m_remote_platform_sp =
141af921006SPavel Labath platform_gdb_server::PlatformRemoteGDBServer::CreateInstance(
142af921006SPavel Labath /*force=*/true, nullptr);
143a0154f98SDeepak Panickal
144b9c1b51eSKate Stone if (m_remote_platform_sp) {
145b9c1b51eSKate Stone if (error.Success()) {
146b9c1b51eSKate Stone if (m_remote_platform_sp) {
147a0154f98SDeepak Panickal error = m_remote_platform_sp->ConnectRemote(args);
148b9c1b51eSKate Stone } else {
149b9c1b51eSKate Stone error.SetErrorString(
150b9c1b51eSKate Stone "\"platform connect\" takes a single argument: <connect-url>");
151a0154f98SDeepak Panickal }
152a0154f98SDeepak Panickal }
153b9c1b51eSKate Stone } else
154a0154f98SDeepak Panickal error.SetErrorString("failed to create a 'remote-gdb-server' platform");
155a0154f98SDeepak Panickal
156a0154f98SDeepak Panickal if (error.Fail())
157a0154f98SDeepak Panickal m_remote_platform_sp.reset();
158a0154f98SDeepak Panickal }
159a0154f98SDeepak Panickal
160a0154f98SDeepak Panickal return error;
161a0154f98SDeepak Panickal }
162a0154f98SDeepak Panickal
DoLoadImage(Process * process,const FileSpec & remote_file,const std::vector<std::string> * paths,Status & error,FileSpec * loaded_image)163f1585a4bSSaleem Abdulrasool uint32_t PlatformWindows::DoLoadImage(Process *process,
164f1585a4bSSaleem Abdulrasool const FileSpec &remote_file,
165f1585a4bSSaleem Abdulrasool const std::vector<std::string> *paths,
166f1585a4bSSaleem Abdulrasool Status &error, FileSpec *loaded_image) {
167f1585a4bSSaleem Abdulrasool DiagnosticManager diagnostics;
168f1585a4bSSaleem Abdulrasool
169f1585a4bSSaleem Abdulrasool if (loaded_image)
170f1585a4bSSaleem Abdulrasool loaded_image->Clear();
171f1585a4bSSaleem Abdulrasool
172f1585a4bSSaleem Abdulrasool ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
173f1585a4bSSaleem Abdulrasool if (!thread) {
174f1585a4bSSaleem Abdulrasool error.SetErrorString("LoadLibrary error: no thread available to invoke LoadLibrary");
175f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
176f1585a4bSSaleem Abdulrasool }
177f1585a4bSSaleem Abdulrasool
178f1585a4bSSaleem Abdulrasool ExecutionContext context;
179f1585a4bSSaleem Abdulrasool thread->CalculateExecutionContext(context);
180f1585a4bSSaleem Abdulrasool
181f1585a4bSSaleem Abdulrasool Status status;
182f1585a4bSSaleem Abdulrasool UtilityFunction *loader =
183f1585a4bSSaleem Abdulrasool process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {
184f1585a4bSSaleem Abdulrasool return MakeLoadImageUtilityFunction(context, status);
185f1585a4bSSaleem Abdulrasool });
186f1585a4bSSaleem Abdulrasool if (loader == nullptr)
187f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
188f1585a4bSSaleem Abdulrasool
189f1585a4bSSaleem Abdulrasool FunctionCaller *invocation = loader->GetFunctionCaller();
190f1585a4bSSaleem Abdulrasool if (!invocation) {
191f1585a4bSSaleem Abdulrasool error.SetErrorString("LoadLibrary error: could not get function caller");
192f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
193f1585a4bSSaleem Abdulrasool }
194f1585a4bSSaleem Abdulrasool
195f1585a4bSSaleem Abdulrasool /* Convert name */
196f1585a4bSSaleem Abdulrasool llvm::SmallVector<llvm::UTF16, 261> name;
197f1585a4bSSaleem Abdulrasool if (!llvm::convertUTF8ToUTF16String(remote_file.GetPath(), name)) {
198f1585a4bSSaleem Abdulrasool error.SetErrorString("LoadLibrary error: could not convert path to UCS2");
199f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
200f1585a4bSSaleem Abdulrasool }
201f1585a4bSSaleem Abdulrasool name.emplace_back(L'\0');
202f1585a4bSSaleem Abdulrasool
203f1585a4bSSaleem Abdulrasool /* Inject name paramter into inferior */
204f1585a4bSSaleem Abdulrasool lldb::addr_t injected_name =
205f1585a4bSSaleem Abdulrasool process->AllocateMemory(name.size() * sizeof(llvm::UTF16),
206f1585a4bSSaleem Abdulrasool ePermissionsReadable | ePermissionsWritable,
207f1585a4bSSaleem Abdulrasool status);
208f1585a4bSSaleem Abdulrasool if (injected_name == LLDB_INVALID_ADDRESS) {
209f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for name: %s",
210f1585a4bSSaleem Abdulrasool status.AsCString());
211f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
212f1585a4bSSaleem Abdulrasool }
213f1585a4bSSaleem Abdulrasool
214f1585a4bSSaleem Abdulrasool auto name_cleanup = llvm::make_scope_exit([process, injected_name]() {
215f1585a4bSSaleem Abdulrasool process->DeallocateMemory(injected_name);
216f1585a4bSSaleem Abdulrasool });
217f1585a4bSSaleem Abdulrasool
218f1585a4bSSaleem Abdulrasool process->WriteMemory(injected_name, name.data(),
219f1585a4bSSaleem Abdulrasool name.size() * sizeof(llvm::UTF16), status);
220f1585a4bSSaleem Abdulrasool if (status.Fail()) {
221f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: unable to write name: %s",
222f1585a4bSSaleem Abdulrasool status.AsCString());
223f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
224f1585a4bSSaleem Abdulrasool }
225f1585a4bSSaleem Abdulrasool
226f1585a4bSSaleem Abdulrasool /* Inject paths parameter into inferior */
227f1585a4bSSaleem Abdulrasool lldb::addr_t injected_paths{0x0};
228f1585a4bSSaleem Abdulrasool llvm::Optional<llvm::detail::scope_exit<std::function<void()>>> paths_cleanup;
229f1585a4bSSaleem Abdulrasool if (paths) {
230f1585a4bSSaleem Abdulrasool llvm::SmallVector<llvm::UTF16, 261> search_paths;
231f1585a4bSSaleem Abdulrasool
232f1585a4bSSaleem Abdulrasool for (const auto &path : *paths) {
233f1585a4bSSaleem Abdulrasool if (path.empty())
234f1585a4bSSaleem Abdulrasool continue;
235f1585a4bSSaleem Abdulrasool
236f1585a4bSSaleem Abdulrasool llvm::SmallVector<llvm::UTF16, 261> buffer;
237f1585a4bSSaleem Abdulrasool if (!llvm::convertUTF8ToUTF16String(path, buffer))
238f1585a4bSSaleem Abdulrasool continue;
239f1585a4bSSaleem Abdulrasool
240f1585a4bSSaleem Abdulrasool search_paths.append(std::begin(buffer), std::end(buffer));
241f1585a4bSSaleem Abdulrasool search_paths.emplace_back(L'\0');
242f1585a4bSSaleem Abdulrasool }
243f1585a4bSSaleem Abdulrasool search_paths.emplace_back(L'\0');
244f1585a4bSSaleem Abdulrasool
245f1585a4bSSaleem Abdulrasool injected_paths =
246f1585a4bSSaleem Abdulrasool process->AllocateMemory(search_paths.size() * sizeof(llvm::UTF16),
247f1585a4bSSaleem Abdulrasool ePermissionsReadable | ePermissionsWritable,
248f1585a4bSSaleem Abdulrasool status);
249f1585a4bSSaleem Abdulrasool if (injected_paths == LLDB_INVALID_ADDRESS) {
250f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for paths: %s",
251f1585a4bSSaleem Abdulrasool status.AsCString());
252f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
253f1585a4bSSaleem Abdulrasool }
254f1585a4bSSaleem Abdulrasool
255f1585a4bSSaleem Abdulrasool paths_cleanup.emplace([process, injected_paths]() {
256f1585a4bSSaleem Abdulrasool process->DeallocateMemory(injected_paths);
257f1585a4bSSaleem Abdulrasool });
258f1585a4bSSaleem Abdulrasool
259f1585a4bSSaleem Abdulrasool process->WriteMemory(injected_paths, search_paths.data(),
260f1585a4bSSaleem Abdulrasool search_paths.size() * sizeof(llvm::UTF16), status);
261f1585a4bSSaleem Abdulrasool if (status.Fail()) {
262f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: unable to write paths: %s",
263f1585a4bSSaleem Abdulrasool status.AsCString());
264f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
265f1585a4bSSaleem Abdulrasool }
266f1585a4bSSaleem Abdulrasool }
267f1585a4bSSaleem Abdulrasool
268f1585a4bSSaleem Abdulrasool /* Inject wszModulePath into inferior */
269f1585a4bSSaleem Abdulrasool // FIXME(compnerd) should do something better for the length?
270f1585a4bSSaleem Abdulrasool // GetModuleFileNameA is likely limited to PATH_MAX rather than the NT path
271f1585a4bSSaleem Abdulrasool // limit.
272f1585a4bSSaleem Abdulrasool unsigned injected_length = 261;
273f1585a4bSSaleem Abdulrasool
274f1585a4bSSaleem Abdulrasool lldb::addr_t injected_module_path =
275f1585a4bSSaleem Abdulrasool process->AllocateMemory(injected_length + 1,
276f1585a4bSSaleem Abdulrasool ePermissionsReadable | ePermissionsWritable,
277f1585a4bSSaleem Abdulrasool status);
278f1585a4bSSaleem Abdulrasool if (injected_module_path == LLDB_INVALID_ADDRESS) {
279f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for module location: %s",
280f1585a4bSSaleem Abdulrasool status.AsCString());
281f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
282f1585a4bSSaleem Abdulrasool }
283f1585a4bSSaleem Abdulrasool
284f1585a4bSSaleem Abdulrasool auto injected_module_path_cleanup =
285f1585a4bSSaleem Abdulrasool llvm::make_scope_exit([process, injected_module_path]() {
286f1585a4bSSaleem Abdulrasool process->DeallocateMemory(injected_module_path);
287f1585a4bSSaleem Abdulrasool });
288f1585a4bSSaleem Abdulrasool
289f1585a4bSSaleem Abdulrasool /* Inject __lldb_LoadLibraryResult into inferior */
290f1585a4bSSaleem Abdulrasool const uint32_t word_size = process->GetAddressByteSize();
291f1585a4bSSaleem Abdulrasool lldb::addr_t injected_result =
292f1585a4bSSaleem Abdulrasool process->AllocateMemory(3 * word_size,
293f1585a4bSSaleem Abdulrasool ePermissionsReadable | ePermissionsWritable,
294f1585a4bSSaleem Abdulrasool status);
295f1585a4bSSaleem Abdulrasool if (status.Fail()) {
296f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: could not allocate memory for result: %s",
297f1585a4bSSaleem Abdulrasool status.AsCString());
298f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
299f1585a4bSSaleem Abdulrasool }
300f1585a4bSSaleem Abdulrasool
301f1585a4bSSaleem Abdulrasool auto result_cleanup = llvm::make_scope_exit([process, injected_result]() {
302f1585a4bSSaleem Abdulrasool process->DeallocateMemory(injected_result);
303f1585a4bSSaleem Abdulrasool });
304f1585a4bSSaleem Abdulrasool
305f1585a4bSSaleem Abdulrasool process->WritePointerToMemory(injected_result + word_size,
306f1585a4bSSaleem Abdulrasool injected_module_path, status);
307f1585a4bSSaleem Abdulrasool if (status.Fail()) {
308f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: could not initialize result: %s",
309f1585a4bSSaleem Abdulrasool status.AsCString());
310f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
311f1585a4bSSaleem Abdulrasool }
312f1585a4bSSaleem Abdulrasool
313f1585a4bSSaleem Abdulrasool // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
314f1585a4bSSaleem Abdulrasool process->WriteScalarToMemory(injected_result + 2 * word_size,
315f1585a4bSSaleem Abdulrasool Scalar{injected_length}, sizeof(unsigned),
316f1585a4bSSaleem Abdulrasool status);
317f1585a4bSSaleem Abdulrasool if (status.Fail()) {
318f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: could not initialize result: %s",
319f1585a4bSSaleem Abdulrasool status.AsCString());
320f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
321f1585a4bSSaleem Abdulrasool }
322f1585a4bSSaleem Abdulrasool
323f1585a4bSSaleem Abdulrasool /* Setup Formal Parameters */
324f1585a4bSSaleem Abdulrasool ValueList parameters = invocation->GetArgumentValues();
325f1585a4bSSaleem Abdulrasool parameters.GetValueAtIndex(0)->GetScalar() = injected_name;
326f1585a4bSSaleem Abdulrasool parameters.GetValueAtIndex(1)->GetScalar() = injected_paths;
327f1585a4bSSaleem Abdulrasool parameters.GetValueAtIndex(2)->GetScalar() = injected_result;
328f1585a4bSSaleem Abdulrasool
329f1585a4bSSaleem Abdulrasool lldb::addr_t injected_parameters = LLDB_INVALID_ADDRESS;
330f1585a4bSSaleem Abdulrasool diagnostics.Clear();
331f1585a4bSSaleem Abdulrasool if (!invocation->WriteFunctionArguments(context, injected_parameters,
332f1585a4bSSaleem Abdulrasool parameters, diagnostics)) {
333f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: unable to write function parameters: %s",
334f1585a4bSSaleem Abdulrasool diagnostics.GetString().c_str());
335f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
336f1585a4bSSaleem Abdulrasool }
337f1585a4bSSaleem Abdulrasool
338f1585a4bSSaleem Abdulrasool auto parameter_cleanup = llvm::make_scope_exit([invocation, &context, injected_parameters]() {
339f1585a4bSSaleem Abdulrasool invocation->DeallocateFunctionResults(context, injected_parameters);
340f1585a4bSSaleem Abdulrasool });
341f1585a4bSSaleem Abdulrasool
342f1585a4bSSaleem Abdulrasool TypeSystemClang *ast =
343f1585a4bSSaleem Abdulrasool ScratchTypeSystemClang::GetForTarget(process->GetTarget());
344f1585a4bSSaleem Abdulrasool if (!ast) {
345f1585a4bSSaleem Abdulrasool error.SetErrorString("LoadLibrary error: unable to get (clang) type system");
346f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
347f1585a4bSSaleem Abdulrasool }
348f1585a4bSSaleem Abdulrasool
349f1585a4bSSaleem Abdulrasool /* Setup Return Type */
350f1585a4bSSaleem Abdulrasool CompilerType VoidPtrTy = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
351f1585a4bSSaleem Abdulrasool
352f1585a4bSSaleem Abdulrasool Value value;
353f1585a4bSSaleem Abdulrasool value.SetCompilerType(VoidPtrTy);
354f1585a4bSSaleem Abdulrasool
355f1585a4bSSaleem Abdulrasool /* Invoke expression */
356f1585a4bSSaleem Abdulrasool EvaluateExpressionOptions options;
357f1585a4bSSaleem Abdulrasool options.SetExecutionPolicy(eExecutionPolicyAlways);
358f1585a4bSSaleem Abdulrasool options.SetLanguage(eLanguageTypeC_plus_plus);
359f1585a4bSSaleem Abdulrasool options.SetIgnoreBreakpoints(true);
360f1585a4bSSaleem Abdulrasool options.SetUnwindOnError(true);
361f1585a4bSSaleem Abdulrasool // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
362f1585a4bSSaleem Abdulrasool // They may potentially throw SEH exceptions which we do not know how to
363f1585a4bSSaleem Abdulrasool // handle currently.
364f1585a4bSSaleem Abdulrasool options.SetTrapExceptions(false);
365f1585a4bSSaleem Abdulrasool options.SetTimeout(process->GetUtilityExpressionTimeout());
366f1585a4bSSaleem Abdulrasool options.SetIsForUtilityExpr(true);
367f1585a4bSSaleem Abdulrasool
368f1585a4bSSaleem Abdulrasool ExpressionResults result =
369f1585a4bSSaleem Abdulrasool invocation->ExecuteFunction(context, &injected_parameters, options,
370f1585a4bSSaleem Abdulrasool diagnostics, value);
371f1585a4bSSaleem Abdulrasool if (result != eExpressionCompleted) {
372f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: failed to execute LoadLibrary helper: %s",
373f1585a4bSSaleem Abdulrasool diagnostics.GetString().c_str());
374f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
375f1585a4bSSaleem Abdulrasool }
376f1585a4bSSaleem Abdulrasool
377f1585a4bSSaleem Abdulrasool /* Read result */
378f1585a4bSSaleem Abdulrasool lldb::addr_t token = process->ReadPointerFromMemory(injected_result, status);
379f1585a4bSSaleem Abdulrasool if (status.Fail()) {
380f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: could not read the result: %s",
381f1585a4bSSaleem Abdulrasool status.AsCString());
382f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
383f1585a4bSSaleem Abdulrasool }
384f1585a4bSSaleem Abdulrasool
385ee4b4626SKazu Hirata if (!token) {
386f1585a4bSSaleem Abdulrasool // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
387f1585a4bSSaleem Abdulrasool uint64_t error_code =
388f1585a4bSSaleem Abdulrasool process->ReadUnsignedIntegerFromMemory(injected_result + 2 * word_size + sizeof(unsigned),
389f1585a4bSSaleem Abdulrasool word_size, 0, status);
390f1585a4bSSaleem Abdulrasool if (status.Fail()) {
391f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: could not read error status: %s",
392f1585a4bSSaleem Abdulrasool status.AsCString());
393f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
394f1585a4bSSaleem Abdulrasool }
395f1585a4bSSaleem Abdulrasool
39681f4874cSBenjamin Kramer error.SetErrorStringWithFormat("LoadLibrary Error: %" PRIu64, error_code);
397f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
398f1585a4bSSaleem Abdulrasool }
399f1585a4bSSaleem Abdulrasool
400f1585a4bSSaleem Abdulrasool std::string module_path;
401f1585a4bSSaleem Abdulrasool process->ReadCStringFromMemory(injected_module_path, module_path, status);
402f1585a4bSSaleem Abdulrasool if (status.Fail()) {
403f1585a4bSSaleem Abdulrasool error.SetErrorStringWithFormat("LoadLibrary error: could not read module path: %s",
404f1585a4bSSaleem Abdulrasool status.AsCString());
405f1585a4bSSaleem Abdulrasool return LLDB_INVALID_IMAGE_TOKEN;
406f1585a4bSSaleem Abdulrasool }
407f1585a4bSSaleem Abdulrasool
408f1585a4bSSaleem Abdulrasool if (loaded_image)
409f1585a4bSSaleem Abdulrasool loaded_image->SetFile(module_path, llvm::sys::path::Style::native);
410f1585a4bSSaleem Abdulrasool return process->AddImageToken(token);
411f1585a4bSSaleem Abdulrasool }
412f1585a4bSSaleem Abdulrasool
UnloadImage(Process * process,uint32_t image_token)413f1585a4bSSaleem Abdulrasool Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {
414f1585a4bSSaleem Abdulrasool const addr_t address = process->GetImagePtrFromToken(image_token);
415f1585a4bSSaleem Abdulrasool if (address == LLDB_INVALID_ADDRESS)
416f1585a4bSSaleem Abdulrasool return Status("invalid image token");
417f1585a4bSSaleem Abdulrasool
418f1585a4bSSaleem Abdulrasool StreamString expression;
419f1585a4bSSaleem Abdulrasool expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);
420f1585a4bSSaleem Abdulrasool
421f1585a4bSSaleem Abdulrasool ValueObjectSP value;
422f1585a4bSSaleem Abdulrasool Status result =
423f1585a4bSSaleem Abdulrasool EvaluateLoaderExpression(process, expression.GetData(), value);
424f1585a4bSSaleem Abdulrasool if (result.Fail())
425f1585a4bSSaleem Abdulrasool return result;
426f1585a4bSSaleem Abdulrasool
427f1585a4bSSaleem Abdulrasool if (value->GetError().Fail())
428f1585a4bSSaleem Abdulrasool return value->GetError();
429f1585a4bSSaleem Abdulrasool
430f1585a4bSSaleem Abdulrasool Scalar scalar;
431f1585a4bSSaleem Abdulrasool if (value->ResolveValue(scalar)) {
432f1585a4bSSaleem Abdulrasool if (scalar.UInt(1))
433f1585a4bSSaleem Abdulrasool return Status("expression failed: \"%s\"", expression.GetData());
434f1585a4bSSaleem Abdulrasool process->ResetImageToken(image_token);
435f1585a4bSSaleem Abdulrasool }
436f1585a4bSSaleem Abdulrasool
437f1585a4bSSaleem Abdulrasool return Status();
438f1585a4bSSaleem Abdulrasool }
439f1585a4bSSaleem Abdulrasool
DisconnectRemote()44097206d57SZachary Turner Status PlatformWindows::DisconnectRemote() {
44197206d57SZachary Turner Status error;
442a0154f98SDeepak Panickal
443b9c1b51eSKate Stone if (IsHost()) {
444a3939e15SPavel Labath error.SetErrorStringWithFormatv(
445a3939e15SPavel Labath "can't disconnect from the host platform '{0}', always connected",
446a3939e15SPavel Labath GetPluginName());
447b9c1b51eSKate Stone } else {
448a0154f98SDeepak Panickal if (m_remote_platform_sp)
449a0154f98SDeepak Panickal error = m_remote_platform_sp->DisconnectRemote();
450a0154f98SDeepak Panickal else
451a0154f98SDeepak Panickal error.SetErrorString("the platform is not currently connected");
452a0154f98SDeepak Panickal }
453a0154f98SDeepak Panickal return error;
454a0154f98SDeepak Panickal }
455a0154f98SDeepak Panickal
DebugProcess(ProcessLaunchInfo & launch_info,Debugger & debugger,Target & target,Status & error)456b9c1b51eSKate Stone ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
457bd590a5fSPavel Labath Debugger &debugger, Target &target,
45897206d57SZachary Turner Status &error) {
459b9c1b51eSKate Stone // Windows has special considerations that must be followed when launching or
46005097246SAdrian Prantl // attaching to a process. The key requirement is that when launching or
46105097246SAdrian Prantl // attaching to a process, you must do it from the same the thread that will
46205097246SAdrian Prantl // go into a permanent loop which will then receive debug events from the
46305097246SAdrian Prantl // process. In particular, this means we can't use any of LLDB's generic
46405097246SAdrian Prantl // mechanisms to do it for us, because it doesn't have the special knowledge
46505097246SAdrian Prantl // required for setting up the background thread or passing the right flags.
466c62733b0SZachary Turner //
467b9c1b51eSKate Stone // Another problem is that that LLDB's standard model for debugging a process
46805097246SAdrian Prantl // is to first launch it, have it stop at the entry point, and then attach to
46905097246SAdrian Prantl // it. In Windows this doesn't quite work, you have to specify as an
47005097246SAdrian Prantl // argument to CreateProcess() that you're going to debug the process. So we
47105097246SAdrian Prantl // override DebugProcess here to handle this. Launch operations go directly
47205097246SAdrian Prantl // to the process plugin, and attach operations almost go directly to the
47305097246SAdrian Prantl // process plugin (but we hijack the events first). In essence, we
47405097246SAdrian Prantl // encapsulate all the logic of Launching and Attaching in the process
47505097246SAdrian Prantl // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
47605097246SAdrian Prantl // the process plugin.
477c62733b0SZachary Turner
478d504fe20SAaron Smith if (IsRemote()) {
479d504fe20SAaron Smith if (m_remote_platform_sp)
480d504fe20SAaron Smith return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,
481d504fe20SAaron Smith error);
482d504fe20SAaron Smith else
483d504fe20SAaron Smith error.SetErrorString("the platform is not currently connected");
484d504fe20SAaron Smith }
485d504fe20SAaron Smith
486b9c1b51eSKate Stone if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
487c62733b0SZachary Turner // This is a process attach. Don't need to launch anything.
488c62733b0SZachary Turner ProcessAttachInfo attach_info(launch_info);
489bd590a5fSPavel Labath return Attach(attach_info, debugger, &target, error);
490a2c267e0SIlya Nozhkin }
491a2c267e0SIlya Nozhkin
492a2c267e0SIlya Nozhkin ProcessSP process_sp =
493a2c267e0SIlya Nozhkin target.CreateProcess(launch_info.GetListener(),
494a2c267e0SIlya Nozhkin launch_info.GetProcessPluginName(), nullptr, false);
495a2c267e0SIlya Nozhkin
496a2c267e0SIlya Nozhkin process_sp->HijackProcessEvents(launch_info.GetHijackListener());
497c62733b0SZachary Turner
498c62733b0SZachary Turner // We need to launch and attach to the process.
499c62733b0SZachary Turner launch_info.GetFlags().Set(eLaunchFlagDebug);
500c62733b0SZachary Turner if (process_sp)
501c62733b0SZachary Turner error = process_sp->Launch(launch_info);
502c62733b0SZachary Turner
503c62733b0SZachary Turner return process_sp;
504c62733b0SZachary Turner }
505c62733b0SZachary Turner
Attach(ProcessAttachInfo & attach_info,Debugger & debugger,Target * target,Status & error)506b9c1b51eSKate Stone lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,
507b9c1b51eSKate Stone Debugger &debugger, Target *target,
50897206d57SZachary Turner Status &error) {
509c62733b0SZachary Turner error.Clear();
510a0154f98SDeepak Panickal lldb::ProcessSP process_sp;
511b9c1b51eSKate Stone if (!IsHost()) {
512c62733b0SZachary Turner if (m_remote_platform_sp)
513b9c1b51eSKate Stone process_sp =
514b9c1b51eSKate Stone m_remote_platform_sp->Attach(attach_info, debugger, target, error);
515c62733b0SZachary Turner else
516c62733b0SZachary Turner error.SetErrorString("the platform is not currently connected");
517c62733b0SZachary Turner return process_sp;
518c62733b0SZachary Turner }
519c62733b0SZachary Turner
520b9c1b51eSKate Stone if (target == nullptr) {
521a0154f98SDeepak Panickal TargetSP new_target_sp;
522a0154f98SDeepak Panickal FileSpec emptyFileSpec;
523a0154f98SDeepak Panickal ArchSpec emptyArchSpec;
524a0154f98SDeepak Panickal
525f9a07e9fSJonas Devlieghere error = debugger.GetTargetList().CreateTarget(
526f9a07e9fSJonas Devlieghere debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
527a0154f98SDeepak Panickal target = new_target_sp.get();
528a0154f98SDeepak Panickal }
529a0154f98SDeepak Panickal
530c62733b0SZachary Turner if (!target || error.Fail())
531c62733b0SZachary Turner return process_sp;
532c62733b0SZachary Turner
533c62733b0SZachary Turner const char *plugin_name = attach_info.GetProcessPluginName();
534b9c1b51eSKate Stone process_sp = target->CreateProcess(
53518e4272aSMichał Górny attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false);
536c62733b0SZachary Turner
537583bbb1dSJim Ingham process_sp->HijackProcessEvents(attach_info.GetHijackListener());
538a0154f98SDeepak Panickal if (process_sp)
539a0154f98SDeepak Panickal error = process_sp->Attach(attach_info);
540c62733b0SZachary Turner
541a0154f98SDeepak Panickal return process_sp;
542a0154f98SDeepak Panickal }
543a0154f98SDeepak Panickal
GetStatus(Stream & strm)544b9c1b51eSKate Stone void PlatformWindows::GetStatus(Stream &strm) {
545a0154f98SDeepak Panickal Platform::GetStatus(strm);
546a0154f98SDeepak Panickal
547a0154f98SDeepak Panickal #ifdef _WIN32
54876ba4971SPavel Labath llvm::VersionTuple version = HostInfo::GetOSVersion();
54976ba4971SPavel Labath strm << " Host: Windows " << version.getAsString() << '\n';
550a0154f98SDeepak Panickal #endif
551a0154f98SDeepak Panickal }
552c62733b0SZachary Turner
CanDebugProcess()553b9c1b51eSKate Stone bool PlatformWindows::CanDebugProcess() { return true; }
554279a2b75SZachary Turner
GetFullNameForDylib(ConstString basename)555b9c1b51eSKate Stone ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
5566e25aeeaSEnrico Granata if (basename.IsEmpty())
5576e25aeeaSEnrico Granata return basename;
5586e25aeeaSEnrico Granata
5596e25aeeaSEnrico Granata StreamString stream;
5606e25aeeaSEnrico Granata stream.Printf("%s.dll", basename.GetCString());
561c156427dSZachary Turner return ConstString(stream.GetString());
5626e25aeeaSEnrico Granata }
5639f34f75fSMartin Storsjö
5649f34f75fSMartin Storsjö size_t
GetSoftwareBreakpointTrapOpcode(Target & target,BreakpointSite * bp_site)5659f34f75fSMartin Storsjö PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
5669f34f75fSMartin Storsjö BreakpointSite *bp_site) {
5679f34f75fSMartin Storsjö ArchSpec arch = target.GetArchitecture();
5689f34f75fSMartin Storsjö assert(arch.IsValid());
5699f34f75fSMartin Storsjö const uint8_t *trap_opcode = nullptr;
5709f34f75fSMartin Storsjö size_t trap_opcode_size = 0;
5719f34f75fSMartin Storsjö
5729f34f75fSMartin Storsjö switch (arch.GetMachine()) {
5739f34f75fSMartin Storsjö case llvm::Triple::aarch64: {
5749f34f75fSMartin Storsjö static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
5759f34f75fSMartin Storsjö trap_opcode = g_aarch64_opcode;
5769f34f75fSMartin Storsjö trap_opcode_size = sizeof(g_aarch64_opcode);
5779f34f75fSMartin Storsjö
5789f34f75fSMartin Storsjö if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
5799f34f75fSMartin Storsjö return trap_opcode_size;
5809f34f75fSMartin Storsjö return 0;
5819f34f75fSMartin Storsjö } break;
5829f34f75fSMartin Storsjö
5839f34f75fSMartin Storsjö case llvm::Triple::arm:
5849f34f75fSMartin Storsjö case llvm::Triple::thumb: {
5859f34f75fSMartin Storsjö static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
5869f34f75fSMartin Storsjö trap_opcode = g_thumb_opcode;
5879f34f75fSMartin Storsjö trap_opcode_size = sizeof(g_thumb_opcode);
5889f34f75fSMartin Storsjö
5899f34f75fSMartin Storsjö if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
5909f34f75fSMartin Storsjö return trap_opcode_size;
5919f34f75fSMartin Storsjö return 0;
5929f34f75fSMartin Storsjö } break;
5939f34f75fSMartin Storsjö
5949f34f75fSMartin Storsjö default:
5959f34f75fSMartin Storsjö return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
5969f34f75fSMartin Storsjö }
5979f34f75fSMartin Storsjö }
598f1585a4bSSaleem Abdulrasool
599f1585a4bSSaleem Abdulrasool std::unique_ptr<UtilityFunction>
MakeLoadImageUtilityFunction(ExecutionContext & context,Status & status)600f1585a4bSSaleem Abdulrasool PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
601f1585a4bSSaleem Abdulrasool Status &status) {
602f1585a4bSSaleem Abdulrasool // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
603f1585a4bSSaleem Abdulrasool static constexpr const char kLoaderDecls[] = R"(
604f1585a4bSSaleem Abdulrasool extern "C" {
605f1585a4bSSaleem Abdulrasool // errhandlingapi.h
606f1585a4bSSaleem Abdulrasool
607f1585a4bSSaleem Abdulrasool // `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
608f1585a4bSSaleem Abdulrasool //
609f1585a4bSSaleem Abdulrasool // Directories in the standard search path are not searched. This value cannot
610f1585a4bSSaleem Abdulrasool // be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
611f1585a4bSSaleem Abdulrasool //
612f1585a4bSSaleem Abdulrasool // This value represents the recommended maximum number of directories an
613f1585a4bSSaleem Abdulrasool // application should include in its DLL search path.
614f1585a4bSSaleem Abdulrasool #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
615f1585a4bSSaleem Abdulrasool
616f1585a4bSSaleem Abdulrasool // WINBASEAPI DWORD WINAPI GetLastError(VOID);
617f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
618f1585a4bSSaleem Abdulrasool
619f1585a4bSSaleem Abdulrasool // libloaderapi.h
620f1585a4bSSaleem Abdulrasool
621f1585a4bSSaleem Abdulrasool // WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
622f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
623f1585a4bSSaleem Abdulrasool
624f1585a4bSSaleem Abdulrasool // WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
625f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
626f1585a4bSSaleem Abdulrasool
627f1585a4bSSaleem Abdulrasool // WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
628f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
629f1585a4bSSaleem Abdulrasool
630f1585a4bSSaleem Abdulrasool // WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
631f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
632f1585a4bSSaleem Abdulrasool
633f1585a4bSSaleem Abdulrasool // corecrt_wstring.h
634f1585a4bSSaleem Abdulrasool
635f1585a4bSSaleem Abdulrasool // _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
636f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
637f1585a4bSSaleem Abdulrasool
638f1585a4bSSaleem Abdulrasool // lldb specific code
639f1585a4bSSaleem Abdulrasool
640f1585a4bSSaleem Abdulrasool struct __lldb_LoadLibraryResult {
641f1585a4bSSaleem Abdulrasool void *ImageBase;
642f1585a4bSSaleem Abdulrasool char *ModulePath;
643f1585a4bSSaleem Abdulrasool unsigned Length;
644f1585a4bSSaleem Abdulrasool unsigned ErrorCode;
645f1585a4bSSaleem Abdulrasool };
646f1585a4bSSaleem Abdulrasool
647f1585a4bSSaleem Abdulrasool _Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
648f1585a4bSSaleem Abdulrasool "__lldb_LoadLibraryResult size mismatch");
649f1585a4bSSaleem Abdulrasool
650f1585a4bSSaleem Abdulrasool void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
651f1585a4bSSaleem Abdulrasool __lldb_LoadLibraryResult *result) {
652*2696d82fSSaleem Abdulrasool for (const wchar_t *path = paths; path && *path; ) {
653f1585a4bSSaleem Abdulrasool (void)AddDllDirectory(path);
654f1585a4bSSaleem Abdulrasool path += wcslen(path) + 1;
655f1585a4bSSaleem Abdulrasool }
656f1585a4bSSaleem Abdulrasool
657f1585a4bSSaleem Abdulrasool result->ImageBase = LoadLibraryExW(name, nullptr,
658f1585a4bSSaleem Abdulrasool LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
659f1585a4bSSaleem Abdulrasool if (result->ImageBase == nullptr)
660f1585a4bSSaleem Abdulrasool result->ErrorCode = GetLastError();
661f1585a4bSSaleem Abdulrasool else
662f1585a4bSSaleem Abdulrasool result->Length = GetModuleFileNameA(result->ImageBase, result->ModulePath,
663f1585a4bSSaleem Abdulrasool result->Length);
664f1585a4bSSaleem Abdulrasool
665f1585a4bSSaleem Abdulrasool return result->ImageBase;
666f1585a4bSSaleem Abdulrasool }
667f1585a4bSSaleem Abdulrasool }
668f1585a4bSSaleem Abdulrasool )";
669f1585a4bSSaleem Abdulrasool
670f1585a4bSSaleem Abdulrasool static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
671f1585a4bSSaleem Abdulrasool
672f1585a4bSSaleem Abdulrasool ProcessSP process = context.GetProcessSP();
673f1585a4bSSaleem Abdulrasool Target &target = process->GetTarget();
674f1585a4bSSaleem Abdulrasool
675f1585a4bSSaleem Abdulrasool auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
676f1585a4bSSaleem Abdulrasool eLanguageTypeC_plus_plus,
677f1585a4bSSaleem Abdulrasool context);
678f1585a4bSSaleem Abdulrasool if (!function) {
679f1585a4bSSaleem Abdulrasool std::string error = llvm::toString(function.takeError());
680f1585a4bSSaleem Abdulrasool status.SetErrorStringWithFormat("LoadLibrary error: could not create utility function: %s",
681f1585a4bSSaleem Abdulrasool error.c_str());
682f1585a4bSSaleem Abdulrasool return nullptr;
683f1585a4bSSaleem Abdulrasool }
684f1585a4bSSaleem Abdulrasool
685f1585a4bSSaleem Abdulrasool TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget(target);
686f1585a4bSSaleem Abdulrasool if (!ast)
687f1585a4bSSaleem Abdulrasool return nullptr;
688f1585a4bSSaleem Abdulrasool
689f1585a4bSSaleem Abdulrasool CompilerType VoidPtrTy = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
690f1585a4bSSaleem Abdulrasool CompilerType WCharPtrTy = ast->GetBasicType(eBasicTypeWChar).GetPointerType();
691f1585a4bSSaleem Abdulrasool
692f1585a4bSSaleem Abdulrasool ValueList parameters;
693f1585a4bSSaleem Abdulrasool
694f1585a4bSSaleem Abdulrasool Value value;
695f1585a4bSSaleem Abdulrasool value.SetValueType(Value::ValueType::Scalar);
696f1585a4bSSaleem Abdulrasool
697f1585a4bSSaleem Abdulrasool value.SetCompilerType(WCharPtrTy);
698f1585a4bSSaleem Abdulrasool parameters.PushValue(value); // name
699f1585a4bSSaleem Abdulrasool parameters.PushValue(value); // paths
700f1585a4bSSaleem Abdulrasool
701f1585a4bSSaleem Abdulrasool value.SetCompilerType(VoidPtrTy);
702f1585a4bSSaleem Abdulrasool parameters.PushValue(value); // result
703f1585a4bSSaleem Abdulrasool
704f1585a4bSSaleem Abdulrasool Status error;
705f1585a4bSSaleem Abdulrasool std::unique_ptr<UtilityFunction> utility{std::move(*function)};
706f1585a4bSSaleem Abdulrasool utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
707f1585a4bSSaleem Abdulrasool error);
708f1585a4bSSaleem Abdulrasool if (error.Fail()) {
709f1585a4bSSaleem Abdulrasool status.SetErrorStringWithFormat("LoadLibrary error: could not create function caller: %s",
710f1585a4bSSaleem Abdulrasool error.AsCString());
711f1585a4bSSaleem Abdulrasool return nullptr;
712f1585a4bSSaleem Abdulrasool }
713f1585a4bSSaleem Abdulrasool
714f1585a4bSSaleem Abdulrasool if (!utility->GetFunctionCaller()) {
715f1585a4bSSaleem Abdulrasool status.SetErrorString("LoadLibrary error: could not get function caller");
716f1585a4bSSaleem Abdulrasool return nullptr;
717f1585a4bSSaleem Abdulrasool }
718f1585a4bSSaleem Abdulrasool
719f1585a4bSSaleem Abdulrasool return utility;
720f1585a4bSSaleem Abdulrasool }
721f1585a4bSSaleem Abdulrasool
EvaluateLoaderExpression(Process * process,const char * expression,ValueObjectSP & value)722f1585a4bSSaleem Abdulrasool Status PlatformWindows::EvaluateLoaderExpression(Process *process,
723f1585a4bSSaleem Abdulrasool const char *expression,
724f1585a4bSSaleem Abdulrasool ValueObjectSP &value) {
725f1585a4bSSaleem Abdulrasool // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
726f1585a4bSSaleem Abdulrasool static constexpr const char kLoaderDecls[] = R"(
727f1585a4bSSaleem Abdulrasool extern "C" {
728f1585a4bSSaleem Abdulrasool // libloaderapi.h
729f1585a4bSSaleem Abdulrasool
730f1585a4bSSaleem Abdulrasool // WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
731f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
732f1585a4bSSaleem Abdulrasool
733f1585a4bSSaleem Abdulrasool // WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
734f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ int __stdcall FreeModule(void *);
735f1585a4bSSaleem Abdulrasool
736f1585a4bSSaleem Abdulrasool // WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE, LPSTR, DWORD);
737f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
738f1585a4bSSaleem Abdulrasool
739f1585a4bSSaleem Abdulrasool // WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
740f1585a4bSSaleem Abdulrasool /* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
741f1585a4bSSaleem Abdulrasool }
742f1585a4bSSaleem Abdulrasool )";
743f1585a4bSSaleem Abdulrasool
744f1585a4bSSaleem Abdulrasool if (DynamicLoader *loader = process->GetDynamicLoader()) {
745f1585a4bSSaleem Abdulrasool Status result = loader->CanLoadImage();
746f1585a4bSSaleem Abdulrasool if (result.Fail())
747f1585a4bSSaleem Abdulrasool return result;
748f1585a4bSSaleem Abdulrasool }
749f1585a4bSSaleem Abdulrasool
750f1585a4bSSaleem Abdulrasool ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
751f1585a4bSSaleem Abdulrasool if (!thread)
752f1585a4bSSaleem Abdulrasool return Status("selected thread is invalid");
753f1585a4bSSaleem Abdulrasool
754f1585a4bSSaleem Abdulrasool StackFrameSP frame = thread->GetStackFrameAtIndex(0);
755f1585a4bSSaleem Abdulrasool if (!frame)
756f1585a4bSSaleem Abdulrasool return Status("frame 0 is invalid");
757f1585a4bSSaleem Abdulrasool
758f1585a4bSSaleem Abdulrasool ExecutionContext context;
759f1585a4bSSaleem Abdulrasool frame->CalculateExecutionContext(context);
760f1585a4bSSaleem Abdulrasool
761f1585a4bSSaleem Abdulrasool EvaluateExpressionOptions options;
762f1585a4bSSaleem Abdulrasool options.SetUnwindOnError(true);
763f1585a4bSSaleem Abdulrasool options.SetIgnoreBreakpoints(true);
764f1585a4bSSaleem Abdulrasool options.SetExecutionPolicy(eExecutionPolicyAlways);
765f1585a4bSSaleem Abdulrasool options.SetLanguage(eLanguageTypeC_plus_plus);
766f1585a4bSSaleem Abdulrasool // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
767f1585a4bSSaleem Abdulrasool // They may potentially throw SEH exceptions which we do not know how to
768f1585a4bSSaleem Abdulrasool // handle currently.
769f1585a4bSSaleem Abdulrasool options.SetTrapExceptions(false);
770f1585a4bSSaleem Abdulrasool options.SetTimeout(process->GetUtilityExpressionTimeout());
771f1585a4bSSaleem Abdulrasool
772f1585a4bSSaleem Abdulrasool Status error;
773f1585a4bSSaleem Abdulrasool ExpressionResults result = UserExpression::Evaluate(
774f1585a4bSSaleem Abdulrasool context, options, expression, kLoaderDecls, value, error);
775f1585a4bSSaleem Abdulrasool if (result != eExpressionCompleted)
776f1585a4bSSaleem Abdulrasool return error;
777f1585a4bSSaleem Abdulrasool
778f1585a4bSSaleem Abdulrasool if (value->GetError().Fail())
779f1585a4bSSaleem Abdulrasool return value->GetError();
780f1585a4bSSaleem Abdulrasool
781f1585a4bSSaleem Abdulrasool return Status();
782f1585a4bSSaleem Abdulrasool }
783