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