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