LLDB mainline
PlatformWindows.cpp
Go to the documentation of this file.
1//===-- PlatformWindows.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "PlatformWindows.h"
10
11#include <cstdio>
12#include <optional>
13#if defined(_WIN32)
15#include <pathcch.h>
16#include <winsock2.h>
17#else
18#define MAX_PATH 260
19#define PATHCCH_MAX_CCH 0x8000
20#endif
21
26#include "lldb/Core/Debugger.h"
27#include "lldb/Core/Module.h"
33#include "lldb/Host/HostInfo.h"
35#include "lldb/Target/Process.h"
36#include "lldb/Utility/Status.h"
37
38#include "llvm/ADT/ScopeExit.h"
39#include "llvm/Support/ConvertUTF.h"
40
41using namespace lldb;
42using namespace lldb_private;
43
45
46static uint32_t g_initialize_count = 0;
47
49 const lldb_private::ArchSpec *arch) {
50 // The only time we create an instance is when we are creating a remote
51 // windows platform
52 const bool is_host = false;
53
54 bool create = force;
55 if (!create && arch && arch->IsValid()) {
56 const llvm::Triple &triple = arch->GetTriple();
57 switch (triple.getVendor()) {
58 case llvm::Triple::PC:
59 create = true;
60 break;
61
62 case llvm::Triple::UnknownVendor:
63 create = !arch->TripleVendorWasSpecified();
64 break;
65
66 default:
67 break;
68 }
69
70 if (create) {
71 switch (triple.getOS()) {
72 case llvm::Triple::Win32:
73 break;
74
75 case llvm::Triple::UnknownOS:
76 create = arch->TripleOSWasSpecified();
77 break;
78
79 default:
80 create = false;
81 break;
82 }
83 }
84 }
85 if (create)
86 return PlatformSP(new PlatformWindows(is_host));
87 return PlatformSP();
88}
89
90llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
91 return is_host ? "Local Windows user platform plug-in."
92 : "Remote Windows user platform plug-in.";
93}
94
97
98 if (g_initialize_count++ == 0) {
99#if defined(_WIN32)
100 // Force a host flag to true for the default platform object.
101 PlatformSP default_platform_sp(new PlatformWindows(true));
102 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
103 Platform::SetHostPlatform(default_platform_sp);
104#endif
109 }
110}
111
121
122/// Default Constructor
124 const auto &AddArch = [&](const ArchSpec &spec) {
125 if (llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) {
126 return spec.IsExactMatch(rhs);
127 }))
128 return;
129 if (spec.IsValid())
130 m_supported_architectures.push_back(spec);
131 };
132 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
133 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
134 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
135}
136
138 if (IsHost())
140 "can't connect to the host platform '{0}', always connected",
141 GetPluginName());
142
146 /*force=*/true, nullptr);
147
150 "failed to create a 'remote-gdb-server' platform");
151
152 Status error = m_remote_platform_sp->ConnectRemote(args);
153 if (error.Fail())
154 m_remote_platform_sp.reset();
155
156 return error;
157}
158
160 const FileSpec &remote_file,
161 const std::vector<std::string> *paths,
162 Status &error, FileSpec *loaded_image) {
163 DiagnosticManager diagnostics;
164
165 if (loaded_image)
166 loaded_image->Clear();
167
169 if (!thread) {
171 "LoadLibrary error: no thread available to invoke LoadLibrary");
173 }
174
175 ExecutionContext context;
176 thread->CalculateExecutionContext(context);
177
178 Status status;
179 UtilityFunction *loader =
180 process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {
181 return MakeLoadImageUtilityFunction(context, status);
182 });
183 if (loader == nullptr)
185
186 FunctionCaller *invocation = loader->GetFunctionCaller();
187 if (!invocation) {
189 "LoadLibrary error: could not get function caller");
191 }
192
193 /* Convert name */
194 llvm::SmallVector<llvm::UTF16, 261> name;
195 if (!llvm::convertUTF8ToUTF16String(remote_file.GetPath(), name)) {
197 "LoadLibrary error: could not convert path to UCS2");
199 }
200 name.emplace_back(L'\0');
201
202 /* Inject name paramter into inferior */
203 lldb::addr_t injected_name =
204 process->AllocateMemory(name.size() * sizeof(llvm::UTF16),
205 ePermissionsReadable | ePermissionsWritable,
206 status);
207 if (injected_name == LLDB_INVALID_ADDRESS) {
209 "LoadLibrary error: unable to allocate memory for name: %s",
210 status.AsCString());
212 }
213
214 llvm::scope_exit name_cleanup(
215 [process, injected_name]() { process->DeallocateMemory(injected_name); });
216
217 process->WriteMemory(injected_name, name.data(),
218 name.size() * sizeof(llvm::UTF16), status);
219 if (status.Fail()) {
221 "LoadLibrary error: unable to write name: %s", status.AsCString());
223 }
224
225 /* Inject paths parameter into inferior */
226 lldb::addr_t injected_paths{0x0};
227 std::optional<llvm::scope_exit<std::function<void()>>> paths_cleanup;
228 if (paths) {
229 llvm::SmallVector<llvm::UTF16, 261> search_paths;
230
231 for (const auto &path : *paths) {
232 if (path.empty())
233 continue;
234
235 llvm::SmallVector<llvm::UTF16, 261> buffer;
236 if (!llvm::convertUTF8ToUTF16String(path, buffer))
237 continue;
238
239 search_paths.append(std::begin(buffer), std::end(buffer));
240 search_paths.emplace_back(L'\0');
241 }
242 search_paths.emplace_back(L'\0');
243
244 injected_paths =
245 process->AllocateMemory(search_paths.size() * sizeof(llvm::UTF16),
246 ePermissionsReadable | ePermissionsWritable,
247 status);
248 if (injected_paths == LLDB_INVALID_ADDRESS) {
250 "LoadLibrary error: unable to allocate memory for paths: %s",
251 status.AsCString());
253 }
254
255 paths_cleanup.emplace([process, injected_paths]() {
256 process->DeallocateMemory(injected_paths);
257 });
258
259 process->WriteMemory(injected_paths, search_paths.data(),
260 search_paths.size() * sizeof(llvm::UTF16), status);
261 if (status.Fail()) {
263 "LoadLibrary error: unable to write paths: %s", status.AsCString());
265 }
266 }
267
268 /* Inject wszModulePath into inferior */
269 // Start with a MAX_PATH-sized buffer (enough for the vast majority of module
270 // paths) and grow it on demand if GetModuleFileNameW reports truncation (see
271 // the loop after the helper runs).
272 unsigned injected_length = MAX_PATH;
273
274 lldb::addr_t injected_module_path = process->AllocateMemory(
275 (injected_length + 1) * sizeof(llvm::UTF16),
276 ePermissionsReadable | ePermissionsWritable, status);
277 if (injected_module_path == LLDB_INVALID_ADDRESS) {
279 "LoadLibrary error: unable to allocate memory for module location: %s",
280 status.AsCString());
282 }
283
284 llvm::scope_exit injected_module_path_cleanup(
285 [process, injected_module_path]() {
286 process->DeallocateMemory(injected_module_path);
287 });
288
289 /* Inject __lldb_LoadLibraryResult into inferior */
290 const uint32_t word_size = process->GetAddressByteSize();
291 lldb::addr_t injected_result =
292 process->AllocateMemory(3 * word_size,
293 ePermissionsReadable | ePermissionsWritable,
294 status);
295 if (status.Fail()) {
297 "LoadLibrary error: could not allocate memory for result: %s",
298 status.AsCString());
300 }
301
302 llvm::scope_exit result_cleanup([process, injected_result]() {
303 process->DeallocateMemory(injected_result);
304 });
305
306 std::vector<lldb::addr_t> grown_path_buffers;
307 llvm::scope_exit grown_path_cleanup([&]() {
308 for (lldb::addr_t buffer : grown_path_buffers)
309 process->DeallocateMemory(buffer);
310 });
311
312 process->WritePointerToMemory(injected_result, 0, status);
313 if (status.Fail()) {
315 "LoadLibrary error: could not initialize result: %s",
316 status.AsCString());
318 }
319
320 process->WritePointerToMemory(injected_result + word_size,
321 injected_module_path, status);
322 if (status.Fail()) {
324 "LoadLibrary error: could not initialize result: %s",
325 status.AsCString());
327 }
328
329 // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
330 process->WriteScalarToMemory(injected_result + 2 * word_size,
331 Scalar{injected_length}, sizeof(unsigned),
332 status);
333 if (status.Fail()) {
335 "LoadLibrary error: could not initialize result: %s",
336 status.AsCString());
338 }
339
340 /* Setup Formal Parameters */
341 ValueList parameters = invocation->GetArgumentValues();
342 parameters.GetValueAtIndex(0)->GetScalar() = injected_name;
343 parameters.GetValueAtIndex(1)->GetScalar() = injected_paths;
344 parameters.GetValueAtIndex(2)->GetScalar() = injected_result;
345
346 lldb::addr_t injected_parameters = LLDB_INVALID_ADDRESS;
347 diagnostics.Clear();
348 if (!invocation->WriteFunctionArguments(context, injected_parameters,
349 parameters, diagnostics)) {
350 error = Status::FromError(diagnostics.GetAsError(
352 "LoadLibrary error: unable to write function parameters:"));
354 }
355
356 llvm::scope_exit parameter_cleanup(
357 [invocation, &context, injected_parameters]() {
358 invocation->DeallocateFunctionResults(context, injected_parameters);
359 });
360
361 TypeSystemClangSP scratch_ts_sp =
363 if (!scratch_ts_sp) {
365 "LoadLibrary error: unable to get (clang) type system");
367 }
368
369 /* Setup Return Type */
370 CompilerType VoidPtrTy =
371 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
372
373 Value value;
374 value.SetCompilerType(VoidPtrTy);
375
376 /* Invoke expression */
380 options.SetIgnoreBreakpoints(true);
381 options.SetUnwindOnError(true);
382 // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
383 // They may potentially throw SEH exceptions which we do not know how to
384 // handle currently.
385 options.SetTrapExceptions(false);
386 options.SetTimeout(process->GetUtilityExpressionTimeout());
387 options.SetIsForUtilityExpr(true);
388
389 ExpressionResults result =
390 invocation->ExecuteFunction(context, &injected_parameters, options,
391 diagnostics, value);
392 if (result != eExpressionCompleted) {
393 error = Status::FromError(diagnostics.GetAsError(
395 "LoadLibrary error: failed to execute LoadLibrary helper:"));
397 }
398
399 /* Read result */
400 lldb::addr_t token = process->ReadPointerFromMemory(injected_result, status);
401 if (status.Fail()) {
403 "LoadLibrary error: could not read the result: %s", status.AsCString());
405 }
406
407 if (!token) {
408 // ErrorCode is a 4-byte `unsigned` field in __lldb_LoadLibraryResult.
409 uint64_t error_code = process->ReadUnsignedIntegerFromMemory(
410 injected_result + 2 * word_size + sizeof(unsigned), sizeof(unsigned), 0,
411 status);
412 if (status.Fail()) {
414 "LoadLibrary error: could not read error status: %s",
415 status.AsCString());
417 }
418
419 error = Status::FromErrorStringWithFormat("LoadLibrary Error: %" PRIu64,
420 error_code);
422 }
423
424 lldb::addr_t module_path_addr = injected_module_path;
425 unsigned capacity = injected_length;
426 uint32_t path_length = process->ReadUnsignedIntegerFromMemory(
427 injected_result + 2 * word_size, sizeof(unsigned), 0, status);
428 while (status.Success() && path_length >= capacity &&
429 capacity < PATHCCH_MAX_CCH) {
430 capacity = std::min<unsigned>(capacity * 2, PATHCCH_MAX_CCH);
431 lldb::addr_t buffer = process->AllocateMemory(
432 (capacity + 1) * sizeof(llvm::UTF16),
433 ePermissionsReadable | ePermissionsWritable, status);
434 if (buffer == LLDB_INVALID_ADDRESS || status.Fail())
435 break;
436 grown_path_buffers.push_back(buffer);
437
438 process->WritePointerToMemory(injected_result + word_size, buffer, status);
439 if (status.Fail())
440 break;
441 process->WriteScalarToMemory(injected_result + 2 * word_size,
442 Scalar{capacity}, sizeof(unsigned), status);
443 if (status.Fail())
444 break;
445
446 diagnostics.Clear();
447 if (invocation->ExecuteFunction(context, &injected_parameters, options,
448 diagnostics, value) != eExpressionCompleted)
449 break;
450 module_path_addr = buffer;
451 path_length = process->ReadUnsignedIntegerFromMemory(
452 injected_result + 2 * word_size, sizeof(unsigned), 0, status);
453 }
454
455 llvm::SmallVector<llvm::UTF16, MAX_PATH> wide_path(path_length);
456 if (path_length)
457 process->ReadMemory(module_path_addr, wide_path.data(),
458 path_length * sizeof(llvm::UTF16), status);
459 if (status.Fail()) {
461 "LoadLibrary error: could not read module path: %s",
462 status.AsCString());
464 }
465
466 std::string module_path;
467 if (!llvm::convertUTF16ToUTF8String(
468 llvm::ArrayRef<llvm::UTF16>(wide_path.data(), wide_path.size()),
469 module_path)) {
471 "LoadLibrary error: could not convert module path to UTF-8");
473 }
474
475 if (loaded_image)
476 loaded_image->SetFile(module_path, llvm::sys::path::Style::native);
477 return process->AddImageToken(token);
478}
479
480Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {
481 const addr_t address = process->GetImagePtrFromToken(image_token);
482 if (address == LLDB_INVALID_ADDRESS)
483 return Status::FromErrorString("invalid image token");
484
485 StreamString expression;
486 expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);
487
488 ValueObjectSP value;
489 Status result =
490 EvaluateLoaderExpression(process, expression.GetData(), value);
491 if (result.Fail())
492 return result;
493
494 if (value->GetError().Fail())
495 return value->GetError().Clone();
496
497 Scalar scalar;
498 if (value->ResolveValue(scalar)) {
499 if (scalar.UInt(1))
500 return Status::FromErrorStringWithFormat("expression failed: \"%s\"",
501 expression.GetData());
502 process->ResetImageToken(image_token);
503 }
504
505 return Status();
506}
507
510
511 if (IsHost()) {
513 "can't disconnect from the host platform '{0}', always connected",
514 GetPluginName());
515 } else {
517 error = m_remote_platform_sp->DisconnectRemote();
518 else
519 error =
520 Status::FromErrorString("the platform is not currently connected");
521 }
522 return error;
523}
524
526 Debugger &debugger, Target &target,
527 Status &error) {
528 // Windows has special considerations that must be followed when launching or
529 // attaching to a process. The key requirement is that when launching or
530 // attaching to a process, you must do it from the same the thread that will
531 // go into a permanent loop which will then receive debug events from the
532 // process. In particular, this means we can't use any of LLDB's generic
533 // mechanisms to do it for us, because it doesn't have the special knowledge
534 // required for setting up the background thread or passing the right flags.
535 //
536 // Another problem is that LLDB's standard model for debugging a process
537 // is to first launch it, have it stop at the entry point, and then attach to
538 // it. In Windows this doesn't quite work, you have to specify as an
539 // argument to CreateProcess() that you're going to debug the process. So we
540 // override DebugProcess here to handle this. Launch operations go directly
541 // to the process plugin, and attach operations almost go directly to the
542 // process plugin (but we hijack the events first). In essence, we
543 // encapsulate all the logic of Launching and Attaching in the process
544 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
545 // the process plugin.
546
547 if (IsRemote()) {
549 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,
550 error);
551 else
552 error =
553 Status::FromErrorString("the platform is not currently connected");
554 }
555
556 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
557 // This is a process attach. Don't need to launch anything.
558 ProcessAttachInfo attach_info(launch_info);
559 return Attach(attach_info, debugger, &target, error);
560 }
561
562 ProcessSP process_sp =
563 target.CreateProcess(launch_info.GetListener(),
564 launch_info.GetProcessPluginName(), nullptr, false);
565 if (!process_sp)
566 return nullptr;
567
568 process_sp->HijackProcessEvents(launch_info.GetHijackListener());
569
570 // We need to launch and attach to the process.
571 launch_info.GetFlags().Set(eLaunchFlagDebug);
572 error = process_sp->Launch(launch_info);
573#ifdef _WIN32
574 if (error.Success()) {
575 process_sp->SetPseudoConsoleHandle();
576 } else {
578 LLDB_LOGF(log, "Platform::%s LaunchProcess() failed: %s", __FUNCTION__,
579 error.AsCString());
580 }
581#endif
582
583 return process_sp;
584}
585
587 Debugger &debugger, Target *target,
588 Status &error) {
589 error.Clear();
590 lldb::ProcessSP process_sp;
591 if (!IsHost()) {
593 process_sp =
594 m_remote_platform_sp->Attach(attach_info, debugger, target, error);
595 else
596 error =
597 Status::FromErrorString("the platform is not currently connected");
598 return process_sp;
599 }
600
601 if (target == nullptr) {
602 TargetSP new_target_sp;
603 error = debugger.GetTargetList().CreateTarget(
604 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
605 target = new_target_sp.get();
606 }
607
608 if (!target || error.Fail())
609 return process_sp;
610
611 process_sp =
612 target->CreateProcess(attach_info.GetListenerForProcess(debugger),
613 attach_info.GetProcessPluginName(), nullptr, false);
614
615 process_sp->HijackProcessEvents(attach_info.GetHijackListener());
616 if (process_sp)
617 error = process_sp->Attach(attach_info);
618
619 return process_sp;
620}
621
624
625#ifdef _WIN32
626 llvm::VersionTuple version = HostInfo::GetOSVersion();
627 strm << " Host: Windows " << version.getAsString() << '\n';
628#endif
629}
630
631bool PlatformWindows::CanDebugProcess() { return true; }
632
634 if (basename.IsEmpty())
635 return basename;
636
637 StreamString stream;
638 stream.Printf("%s.dll", basename.GetCString());
639 return ConstString(stream.GetString());
640}
641
642size_t
644 BreakpointSite *bp_site) {
645 ArchSpec arch = target.GetArchitecture();
646 assert(arch.IsValid());
647 const uint8_t *trap_opcode = nullptr;
648 size_t trap_opcode_size = 0;
649
650 switch (arch.GetMachine()) {
651 case llvm::Triple::aarch64: {
652 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
653 trap_opcode = g_aarch64_opcode;
654 trap_opcode_size = sizeof(g_aarch64_opcode);
655
656 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
657 return trap_opcode_size;
658 return 0;
659 } break;
660
661 case llvm::Triple::arm:
662 case llvm::Triple::thumb: {
663 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
664 trap_opcode = g_thumb_opcode;
665 trap_opcode_size = sizeof(g_thumb_opcode);
666
667 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
668 return trap_opcode_size;
669 return 0;
670 } break;
671
672 default:
673 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
674 }
675}
676
677std::unique_ptr<UtilityFunction>
679 Status &status) {
680 // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
681 static constexpr const char kLoaderDecls[] = R"(
682extern "C" {
683// errhandlingapi.h
684
685// `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
686//
687// Directories in the standard search path are not searched. This value cannot
688// be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
689//
690// This value represents the recommended maximum number of directories an
691// application should include in its DLL search path.
692#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
693
694// If this value is used, and lpFileName specifies an absolute path, the system
695// uses the alternate file search strategy to find associated executable
696// modules.
697#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
698
699// WINBASEAPI DWORD WINAPI GetLastError(VOID);
700/* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
701
702// libloaderapi.h
703
704// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
705/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
706
707// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
708/* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
709
710// WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
711/* __declspec(dllimport) */ uint32_t GetModuleFileNameW(void *, wchar_t *, uint32_t);
712
713// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
714/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
715
716// corecrt_wstring.h
717
718// _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
719/* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
720
721// lldb specific code
722
723struct __lldb_LoadLibraryResult {
724 void *ImageBase;
725 wchar_t *ModulePath;
726 unsigned Length;
727 unsigned ErrorCode;
728};
729
730_Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
731 "__lldb_LoadLibraryResult size mismatch");
732
733void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
734 __lldb_LoadLibraryResult *result) {
735 // When the caller presets ImageBase the module is already loaded and we are
736 // only re-querying its path with a larger buffer. Skip LoadLibrary in that
737 // case so we do not take an extra reference on the module.
738 if (result->ImageBase == nullptr) {
739 for (const wchar_t *path = paths; path && *path; ) {
740 (void)AddDllDirectory(path);
741 path += wcslen(path) + 1;
742 }
743
744 result->ImageBase = LoadLibraryExW(name, nullptr,
745 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
746
747 // Fallback: if the AddDllDirectory + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS path
748 // failed to find the library, iterate the search paths ourselves and
749 // load by absolute path using LOAD_WITH_ALTERED_SEARCH_PATH, which makes
750 // Windows use the loaded DLL's own directory to resolve its sibling imports.
751 if (result->ImageBase == nullptr) {
752 wchar_t full[4096];
753 for (const wchar_t *path = paths; path && *path; path += wcslen(path) + 1) {
754 size_t plen = wcslen(path);
755 size_t nlen = wcslen(name);
756 // Need room for: path + '\\' + name + '\0'
757 if (plen + 1 + nlen + 1 > 4096)
758 continue;
759 wchar_t *p = full;
760 for (size_t i = 0; i < plen; ++i)
761 *p++ = path[i];
762 *p++ = L'\\';
763 for (size_t i = 0; i <= nlen; ++i) // Copy name including trailing '\0'.
764 *p++ = name[i];
765 result->ImageBase = LoadLibraryExW(full, nullptr,
766 LOAD_WITH_ALTERED_SEARCH_PATH);
767 if (result->ImageBase != nullptr)
768 break;
769 }
770 }
771 }
772
773 if (result->ImageBase == nullptr)
774 result->ErrorCode = GetLastError();
775 else
776 result->Length = GetModuleFileNameW(result->ImageBase, result->ModulePath,
777 result->Length);
778
779 return result->ImageBase;
780}
781}
782 )";
783
784 static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
785
786 ProcessSP process = context.GetProcessSP();
787 Target &target = process->GetTarget();
788
789 auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
791 context);
792 if (!function) {
793 std::string error = llvm::toString(function.takeError());
795 "LoadLibrary error: could not create utility function: %s",
796 error.c_str());
797 return nullptr;
798 }
799
800 TypeSystemClangSP scratch_ts_sp =
802 if (!scratch_ts_sp)
803 return nullptr;
804
805 CompilerType VoidPtrTy =
806 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
807 CompilerType WCharPtrTy =
808 scratch_ts_sp->GetBasicType(eBasicTypeWChar).GetPointerType();
809
810 ValueList parameters;
811
812 Value value;
814
815 value.SetCompilerType(WCharPtrTy);
816 parameters.PushValue(value); // name
817 parameters.PushValue(value); // paths
818
819 value.SetCompilerType(VoidPtrTy);
820 parameters.PushValue(value); // result
821
823 std::unique_ptr<UtilityFunction> utility{std::move(*function)};
824 utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
825 error);
826 if (error.Fail()) {
828 "LoadLibrary error: could not create function caller: %s",
829 error.AsCString());
830 return nullptr;
831 }
832
833 if (!utility->GetFunctionCaller()) {
835 "LoadLibrary error: could not get function caller");
836 return nullptr;
837 }
838
839 return utility;
840}
841
843 const char *expression,
844 ValueObjectSP &value) {
845 // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
846 static constexpr const char kLoaderDecls[] = R"(
847extern "C" {
848// libloaderapi.h
849
850// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
851/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
852
853// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
854/* __declspec(dllimport) */ int __stdcall FreeModule(void *);
855
856// WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE, LPWSTR, DWORD);
857/* __declspec(dllimport) */ uint32_t GetModuleFileNameW(void *, wchar_t *, uint32_t);
858
859// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
860/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
861}
862 )";
863
864 if (DynamicLoader *loader = process->GetDynamicLoader()) {
865 Status result = loader->CanLoadImage();
866 if (result.Fail())
867 return result;
868 }
869
871 if (!thread)
872 return Status::FromErrorString("selected thread is invalid");
873
874 StackFrameSP frame = thread->GetStackFrameAtIndex(0);
875 if (!frame)
876 return Status::FromErrorString("frame 0 is invalid");
877
878 ExecutionContext context;
879 frame->CalculateExecutionContext(context);
880
881 EvaluateExpressionOptions options;
882 options.SetUnwindOnError(true);
883 options.SetIgnoreBreakpoints(true);
886 // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
887 // They may potentially throw SEH exceptions which we do not know how to
888 // handle currently.
889 options.SetTrapExceptions(false);
890 options.SetTimeout(process->GetUtilityExpressionTimeout());
891
893 context, options, expression, kLoaderDecls, value);
894 if (result != eExpressionCompleted)
895 return value ? value->GetError().Clone() : Status("unknown error");
896
897 if (value && value->GetError().Fail())
898 return value->GetError().Clone();
899
900 return Status();
901}
static const size_t word_size
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:390
static uint32_t g_initialize_count
#define PATHCCH_MAX_CCH
#define MAX_PATH
#define LLDB_PLUGIN_DEFINE(PluginName)
static constexpr llvm::StringLiteral kName
An architecture specification class.
Definition ArchSpec.h:32
bool IsValid() const
Tests if this ArchSpec is valid.
Definition ArchSpec.h:452
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition ArchSpec.cpp:881
A command line argument class.
Definition Args.h:33
Class that manages the actual breakpoint that will be inserted into the running program.
bool SetTrapOpcode(const uint8_t *trap_opcode, uint32_t trap_opcode_size)
Sets the trap opcode.
Generic representation of a type in a programming language.
CompilerType GetPointerType() const
Return a new CompilerType that is a pointer to this type.
A uniqued constant string class.
Definition ConstString.h:40
bool IsEmpty() const
Test for empty string.
const char * GetCString() const
Get the string value as a C string.
A class to manage flag bits.
Definition Debugger.h:100
TargetList & GetTargetList()
Get accessor for the target list.
Definition Debugger.h:220
llvm::Error GetAsError(lldb::ExpressionResults result, llvm::Twine message={}) const
Returns an ExpressionError with arg as error code.
void SetUnwindOnError(bool unwind=false)
Definition Target.h:396
void SetExecutionPolicy(ExecutionPolicy policy=eExecutionPolicyAlways)
Definition Target.h:354
void SetLanguage(lldb::LanguageType language_type)
Definition Target.h:360
void SetTimeout(const Timeout< std::micro > &timeout)
Definition Target.h:417
void SetIgnoreBreakpoints(bool ignore=false)
Definition Target.h:400
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
const lldb::ProcessSP & GetProcessSP() const
Get accessor to get the process shared pointer.
const lldb::ThreadSP & GetThreadSP() const
Get accessor to get the thread shared pointer.
A file utility class.
Definition FileSpec.h:57
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition FileSpec.cpp:174
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:376
void Clear()
Clears the object state.
Definition FileSpec.cpp:261
ValueType Set(ValueType mask)
Set one or more flags by logical OR'ing mask with the current flags.
Definition Flags.h:73
Encapsulates a function that can be called.
ValueList GetArgumentValues() const
void DeallocateFunctionResults(ExecutionContext &exe_ctx, lldb::addr_t args_addr)
Deallocate the arguments structure.
lldb::ExpressionResults ExecuteFunction(ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager, Value &results)
Run the function this FunctionCaller was created with.
bool WriteFunctionArguments(ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, DiagnosticManager &diagnostic_manager)
Insert the default function argument struct.
PlatformWindows(bool is_host)
Default Constructor.
lldb_private::Status UnloadImage(lldb_private::Process *process, uint32_t image_token) override
llvm::StringRef GetPluginName() override
std::unique_ptr< lldb_private::UtilityFunction > MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &context, lldb_private::Status &status)
lldb_private::Status DisconnectRemote() override
ConstString GetFullNameForDylib(ConstString basename) override
lldb::ProcessSP Attach(lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, lldb_private::Status &error) override
Attach to an existing process using a process ID.
static llvm::StringRef GetPluginDescriptionStatic(bool is_host)
void GetStatus(lldb_private::Stream &strm) override
Report the current status for this platform.
std::vector< ArchSpec > m_supported_architectures
lldb_private::Status ConnectRemote(lldb_private::Args &args) override
lldb::ProcessSP DebugProcess(lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target &target, lldb_private::Status &error) override
Subclasses do not need to implement this function as it uses the Platform::LaunchProcess() followed b...
static llvm::StringRef GetPluginNameStatic(bool is_host)
static lldb::PlatformSP CreateInstance(bool force, const lldb_private::ArchSpec *arch)
uint32_t DoLoadImage(lldb_private::Process *process, const lldb_private::FileSpec &remote_file, const std::vector< std::string > *paths, lldb_private::Status &error, lldb_private::FileSpec *loaded_path) override
lldb_private::Status EvaluateLoaderExpression(lldb_private::Process *process, const char *expression, lldb::ValueObjectSP &value)
bool CanDebugProcess() override
Not all platforms will support debugging a process by spawning somehow halted for a debugger (specifi...
size_t GetSoftwareBreakpointTrapOpcode(Target &target, BreakpointSite *bp_site) override
virtual size_t GetSoftwareBreakpointTrapOpcode(Target &target, BreakpointSite *bp_site)
static void Terminate()
Definition Platform.cpp:143
static void SetHostPlatform(const lldb::PlatformSP &platform_sp)
Definition Platform.cpp:150
virtual void GetStatus(Stream &strm)
Report the current status for this platform.
Definition Platform.cpp:342
static void Initialize()
Definition Platform.cpp:141
bool IsRemote() const
Definition Platform.h:561
bool IsHost() const
Definition Platform.h:557
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
lldb::ListenerSP GetListenerForProcess(Debugger &debugger)
Definition Process.cpp:3213
llvm::StringRef GetProcessPluginName() const
Definition Process.h:162
lldb::ListenerSP GetHijackListener() const
lldb::pid_t GetProcessID() const
Definition ProcessInfo.h:66
lldb::ListenerSP GetListener() const
llvm::StringRef GetProcessPluginName() const
std::chrono::seconds GetUtilityExpressionTimeout() const
Definition Process.cpp:346
A plug-in interface definition class for debugging a process.
Definition Process.h:359
UtilityFunction * GetLoadImageUtilityFunction(Platform *platform, llvm::function_ref< std::unique_ptr< UtilityFunction >()> factory)
Get the cached UtilityFunction that assists in loading binary images into the process.
Definition Process.cpp:6657
void ResetImageToken(size_t token)
Definition Process.cpp:6429
ThreadList & GetThreadList()
Definition Process.h:2394
lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, Status &error)
The public interface to allocating memory in the process.
Definition Process.cpp:2701
bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value, Status &error)
Definition Process.cpp:2531
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Definition Process.cpp:2038
size_t AddImageToken(lldb::addr_t image_ptr)
Definition Process.cpp:6418
uint64_t ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, uint64_t fail_value, Status &error)
Reads an unsigned integer of the specified byte size from process memory.
Definition Process.cpp:2456
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
Definition Process.cpp:2517
Status DeallocateMemory(lldb::addr_t ptr)
The public interface to deallocating memory in the process.
Definition Process.cpp:2764
lldb::addr_t GetImagePtrFromToken(size_t token) const
Definition Process.cpp:6423
uint32_t GetAddressByteSize() const
Definition Process.cpp:3930
size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Status &error)
Write memory to a process.
Definition Process.cpp:2559
virtual DynamicLoader * GetDynamicLoader()
Get the dynamic loader plug-in for this process.
Definition Process.cpp:3107
size_t WriteScalarToMemory(lldb::addr_t vm_addr, const Scalar &scalar, size_t size, Status &error)
Write all or part of a scalar value to memory.
Definition Process.cpp:2640
Target & GetTarget()
Get the target object pointer for this module.
Definition Process.h:1258
A base class for platforms which automatically want to be able to forward operations to a remote plat...
unsigned int UInt(unsigned int fail_value=0) const
Definition Scalar.cpp:351
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
bool Fail() const
Test for error condition.
Definition Status.cpp:293
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition Status.cpp:194
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
bool Success() const
Test for success condition.
Definition Status.cpp:303
const char * GetData() const
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
Status CreateTarget(Debugger &debugger, llvm::StringRef user_exe_path, llvm::StringRef triple_str, LoadDependentFiles get_dependent_modules, const OptionGroupPlatform *platform_options, lldb::TargetSP &target_sp)
Create a new Target.
const lldb::ProcessSP & CreateProcess(lldb::ListenerSP listener_sp, llvm::StringRef plugin_name, const FileSpec *crash_file, bool can_connect)
Definition Target.cpp:317
llvm::Expected< std::unique_ptr< UtilityFunction > > CreateUtilityFunction(std::string expression, std::string name, lldb::LanguageType language, ExecutionContext &exe_ctx)
Creates and installs a UtilityFunction for the given language.
Definition Target.cpp:2861
const ArchSpec & GetArchitecture() const
Definition Target.h:1285
lldb::ThreadSP GetExpressionExecutionThread()
static lldb::ExpressionResults Evaluate(ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options, llvm::StringRef expr_cstr, llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp, std::string *fixed_expression=nullptr, ValueObject *ctx_obj=nullptr)
Evaluate one expression in the scratch context of the target passed in the exe_ctx and return its res...
"lldb/Expression/UtilityFunction.h" Encapsulates a bit of source code that provides a function that i...
FunctionCaller * GetFunctionCaller()
void PushValue(const Value &value)
Definition Value.cpp:694
Value * GetValueAtIndex(size_t idx)
Definition Value.cpp:698
const Scalar & GetScalar() const
See comment on m_scalar to understand what GetScalar returns.
Definition Value.h:114
@ Scalar
A raw scalar value.
Definition Value.h:46
void SetCompilerType(const CompilerType &compiler_type)
Definition Value.cpp:276
void SetValueType(ValueType value_type)
Definition Value.h:90
static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch)
#define LLDB_INVALID_IMAGE_TOKEN
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_PROCESS_ID
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:339
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Platform > PlatformSP
@ eLanguageTypeC_plus_plus
ISO C++:1998.
ExpressionResults
The results of expression evaluation.
@ eExpressionCompleted
@ eExpressionSetupError
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::TypeSystemClang > TypeSystemClangSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP