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 <chrono>
12#include <cstdio>
13#include <optional>
14#if defined(_WIN32)
16#include <pathcch.h>
17#include <winsock2.h>
18#else
19#define MAX_PATH 260
20#define PATHCCH_MAX_CCH 0x8000
21#endif
22
27#include "lldb/Core/Debugger.h"
28#include "lldb/Core/Module.h"
34#include "lldb/Host/HostInfo.h"
36#include "lldb/Target/Process.h"
38#include "lldb/Utility/Status.h"
39
40#include "llvm/ADT/ScopeExit.h"
41#include "llvm/Support/ConvertUTF.h"
42#include "llvm/Support/Error.h"
43#include "llvm/Support/FormatAdapters.h"
44#include "llvm/Support/FormatVariadic.h"
45
46using namespace lldb;
47using namespace lldb_private;
48
50
51static uint32_t g_initialize_count = 0;
52
53// Upper bound on the timeout used when running a utility expression with
54// only one thread allowed to run. On expiry, RunThreadPlan retries with all
55// threads, so this does not shorten the overall timeout.
56static std::chrono::microseconds GetLoaderOneThreadTimeout(Process *process) {
57 constexpr std::chrono::seconds preferred(5);
58 return std::min<std::chrono::microseconds>(
59 preferred,
60 std::chrono::microseconds(process->GetUtilityExpressionTimeout()) / 2);
61}
62
63namespace {
64
65#define LLDB_PROPERTIES_windows
66#include "PlatformWindowsProperties.inc"
67
68enum {
69#define LLDB_PROPERTIES_windows
70#include "PlatformWindowsPropertiesEnum.inc"
71};
72
73class PluginProperties : public Properties {
74public:
75 PluginProperties() {
76 m_collection_sp = std::make_shared<OptionValueProperties>("windows");
77 m_collection_sp->Initialize(g_windows_properties_def);
78 }
79
80 bool DisableDebugHeap() const {
81 return GetPropertyAtIndexAs<bool>(ePropertyDisableDebugHeap, true);
82 }
83};
84
85static PluginProperties &GetGlobalProperties() {
86 static PluginProperties g_settings;
87 return g_settings;
88}
89
90} // end of anonymous namespace
91
93 const lldb_private::ArchSpec *arch) {
94 // The only time we create an instance is when we are creating a remote
95 // windows platform
96 const bool is_host = false;
97
98 bool create = force;
99 if (!create && arch && arch->IsValid()) {
100 const llvm::Triple &triple = arch->GetTriple();
101 switch (triple.getVendor()) {
102 case llvm::Triple::PC:
103 create = true;
104 break;
105
106 case llvm::Triple::UnknownVendor:
107 create = !arch->TripleVendorWasSpecified();
108 break;
109
110 default:
111 break;
112 }
113
114 if (create) {
115 switch (triple.getOS()) {
116 case llvm::Triple::Win32:
117 break;
118
119 case llvm::Triple::UnknownOS:
120 create = arch->TripleOSWasSpecified();
121 break;
122
123 default:
124 create = false;
125 break;
126 }
127 }
128 }
129 if (create)
130 return PlatformSP(new PlatformWindows(is_host));
131 return PlatformSP();
132}
133
134llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
135 return is_host ? "Local Windows user platform plug-in."
136 : "Remote Windows user platform plug-in.";
137}
138
140 if (!PluginManager::GetSettingForPlatformPlugin(debugger, "windows")) {
142 debugger, GetGlobalProperties().GetValueProperties(),
143 "Properties for the Windows platform plugin.",
144 /*is_global_property=*/true);
145 }
146}
147
150
151 if (g_initialize_count++ == 0) {
152#if defined(_WIN32)
153 // Force a host flag to true for the default platform object.
154 PlatformSP default_platform_sp(new PlatformWindows(true));
155 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
156 Platform::SetHostPlatform(default_platform_sp);
157#endif
162 }
163}
164
174
175/// Default Constructor
177 const auto &AddArch = [&](const ArchSpec &spec) {
178 if (llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) {
179 return spec.IsExactMatch(rhs);
180 }))
181 return;
182 if (spec.IsValid())
183 m_supported_architectures.push_back(spec);
184 };
185 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
186 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
187 AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
188}
189
191 if (IsHost())
193 "can't connect to the host platform '{0}', always connected",
194 GetPluginName());
195
199 /*force=*/true, nullptr);
200
203 "failed to create a 'remote-gdb-server' platform");
204
205 Status error = m_remote_platform_sp->ConnectRemote(args);
206 if (error.Fail())
207 m_remote_platform_sp.reset();
208
209 return error;
210}
211
213 const FileSpec &remote_file,
214 const std::vector<std::string> *paths,
215 Status &error, FileSpec *loaded_image) {
216 DiagnosticManager diagnostics;
217
218 if (loaded_image)
219 loaded_image->Clear();
220
222 if (!thread) {
224 "LoadLibrary error: no thread available to invoke LoadLibrary");
226 }
227
228 ExecutionContext context;
229 thread->CalculateExecutionContext(context);
230
231 Status status;
232 UtilityFunction *loader =
233 process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {
234 return MakeLoadImageUtilityFunction(context, status);
235 });
236 if (loader == nullptr)
238
239 FunctionCaller *invocation = loader->GetFunctionCaller();
240 if (!invocation) {
242 "LoadLibrary error: could not get function caller");
244 }
245
246 /* Convert name */
247 llvm::SmallVector<llvm::UTF16, 261> name;
248 if (!llvm::convertUTF8ToUTF16String(remote_file.GetPath(), name)) {
250 "LoadLibrary error: could not convert path to UCS2");
252 }
253 name.emplace_back(L'\0');
254
255 /* Inject name paramter into inferior */
256 lldb::addr_t injected_name =
257 process->AllocateMemory(name.size() * sizeof(llvm::UTF16),
258 ePermissionsReadable | ePermissionsWritable,
259 status);
260 if (injected_name == LLDB_INVALID_ADDRESS) {
262 "LoadLibrary error: unable to allocate memory for name: %s",
263 status.AsCString());
265 }
266
267 llvm::scope_exit name_cleanup(
268 [process, injected_name]() { process->DeallocateMemory(injected_name); });
269
270 process->WriteMemory(injected_name, name.data(),
271 name.size() * sizeof(llvm::UTF16), status);
272 if (status.Fail()) {
274 "LoadLibrary error: unable to write name: %s", status.AsCString());
276 }
277
278 /* Inject paths parameter into inferior */
279 lldb::addr_t injected_paths{0x0};
280 std::optional<llvm::scope_exit<std::function<void()>>> paths_cleanup;
281 if (paths) {
282 llvm::SmallVector<llvm::UTF16, 261> search_paths;
283
284 for (const auto &path : *paths) {
285 if (path.empty())
286 continue;
287
288 llvm::SmallVector<llvm::UTF16, 261> buffer;
289 if (!llvm::convertUTF8ToUTF16String(path, buffer))
290 continue;
291
292 search_paths.append(std::begin(buffer), std::end(buffer));
293 search_paths.emplace_back(L'\0');
294 }
295 search_paths.emplace_back(L'\0');
296
297 injected_paths =
298 process->AllocateMemory(search_paths.size() * sizeof(llvm::UTF16),
299 ePermissionsReadable | ePermissionsWritable,
300 status);
301 if (injected_paths == LLDB_INVALID_ADDRESS) {
303 "LoadLibrary error: unable to allocate memory for paths: %s",
304 status.AsCString());
306 }
307
308 paths_cleanup.emplace([process, injected_paths]() {
309 process->DeallocateMemory(injected_paths);
310 });
311
312 process->WriteMemory(injected_paths, search_paths.data(),
313 search_paths.size() * sizeof(llvm::UTF16), status);
314 if (status.Fail()) {
316 "LoadLibrary error: unable to write paths: %s", status.AsCString());
318 }
319 }
320
321 /* Inject wszModulePath into inferior */
322 // Start with a MAX_PATH-sized buffer (enough for the vast majority of module
323 // paths) and grow it on demand if GetModuleFileNameW reports truncation (see
324 // the loop after the helper runs).
325 unsigned injected_length = MAX_PATH;
326
327 lldb::addr_t injected_module_path = process->AllocateMemory(
328 (injected_length + 1) * sizeof(llvm::UTF16),
329 ePermissionsReadable | ePermissionsWritable, status);
330 if (injected_module_path == LLDB_INVALID_ADDRESS) {
332 "LoadLibrary error: unable to allocate memory for module location: %s",
333 status.AsCString());
335 }
336
337 llvm::scope_exit injected_module_path_cleanup(
338 [process, injected_module_path]() {
339 process->DeallocateMemory(injected_module_path);
340 });
341
342 /* Inject __lldb_LoadLibraryResult into inferior */
343 const uint32_t word_size = process->GetAddressByteSize();
344 lldb::addr_t injected_result =
345 process->AllocateMemory(3 * word_size,
346 ePermissionsReadable | ePermissionsWritable,
347 status);
348 if (status.Fail()) {
350 "LoadLibrary error: could not allocate memory for result: %s",
351 status.AsCString());
353 }
354
355 llvm::scope_exit result_cleanup([process, injected_result]() {
356 process->DeallocateMemory(injected_result);
357 });
358
359 std::vector<lldb::addr_t> grown_path_buffers;
360 llvm::scope_exit grown_path_cleanup([&]() {
361 for (lldb::addr_t buffer : grown_path_buffers)
362 process->DeallocateMemory(buffer);
363 });
364
365 process->WritePointerToMemory(injected_result, 0, status);
366 if (status.Fail()) {
368 "LoadLibrary error: could not initialize result: %s",
369 status.AsCString());
371 }
372
373 process->WritePointerToMemory(injected_result + word_size,
374 injected_module_path, status);
375 if (status.Fail()) {
377 "LoadLibrary error: could not initialize result: %s",
378 status.AsCString());
380 }
381
382 // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
383 process->WriteScalarToMemory(injected_result + 2 * word_size,
384 Scalar{injected_length}, sizeof(unsigned),
385 status);
386 if (status.Fail()) {
388 "LoadLibrary error: could not initialize result: %s",
389 status.AsCString());
391 }
392
393 /* Setup Formal Parameters */
394 ValueList parameters = invocation->GetArgumentValues();
395 parameters.GetValueAtIndex(0)->GetScalar() = injected_name;
396 parameters.GetValueAtIndex(1)->GetScalar() = injected_paths;
397 parameters.GetValueAtIndex(2)->GetScalar() = injected_result;
398
399 lldb::addr_t injected_parameters = LLDB_INVALID_ADDRESS;
400 diagnostics.Clear();
401 if (!invocation->WriteFunctionArguments(context, injected_parameters,
402 parameters, diagnostics)) {
403 error = Status::FromError(diagnostics.GetAsError(
405 "LoadLibrary error: unable to write function parameters:"));
407 }
408
409 llvm::scope_exit parameter_cleanup(
410 [invocation, &context, injected_parameters]() {
411 invocation->DeallocateFunctionResults(context, injected_parameters);
412 });
413
414 TypeSystemClangSP scratch_ts_sp =
416 if (!scratch_ts_sp) {
418 "LoadLibrary error: unable to get (clang) type system");
420 }
421
422 /* Setup Return Type */
423 CompilerType VoidPtrTy =
424 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
425
426 Value value;
427 value.SetCompilerType(VoidPtrTy);
428
429 /* Invoke expression */
433 options.SetIgnoreBreakpoints(true);
434 options.SetUnwindOnError(true);
435 // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
436 // They may potentially throw SEH exceptions which we do not know how to
437 // handle currently.
438 options.SetTrapExceptions(false);
439 options.SetTimeout(process->GetUtilityExpressionTimeout());
441 options.SetIsForUtilityExpr(true);
442
443 ExpressionResults result =
444 invocation->ExecuteFunction(context, &injected_parameters, options,
445 diagnostics, value);
446 if (result != eExpressionCompleted) {
447 error = Status::FromError(diagnostics.GetAsError(
449 llvm::formatv("failed to execute LoadLibrary helper "
450 "({0}):",
451 toString(result))
452 .str()));
454 }
455
456 /* Read result */
457 llvm::Expected<lldb::addr_t> token_or_err =
458 process->ReadPointerFromMemory(injected_result);
459 if (!token_or_err) {
461 "LoadLibrary error: could not read the result: {0}",
462 llvm::fmt_consume(token_or_err.takeError()));
464 }
465 lldb::addr_t token = *token_or_err;
466
467 if (!token) {
468 // ErrorCode is a 4-byte `unsigned` field in __lldb_LoadLibraryResult.
469 uint64_t error_code = process->ReadUnsignedIntegerFromMemory(
470 injected_result + 2 * word_size + sizeof(unsigned), sizeof(unsigned), 0,
471 status);
472 if (status.Fail()) {
474 "LoadLibrary error: could not read error status: %s",
475 status.AsCString());
477 }
478
479 error = Status::FromErrorStringWithFormat("LoadLibrary Error: %" PRIu64,
480 error_code);
482 }
483
484 lldb::addr_t module_path_addr = injected_module_path;
485 unsigned capacity = injected_length;
486 uint32_t path_length = process->ReadUnsignedIntegerFromMemory(
487 injected_result + 2 * word_size, sizeof(unsigned), 0, status);
488 while (status.Success() && path_length >= capacity &&
489 capacity < PATHCCH_MAX_CCH) {
490 capacity = std::min<unsigned>(capacity * 2, PATHCCH_MAX_CCH);
491 lldb::addr_t buffer = process->AllocateMemory(
492 (capacity + 1) * sizeof(llvm::UTF16),
493 ePermissionsReadable | ePermissionsWritable, status);
494 if (buffer == LLDB_INVALID_ADDRESS || status.Fail())
495 break;
496 grown_path_buffers.push_back(buffer);
497
498 process->WritePointerToMemory(injected_result + word_size, buffer, status);
499 if (status.Fail())
500 break;
501 process->WriteScalarToMemory(injected_result + 2 * word_size,
502 Scalar{capacity}, sizeof(unsigned), status);
503 if (status.Fail())
504 break;
505
506 diagnostics.Clear();
507 if (invocation->ExecuteFunction(context, &injected_parameters, options,
508 diagnostics, value) != eExpressionCompleted)
509 break;
510 module_path_addr = buffer;
511 path_length = process->ReadUnsignedIntegerFromMemory(
512 injected_result + 2 * word_size, sizeof(unsigned), 0, status);
513 }
514
515 llvm::SmallVector<llvm::UTF16, MAX_PATH> wide_path(path_length);
516 if (path_length)
517 process->ReadMemory(module_path_addr, wide_path.data(),
518 path_length * sizeof(llvm::UTF16), status);
519 if (status.Fail()) {
521 "LoadLibrary error: could not read module path: %s",
522 status.AsCString());
524 }
525
526 std::string module_path;
527 if (!llvm::convertUTF16ToUTF8String(
528 llvm::ArrayRef<llvm::UTF16>(wide_path.data(), wide_path.size()),
529 module_path)) {
531 "LoadLibrary error: could not convert module path to UTF-8");
533 }
534
535 if (loaded_image)
536 loaded_image->SetFile(module_path, llvm::sys::path::Style::native);
537 return process->AddImageToken(token);
538}
539
540Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {
541 const addr_t address = process->GetImagePtrFromToken(image_token);
542 if (address == LLDB_INVALID_ADDRESS)
543 return Status::FromErrorString("invalid image token");
544
545 StreamString expression;
546 expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);
547
548 ValueObjectSP value;
549 Status result =
550 EvaluateLoaderExpression(process, expression.GetData(), value);
551 if (result.Fail())
552 return result;
553
554 if (value->GetError().Fail())
555 return value->GetError().Clone();
556
557 Scalar scalar;
558 if (value->ResolveValue(scalar)) {
559 if (scalar.UInt(1))
560 return Status::FromErrorStringWithFormat("expression failed: \"%s\"",
561 expression.GetData());
562 process->ResetImageToken(image_token);
563 }
564
565 return Status();
566}
567
570
571 if (IsHost()) {
573 "can't disconnect from the host platform '{0}', always connected",
574 GetPluginName());
575 } else {
577 error = m_remote_platform_sp->DisconnectRemote();
578 else
579 error =
580 Status::FromErrorString("the platform is not currently connected");
581 }
582 return error;
583}
584
586 Debugger &debugger, Target &target,
587 Status &error) {
588 // Windows has special considerations that must be followed when launching or
589 // attaching to a process. The key requirement is that when launching or
590 // attaching to a process, you must do it from the same the thread that will
591 // go into a permanent loop which will then receive debug events from the
592 // process. In particular, this means we can't use any of LLDB's generic
593 // mechanisms to do it for us, because it doesn't have the special knowledge
594 // required for setting up the background thread or passing the right flags.
595 //
596 // Another problem is that LLDB's standard model for debugging a process
597 // is to first launch it, have it stop at the entry point, and then attach to
598 // it. In Windows this doesn't quite work, you have to specify as an
599 // argument to CreateProcess() that you're going to debug the process. So we
600 // override DebugProcess here to handle this. Launch operations go directly
601 // to the process plugin, and attach operations almost go directly to the
602 // process plugin (but we hijack the events first). In essence, we
603 // encapsulate all the logic of Launching and Attaching in the process
604 // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
605 // the process plugin.
606
607 if (IsRemote()) {
609 return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,
610 error);
611 else
612 error =
613 Status::FromErrorString("the platform is not currently connected");
614 }
615
616 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
617 // This is a process attach. Don't need to launch anything.
618 ProcessAttachInfo attach_info(launch_info);
619 return Attach(attach_info, debugger, &target, error);
620 }
621
622 Environment &env = launch_info.GetEnvironment();
623 if (GetGlobalProperties().DisableDebugHeap() &&
624 !env.contains("_NO_DEBUG_HEAP")) {
625 env.try_emplace("_NO_DEBUG_HEAP", "1");
626 }
627
628 ProcessSP process_sp =
629 target.CreateProcess(launch_info.GetListener(),
630 launch_info.GetProcessPluginName(), nullptr, false);
631 if (!process_sp)
632 return nullptr;
633
634 process_sp->HijackProcessEvents(launch_info.GetHijackListener());
635 process_sp->SetShadowListener(launch_info.GetShadowListener());
636
637 // We need to launch and attach to the process.
638 launch_info.GetFlags().Set(eLaunchFlagDebug);
639 error = process_sp->Launch(launch_info);
640#ifdef _WIN32
641 if (error.Success()) {
642 process_sp->SetPseudoConsoleHandle();
643 } else {
645 LLDB_LOGF(log, "Platform::%s LaunchProcess() failed: %s", __FUNCTION__,
646 error.AsCString());
647 }
648#endif
649
650 return process_sp;
651}
652
654 Debugger &debugger, Target *target,
655 Status &error) {
656 error.Clear();
657 lldb::ProcessSP process_sp;
658 if (!IsHost()) {
660 process_sp =
661 m_remote_platform_sp->Attach(attach_info, debugger, target, error);
662 else
663 error =
664 Status::FromErrorString("the platform is not currently connected");
665 return process_sp;
666 }
667
668 if (target == nullptr) {
669 TargetSP new_target_sp;
670 error = debugger.GetTargetList().CreateTarget(
671 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
672 target = new_target_sp.get();
673 }
674
675 if (!target || error.Fail())
676 return process_sp;
677
678 process_sp =
679 target->CreateProcess(attach_info.GetListenerForProcess(debugger),
680 attach_info.GetProcessPluginName(), nullptr, false);
681
682 if (process_sp) {
683 process_sp->HijackProcessEvents(attach_info.GetHijackListener());
684 process_sp->SetShadowListener(attach_info.GetShadowListener());
685 error = process_sp->Attach(attach_info);
686 }
687
688 return process_sp;
689}
690
693
694#ifdef _WIN32
695 llvm::VersionTuple version = HostInfo::GetOSVersion();
696 strm << " Host: Windows " << version.getAsString() << '\n';
697#endif
698}
699
700bool PlatformWindows::CanDebugProcess() { return true; }
701
702std::string PlatformWindows::GetFullNameForDylib(llvm::StringRef basename) {
703 if (basename.empty())
704 return basename.str();
705
706 return llvm::formatv("{0}.dll", basename).str();
707}
708
709size_t
711 BreakpointSite *bp_site) {
712 ArchSpec arch = target.GetArchitecture();
713 assert(arch.IsValid());
714 const uint8_t *trap_opcode = nullptr;
715 size_t trap_opcode_size = 0;
716
717 switch (arch.GetMachine()) {
718 case llvm::Triple::aarch64: {
719 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
720 trap_opcode = g_aarch64_opcode;
721 trap_opcode_size = sizeof(g_aarch64_opcode);
722
723 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
724 return trap_opcode_size;
725 return 0;
726 } break;
727
728 case llvm::Triple::arm:
729 case llvm::Triple::thumb: {
730 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
731 trap_opcode = g_thumb_opcode;
732 trap_opcode_size = sizeof(g_thumb_opcode);
733
734 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
735 return trap_opcode_size;
736 return 0;
737 } break;
738
739 default:
740 return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
741 }
742}
743
744std::unique_ptr<UtilityFunction>
746 Status &status) {
747 // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
748 static constexpr const char kLoaderDecls[] = R"(
749extern "C" {
750// errhandlingapi.h
751
752// `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
753//
754// Directories in the standard search path are not searched. This value cannot
755// be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
756//
757// This value represents the recommended maximum number of directories an
758// application should include in its DLL search path.
759#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
760
761// If this value is used, and lpFileName specifies an absolute path, the system
762// uses the alternate file search strategy to find associated executable
763// modules.
764#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
765
766// WINBASEAPI DWORD WINAPI GetLastError(VOID);
767/* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
768
769// libloaderapi.h
770
771// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
772/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
773
774// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
775/* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
776
777// WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
778/* __declspec(dllimport) */ uint32_t GetModuleFileNameW(void *, wchar_t *, uint32_t);
779
780// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
781/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
782
783// corecrt_wstring.h
784
785// _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
786/* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
787
788// lldb specific code
789
790struct __lldb_LoadLibraryResult {
791 void *ImageBase;
792 wchar_t *ModulePath;
793 unsigned Length;
794 unsigned ErrorCode;
795};
796
797_Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
798 "__lldb_LoadLibraryResult size mismatch");
799
800void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
801 __lldb_LoadLibraryResult *result) {
802 // When the caller presets ImageBase the module is already loaded and we are
803 // only re-querying its path with a larger buffer. Skip LoadLibrary in that
804 // case so we do not take an extra reference on the module.
805 if (result->ImageBase == nullptr) {
806 for (const wchar_t *path = paths; path && *path; ) {
807 (void)AddDllDirectory(path);
808 path += wcslen(path) + 1;
809 }
810
811 result->ImageBase = LoadLibraryExW(name, nullptr,
812 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
813
814 // Fallback: if the AddDllDirectory + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS path
815 // failed to find the library, iterate the search paths ourselves and
816 // load by absolute path using LOAD_WITH_ALTERED_SEARCH_PATH, which makes
817 // Windows use the loaded DLL's own directory to resolve its sibling imports.
818 if (result->ImageBase == nullptr) {
819 wchar_t full[4096];
820 for (const wchar_t *path = paths; path && *path; path += wcslen(path) + 1) {
821 size_t plen = wcslen(path);
822 size_t nlen = wcslen(name);
823 // Need room for: path + '\\' + name + '\0'
824 if (plen + 1 + nlen + 1 > 4096)
825 continue;
826 wchar_t *p = full;
827 for (size_t i = 0; i < plen; ++i)
828 *p++ = path[i];
829 *p++ = L'\\';
830 for (size_t i = 0; i <= nlen; ++i) // Copy name including trailing '\0'.
831 *p++ = name[i];
832 result->ImageBase = LoadLibraryExW(full, nullptr,
833 LOAD_WITH_ALTERED_SEARCH_PATH);
834 if (result->ImageBase != nullptr)
835 break;
836 }
837 }
838 }
839
840 if (result->ImageBase == nullptr)
841 result->ErrorCode = GetLastError();
842 else
843 result->Length = GetModuleFileNameW(result->ImageBase, result->ModulePath,
844 result->Length);
845
846 return result->ImageBase;
847}
848}
849 )";
850
851 static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
852
853 ProcessSP process = context.GetProcessSP();
854 Target &target = process->GetTarget();
855
856 auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
858 context);
859 if (!function) {
860 std::string error = llvm::toString(function.takeError());
862 "LoadLibrary error: could not create utility function: %s",
863 error.c_str());
864 return nullptr;
865 }
866
867 TypeSystemClangSP scratch_ts_sp =
869 if (!scratch_ts_sp)
870 return nullptr;
871
872 CompilerType VoidPtrTy =
873 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
874 CompilerType WCharPtrTy =
875 scratch_ts_sp->GetBasicType(eBasicTypeWChar).GetPointerType();
876
877 ValueList parameters;
878
879 Value value;
881
882 value.SetCompilerType(WCharPtrTy);
883 parameters.PushValue(value); // name
884 parameters.PushValue(value); // paths
885
886 value.SetCompilerType(VoidPtrTy);
887 parameters.PushValue(value); // result
888
890 std::unique_ptr<UtilityFunction> utility{std::move(*function)};
891 utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
892 error);
893 if (error.Fail()) {
895 "LoadLibrary error: could not create function caller: %s",
896 error.AsCString());
897 return nullptr;
898 }
899
900 if (!utility->GetFunctionCaller()) {
902 "LoadLibrary error: could not get function caller");
903 return nullptr;
904 }
905
906 return utility;
907}
908
910 const char *expression,
911 ValueObjectSP &value) {
912 // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
913 static constexpr const char kLoaderDecls[] = R"(
914extern "C" {
915// libloaderapi.h
916
917// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
918/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
919
920// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
921/* __declspec(dllimport) */ int __stdcall FreeModule(void *);
922
923// WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE, LPWSTR, DWORD);
924/* __declspec(dllimport) */ uint32_t GetModuleFileNameW(void *, wchar_t *, uint32_t);
925
926// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
927/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
928}
929 )";
930
931 if (DynamicLoader *loader = process->GetDynamicLoader()) {
932 Status result = loader->CanLoadImage();
933 if (result.Fail())
934 return result;
935 }
936
938 if (!thread)
939 return Status::FromErrorString("selected thread is invalid");
940
941 StackFrameSP frame = thread->GetStackFrameAtIndex(0);
942 if (!frame)
943 return Status::FromErrorString("frame 0 is invalid");
944
945 ExecutionContext context;
946 frame->CalculateExecutionContext(context);
947
948 EvaluateExpressionOptions options;
949 options.SetUnwindOnError(true);
950 options.SetIgnoreBreakpoints(true);
953 // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
954 // They may potentially throw SEH exceptions which we do not know how to
955 // handle currently.
956 options.SetTrapExceptions(false);
957 options.SetTimeout(process->GetUtilityExpressionTimeout());
959
961 context, options, expression, kLoaderDecls, value);
962 if (result != eExpressionCompleted)
963 return value
964 ? value->GetError().Clone()
966 "failed to execute loader helper ({0})", toString(result));
967
968 if (value && value->GetError().Fail())
969 return value->GetError().Clone();
970
971 return Status();
972}
static const size_t word_size
static llvm::raw_ostream & error(Stream &strm)
static DynamicLoaderDarwinKernelProperties & GetGlobalProperties()
#define LLDB_LOGF(log,...)
Definition Log.h:389
static uint32_t g_initialize_count
static std::chrono::microseconds GetLoaderOneThreadTimeout(Process *process)
#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:453
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:545
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition ArchSpec.cpp:883
bool TripleVendorWasSpecified() const
Definition ArchSpec.h:458
bool TripleOSWasSpecified() const
Definition ArchSpec.h:462
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 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 SetOneThreadTimeout(const Timeout< std::micro > &timeout)
Definition Target.h:434
void SetUnwindOnError(bool unwind=false)
Definition Target.h:407
void SetExecutionPolicy(ExecutionPolicy policy=eExecutionPolicyAlways)
Definition Target.h:365
void SetLanguage(lldb::LanguageType language_type)
Definition Target.h:371
void SetTimeout(const Timeout< std::micro > &timeout)
Definition Target.h:428
void SetIgnoreBreakpoints(bool ignore=false)
Definition Target.h:411
"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:56
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:380
void Clear()
Clears the object state.
Definition FileSpec.cpp:265
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::string GetFullNameForDylib(llvm::StringRef basename) override
std::unique_ptr< lldb_private::UtilityFunction > MakeLoadImageUtilityFunction(lldb_private::ExecutionContext &context, lldb_private::Status &status)
lldb_private::Status DisconnectRemote() 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
static void DebuggerInitialize(Debugger &debugger)
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:154
static void SetHostPlatform(const lldb::PlatformSP &platform_sp)
Definition Platform.cpp:161
virtual void GetStatus(Stream &strm)
Report the current status for this platform.
Definition Platform.cpp:353
static void Initialize()
Definition Platform.cpp:152
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 lldb::OptionValuePropertiesSP GetSettingForPlatformPlugin(Debugger &debugger, llvm::StringRef setting_name)
static bool CreateSettingForPlatformPlugin(Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property)
static bool UnregisterPlugin(ABICreateInstance create_callback)
lldb::ListenerSP GetListenerForProcess(Debugger &debugger)
Definition Process.cpp:3227
llvm::StringRef GetProcessPluginName() const
Definition Process.h:171
lldb::ListenerSP GetHijackListener() const
lldb::pid_t GetProcessID() const
Definition ProcessInfo.h:66
lldb::ListenerSP GetListener() const
lldb::ListenerSP GetShadowListener() const
Environment & GetEnvironment()
Definition ProcessInfo.h:86
llvm::StringRef GetProcessPluginName() const
std::chrono::seconds GetUtilityExpressionTimeout() const
Definition Process.cpp:379
A plug-in interface definition class for debugging a process.
Definition Process.h:368
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:6701
void ResetImageToken(size_t token)
Definition Process.cpp:6473
ThreadList & GetThreadList()
Definition Process.h:2367
lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, Status &error)
The public interface to allocating memory in the process.
Definition Process.cpp:2733
virtual size_t ReadMemory(const ProcessAddress &process_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Definition Process.cpp:2110
bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value, Status &error)
Definition Process.cpp:2567
size_t AddImageToken(lldb::addr_t image_ptr)
Definition Process.cpp:6462
llvm::Expected< lldb::addr_t > ReadPointerFromMemory(lldb::addr_t vm_addr)
Definition Process.cpp:2546
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:2485
Status DeallocateMemory(lldb::addr_t ptr)
The public interface to deallocating memory in the process.
Definition Process.cpp:2778
lldb::addr_t GetImagePtrFromToken(size_t token) const
Definition Process.cpp:6467
uint32_t GetAddressByteSize() const
Definition Process.cpp:3949
size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Status &error)
Write memory to a process.
Definition Process.cpp:2595
virtual DynamicLoader * GetDynamicLoader()
Get the dynamic loader plug-in for this process.
Definition Process.cpp:3121
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:2672
Target & GetTarget()
Get the target object pointer for this module.
Definition Process.h:1267
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:352
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
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:318
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:2890
const ArchSpec & GetArchitecture() const
Definition Target.h:1315
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:698
Value * GetValueAtIndex(size_t idx)
Definition Value.cpp:702
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:338
std::string toString(FormatterBytecode::OpCodes op)
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