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