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