1 //===-- SBPlatform.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 "lldb/API/SBPlatform.h" 10 #include "lldb/API/SBEnvironment.h" 11 #include "lldb/API/SBError.h" 12 #include "lldb/API/SBFileSpec.h" 13 #include "lldb/API/SBLaunchInfo.h" 14 #include "lldb/API/SBModuleSpec.h" 15 #include "lldb/API/SBPlatform.h" 16 #include "lldb/API/SBUnixSignals.h" 17 #include "lldb/Host/File.h" 18 #include "lldb/Target/Platform.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Utility/ArchSpec.h" 21 #include "lldb/Utility/Args.h" 22 #include "lldb/Utility/Instrumentation.h" 23 #include "lldb/Utility/Status.h" 24 25 #include "llvm/Support/FileSystem.h" 26 27 #include <functional> 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 // PlatformConnectOptions 33 struct PlatformConnectOptions { 34 PlatformConnectOptions(const char *url = nullptr) { 35 if (url && url[0]) 36 m_url = url; 37 } 38 39 ~PlatformConnectOptions() = default; 40 41 std::string m_url; 42 std::string m_rsync_options; 43 std::string m_rsync_remote_path_prefix; 44 bool m_rsync_enabled = false; 45 bool m_rsync_omit_hostname_from_remote_path = false; 46 ConstString m_local_cache_directory; 47 }; 48 49 // PlatformShellCommand 50 struct PlatformShellCommand { 51 PlatformShellCommand(llvm::StringRef shell_interpreter, 52 llvm::StringRef shell_command) { 53 if (!shell_interpreter.empty()) 54 m_shell = shell_interpreter.str(); 55 56 if (!m_shell.empty() && !shell_command.empty()) 57 m_command = shell_command.str(); 58 } 59 60 PlatformShellCommand(llvm::StringRef shell_command = llvm::StringRef()) { 61 if (!shell_command.empty()) 62 m_command = shell_command.str(); 63 } 64 65 ~PlatformShellCommand() = default; 66 67 std::string m_shell; 68 std::string m_command; 69 std::string m_working_dir; 70 std::string m_output; 71 int m_status = 0; 72 int m_signo = 0; 73 Timeout<std::ratio<1>> m_timeout = std::nullopt; 74 }; 75 // SBPlatformConnectOptions 76 SBPlatformConnectOptions::SBPlatformConnectOptions(const char *url) 77 : m_opaque_ptr(new PlatformConnectOptions(url)) { 78 LLDB_INSTRUMENT_VA(this, url); 79 } 80 81 SBPlatformConnectOptions::SBPlatformConnectOptions( 82 const SBPlatformConnectOptions &rhs) 83 : m_opaque_ptr(new PlatformConnectOptions()) { 84 LLDB_INSTRUMENT_VA(this, rhs); 85 86 *m_opaque_ptr = *rhs.m_opaque_ptr; 87 } 88 89 SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; } 90 91 SBPlatformConnectOptions & 92 SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) { 93 LLDB_INSTRUMENT_VA(this, rhs); 94 95 *m_opaque_ptr = *rhs.m_opaque_ptr; 96 return *this; 97 } 98 99 const char *SBPlatformConnectOptions::GetURL() { 100 LLDB_INSTRUMENT_VA(this); 101 102 if (m_opaque_ptr->m_url.empty()) 103 return nullptr; 104 return ConstString(m_opaque_ptr->m_url.c_str()).GetCString(); 105 } 106 107 void SBPlatformConnectOptions::SetURL(const char *url) { 108 LLDB_INSTRUMENT_VA(this, url); 109 110 if (url && url[0]) 111 m_opaque_ptr->m_url = url; 112 else 113 m_opaque_ptr->m_url.clear(); 114 } 115 116 bool SBPlatformConnectOptions::GetRsyncEnabled() { 117 LLDB_INSTRUMENT_VA(this); 118 119 return m_opaque_ptr->m_rsync_enabled; 120 } 121 122 void SBPlatformConnectOptions::EnableRsync( 123 const char *options, const char *remote_path_prefix, 124 bool omit_hostname_from_remote_path) { 125 LLDB_INSTRUMENT_VA(this, options, remote_path_prefix, 126 omit_hostname_from_remote_path); 127 128 m_opaque_ptr->m_rsync_enabled = true; 129 m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = 130 omit_hostname_from_remote_path; 131 if (remote_path_prefix && remote_path_prefix[0]) 132 m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix; 133 else 134 m_opaque_ptr->m_rsync_remote_path_prefix.clear(); 135 136 if (options && options[0]) 137 m_opaque_ptr->m_rsync_options = options; 138 else 139 m_opaque_ptr->m_rsync_options.clear(); 140 } 141 142 void SBPlatformConnectOptions::DisableRsync() { 143 LLDB_INSTRUMENT_VA(this); 144 145 m_opaque_ptr->m_rsync_enabled = false; 146 } 147 148 const char *SBPlatformConnectOptions::GetLocalCacheDirectory() { 149 LLDB_INSTRUMENT_VA(this); 150 151 return m_opaque_ptr->m_local_cache_directory.GetCString(); 152 } 153 154 void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) { 155 LLDB_INSTRUMENT_VA(this, path); 156 157 if (path && path[0]) 158 m_opaque_ptr->m_local_cache_directory.SetCString(path); 159 else 160 m_opaque_ptr->m_local_cache_directory = ConstString(); 161 } 162 163 // SBPlatformShellCommand 164 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter, 165 const char *shell_command) 166 : m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) { 167 LLDB_INSTRUMENT_VA(this, shell_interpreter, shell_command); 168 } 169 170 SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command) 171 : m_opaque_ptr(new PlatformShellCommand(shell_command)) { 172 LLDB_INSTRUMENT_VA(this, shell_command); 173 } 174 175 SBPlatformShellCommand::SBPlatformShellCommand( 176 const SBPlatformShellCommand &rhs) 177 : m_opaque_ptr(new PlatformShellCommand()) { 178 LLDB_INSTRUMENT_VA(this, rhs); 179 180 *m_opaque_ptr = *rhs.m_opaque_ptr; 181 } 182 183 SBPlatformShellCommand & 184 SBPlatformShellCommand::operator=(const SBPlatformShellCommand &rhs) { 185 186 LLDB_INSTRUMENT_VA(this, rhs); 187 188 *m_opaque_ptr = *rhs.m_opaque_ptr; 189 return *this; 190 } 191 192 SBPlatformShellCommand::~SBPlatformShellCommand() { delete m_opaque_ptr; } 193 194 void SBPlatformShellCommand::Clear() { 195 LLDB_INSTRUMENT_VA(this); 196 197 m_opaque_ptr->m_output = std::string(); 198 m_opaque_ptr->m_status = 0; 199 m_opaque_ptr->m_signo = 0; 200 } 201 202 const char *SBPlatformShellCommand::GetShell() { 203 LLDB_INSTRUMENT_VA(this); 204 205 if (m_opaque_ptr->m_shell.empty()) 206 return nullptr; 207 return ConstString(m_opaque_ptr->m_shell.c_str()).GetCString(); 208 } 209 210 void SBPlatformShellCommand::SetShell(const char *shell_interpreter) { 211 LLDB_INSTRUMENT_VA(this, shell_interpreter); 212 213 if (shell_interpreter && shell_interpreter[0]) 214 m_opaque_ptr->m_shell = shell_interpreter; 215 else 216 m_opaque_ptr->m_shell.clear(); 217 } 218 219 const char *SBPlatformShellCommand::GetCommand() { 220 LLDB_INSTRUMENT_VA(this); 221 222 if (m_opaque_ptr->m_command.empty()) 223 return nullptr; 224 return ConstString(m_opaque_ptr->m_command.c_str()).GetCString(); 225 } 226 227 void SBPlatformShellCommand::SetCommand(const char *shell_command) { 228 LLDB_INSTRUMENT_VA(this, shell_command); 229 230 if (shell_command && shell_command[0]) 231 m_opaque_ptr->m_command = shell_command; 232 else 233 m_opaque_ptr->m_command.clear(); 234 } 235 236 const char *SBPlatformShellCommand::GetWorkingDirectory() { 237 LLDB_INSTRUMENT_VA(this); 238 239 if (m_opaque_ptr->m_working_dir.empty()) 240 return nullptr; 241 return ConstString(m_opaque_ptr->m_working_dir.c_str()).GetCString(); 242 } 243 244 void SBPlatformShellCommand::SetWorkingDirectory(const char *path) { 245 LLDB_INSTRUMENT_VA(this, path); 246 247 if (path && path[0]) 248 m_opaque_ptr->m_working_dir = path; 249 else 250 m_opaque_ptr->m_working_dir.clear(); 251 } 252 253 uint32_t SBPlatformShellCommand::GetTimeoutSeconds() { 254 LLDB_INSTRUMENT_VA(this); 255 256 if (m_opaque_ptr->m_timeout) 257 return m_opaque_ptr->m_timeout->count(); 258 return UINT32_MAX; 259 } 260 261 void SBPlatformShellCommand::SetTimeoutSeconds(uint32_t sec) { 262 LLDB_INSTRUMENT_VA(this, sec); 263 264 if (sec == UINT32_MAX) 265 m_opaque_ptr->m_timeout = std::nullopt; 266 else 267 m_opaque_ptr->m_timeout = std::chrono::seconds(sec); 268 } 269 270 int SBPlatformShellCommand::GetSignal() { 271 LLDB_INSTRUMENT_VA(this); 272 273 return m_opaque_ptr->m_signo; 274 } 275 276 int SBPlatformShellCommand::GetStatus() { 277 LLDB_INSTRUMENT_VA(this); 278 279 return m_opaque_ptr->m_status; 280 } 281 282 const char *SBPlatformShellCommand::GetOutput() { 283 LLDB_INSTRUMENT_VA(this); 284 285 if (m_opaque_ptr->m_output.empty()) 286 return nullptr; 287 return ConstString(m_opaque_ptr->m_output.c_str()).GetCString(); 288 } 289 290 // SBPlatform 291 SBPlatform::SBPlatform() { LLDB_INSTRUMENT_VA(this); } 292 293 SBPlatform::SBPlatform(const char *platform_name) { 294 LLDB_INSTRUMENT_VA(this, platform_name); 295 296 m_opaque_sp = Platform::Create(platform_name); 297 } 298 299 SBPlatform::SBPlatform(const SBPlatform &rhs) { 300 LLDB_INSTRUMENT_VA(this, rhs); 301 302 m_opaque_sp = rhs.m_opaque_sp; 303 } 304 305 SBPlatform &SBPlatform::operator=(const SBPlatform &rhs) { 306 LLDB_INSTRUMENT_VA(this, rhs); 307 308 m_opaque_sp = rhs.m_opaque_sp; 309 return *this; 310 } 311 312 SBPlatform::~SBPlatform() = default; 313 314 SBPlatform SBPlatform::GetHostPlatform() { 315 LLDB_INSTRUMENT(); 316 317 SBPlatform host_platform; 318 host_platform.m_opaque_sp = Platform::GetHostPlatform(); 319 return host_platform; 320 } 321 322 bool SBPlatform::IsValid() const { 323 LLDB_INSTRUMENT_VA(this); 324 return this->operator bool(); 325 } 326 SBPlatform::operator bool() const { 327 LLDB_INSTRUMENT_VA(this); 328 329 return m_opaque_sp.get() != nullptr; 330 } 331 332 void SBPlatform::Clear() { 333 LLDB_INSTRUMENT_VA(this); 334 335 m_opaque_sp.reset(); 336 } 337 338 const char *SBPlatform::GetName() { 339 LLDB_INSTRUMENT_VA(this); 340 341 PlatformSP platform_sp(GetSP()); 342 if (platform_sp) 343 return ConstString(platform_sp->GetName()).AsCString(); 344 return nullptr; 345 } 346 347 lldb::PlatformSP SBPlatform::GetSP() const { return m_opaque_sp; } 348 349 void SBPlatform::SetSP(const lldb::PlatformSP &platform_sp) { 350 m_opaque_sp = platform_sp; 351 } 352 353 const char *SBPlatform::GetWorkingDirectory() { 354 LLDB_INSTRUMENT_VA(this); 355 356 PlatformSP platform_sp(GetSP()); 357 if (platform_sp) 358 return platform_sp->GetWorkingDirectory().GetPathAsConstString().AsCString(); 359 return nullptr; 360 } 361 362 bool SBPlatform::SetWorkingDirectory(const char *path) { 363 LLDB_INSTRUMENT_VA(this, path); 364 365 PlatformSP platform_sp(GetSP()); 366 if (platform_sp) { 367 if (path) 368 platform_sp->SetWorkingDirectory(FileSpec(path)); 369 else 370 platform_sp->SetWorkingDirectory(FileSpec()); 371 return true; 372 } 373 return false; 374 } 375 376 SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) { 377 LLDB_INSTRUMENT_VA(this, connect_options); 378 379 SBError sb_error; 380 PlatformSP platform_sp(GetSP()); 381 if (platform_sp && connect_options.GetURL()) { 382 Args args; 383 args.AppendArgument(connect_options.GetURL()); 384 sb_error.ref() = platform_sp->ConnectRemote(args); 385 } else { 386 sb_error.SetErrorString("invalid platform"); 387 } 388 return sb_error; 389 } 390 391 void SBPlatform::DisconnectRemote() { 392 LLDB_INSTRUMENT_VA(this); 393 394 PlatformSP platform_sp(GetSP()); 395 if (platform_sp) 396 platform_sp->DisconnectRemote(); 397 } 398 399 bool SBPlatform::IsConnected() { 400 LLDB_INSTRUMENT_VA(this); 401 402 PlatformSP platform_sp(GetSP()); 403 if (platform_sp) 404 return platform_sp->IsConnected(); 405 return false; 406 } 407 408 const char *SBPlatform::GetTriple() { 409 LLDB_INSTRUMENT_VA(this); 410 411 PlatformSP platform_sp(GetSP()); 412 if (platform_sp) { 413 ArchSpec arch(platform_sp->GetSystemArchitecture()); 414 if (arch.IsValid()) { 415 // Const-ify the string so we don't need to worry about the lifetime of 416 // the string 417 return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); 418 } 419 } 420 return nullptr; 421 } 422 423 const char *SBPlatform::GetOSBuild() { 424 LLDB_INSTRUMENT_VA(this); 425 426 PlatformSP platform_sp(GetSP()); 427 if (platform_sp) { 428 std::string s = platform_sp->GetOSBuildString().value_or(""); 429 if (!s.empty()) { 430 // Const-ify the string so we don't need to worry about the lifetime of 431 // the string 432 return ConstString(s).GetCString(); 433 } 434 } 435 return nullptr; 436 } 437 438 const char *SBPlatform::GetOSDescription() { 439 LLDB_INSTRUMENT_VA(this); 440 441 PlatformSP platform_sp(GetSP()); 442 if (platform_sp) { 443 std::string s = platform_sp->GetOSKernelDescription().value_or(""); 444 if (!s.empty()) { 445 // Const-ify the string so we don't need to worry about the lifetime of 446 // the string 447 return ConstString(s.c_str()).GetCString(); 448 } 449 } 450 return nullptr; 451 } 452 453 const char *SBPlatform::GetHostname() { 454 LLDB_INSTRUMENT_VA(this); 455 456 PlatformSP platform_sp(GetSP()); 457 if (platform_sp) 458 return ConstString(platform_sp->GetHostname()).GetCString(); 459 return nullptr; 460 } 461 462 uint32_t SBPlatform::GetOSMajorVersion() { 463 LLDB_INSTRUMENT_VA(this); 464 465 llvm::VersionTuple version; 466 if (PlatformSP platform_sp = GetSP()) 467 version = platform_sp->GetOSVersion(); 468 return version.empty() ? UINT32_MAX : version.getMajor(); 469 } 470 471 uint32_t SBPlatform::GetOSMinorVersion() { 472 LLDB_INSTRUMENT_VA(this); 473 474 llvm::VersionTuple version; 475 if (PlatformSP platform_sp = GetSP()) 476 version = platform_sp->GetOSVersion(); 477 return version.getMinor().value_or(UINT32_MAX); 478 } 479 480 uint32_t SBPlatform::GetOSUpdateVersion() { 481 LLDB_INSTRUMENT_VA(this); 482 483 llvm::VersionTuple version; 484 if (PlatformSP platform_sp = GetSP()) 485 version = platform_sp->GetOSVersion(); 486 return version.getSubminor().value_or(UINT32_MAX); 487 } 488 489 void SBPlatform::SetSDKRoot(const char *sysroot) { 490 LLDB_INSTRUMENT_VA(this, sysroot); 491 if (PlatformSP platform_sp = GetSP()) 492 platform_sp->SetSDKRootDirectory(llvm::StringRef(sysroot).str()); 493 } 494 495 SBError SBPlatform::Get(SBFileSpec &src, SBFileSpec &dst) { 496 LLDB_INSTRUMENT_VA(this, src, dst); 497 498 SBError sb_error; 499 PlatformSP platform_sp(GetSP()); 500 if (platform_sp) { 501 sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); 502 } else { 503 sb_error.SetErrorString("invalid platform"); 504 } 505 return sb_error; 506 } 507 508 SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) { 509 LLDB_INSTRUMENT_VA(this, src, dst); 510 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 511 if (src.Exists()) { 512 uint32_t permissions = FileSystem::Instance().GetPermissions(src.ref()); 513 if (permissions == 0) { 514 if (FileSystem::Instance().IsDirectory(src.ref())) 515 permissions = eFilePermissionsDirectoryDefault; 516 else 517 permissions = eFilePermissionsFileDefault; 518 } 519 520 return platform_sp->PutFile(src.ref(), dst.ref(), permissions); 521 } 522 523 Status error; 524 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 525 src.ref().GetPath().c_str()); 526 return error; 527 }); 528 } 529 530 SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) { 531 LLDB_INSTRUMENT_VA(this, src, dst); 532 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 533 if (src.Exists()) 534 return platform_sp->Install(src.ref(), dst.ref()); 535 536 Status error; 537 error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", 538 src.ref().GetPath().c_str()); 539 return error; 540 }); 541 } 542 543 SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) { 544 LLDB_INSTRUMENT_VA(this, shell_command); 545 return ExecuteConnected( 546 [&](const lldb::PlatformSP &platform_sp) { 547 const char *command = shell_command.GetCommand(); 548 if (!command) 549 return Status("invalid shell command (empty)"); 550 551 if (shell_command.GetWorkingDirectory() == nullptr) { 552 std::string platform_working_dir = 553 platform_sp->GetWorkingDirectory().GetPath(); 554 if (!platform_working_dir.empty()) 555 shell_command.SetWorkingDirectory(platform_working_dir.c_str()); 556 } 557 return platform_sp->RunShellCommand( 558 shell_command.m_opaque_ptr->m_shell, command, 559 FileSpec(shell_command.GetWorkingDirectory()), 560 &shell_command.m_opaque_ptr->m_status, 561 &shell_command.m_opaque_ptr->m_signo, 562 &shell_command.m_opaque_ptr->m_output, 563 shell_command.m_opaque_ptr->m_timeout); 564 }); 565 } 566 567 SBError SBPlatform::Launch(SBLaunchInfo &launch_info) { 568 LLDB_INSTRUMENT_VA(this, launch_info); 569 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 570 ProcessLaunchInfo info = launch_info.ref(); 571 Status error = platform_sp->LaunchProcess(info); 572 launch_info.set_ref(info); 573 return error; 574 }); 575 } 576 577 SBError SBPlatform::Kill(const lldb::pid_t pid) { 578 LLDB_INSTRUMENT_VA(this, pid); 579 return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { 580 return platform_sp->KillProcess(pid); 581 }); 582 } 583 584 SBError SBPlatform::ExecuteConnected( 585 const std::function<Status(const lldb::PlatformSP &)> &func) { 586 SBError sb_error; 587 const auto platform_sp(GetSP()); 588 if (platform_sp) { 589 if (platform_sp->IsConnected()) 590 sb_error.ref() = func(platform_sp); 591 else 592 sb_error.SetErrorString("not connected"); 593 } else 594 sb_error.SetErrorString("invalid platform"); 595 596 return sb_error; 597 } 598 599 SBError SBPlatform::MakeDirectory(const char *path, uint32_t file_permissions) { 600 LLDB_INSTRUMENT_VA(this, path, file_permissions); 601 602 SBError sb_error; 603 PlatformSP platform_sp(GetSP()); 604 if (platform_sp) { 605 sb_error.ref() = 606 platform_sp->MakeDirectory(FileSpec(path), file_permissions); 607 } else { 608 sb_error.SetErrorString("invalid platform"); 609 } 610 return sb_error; 611 } 612 613 uint32_t SBPlatform::GetFilePermissions(const char *path) { 614 LLDB_INSTRUMENT_VA(this, path); 615 616 PlatformSP platform_sp(GetSP()); 617 if (platform_sp) { 618 uint32_t file_permissions = 0; 619 platform_sp->GetFilePermissions(FileSpec(path), file_permissions); 620 return file_permissions; 621 } 622 return 0; 623 } 624 625 SBError SBPlatform::SetFilePermissions(const char *path, 626 uint32_t file_permissions) { 627 LLDB_INSTRUMENT_VA(this, path, file_permissions); 628 629 SBError sb_error; 630 PlatformSP platform_sp(GetSP()); 631 if (platform_sp) { 632 sb_error.ref() = 633 platform_sp->SetFilePermissions(FileSpec(path), file_permissions); 634 } else { 635 sb_error.SetErrorString("invalid platform"); 636 } 637 return sb_error; 638 } 639 640 SBUnixSignals SBPlatform::GetUnixSignals() const { 641 LLDB_INSTRUMENT_VA(this); 642 643 if (auto platform_sp = GetSP()) 644 return SBUnixSignals{platform_sp}; 645 646 return SBUnixSignals(); 647 } 648 649 SBEnvironment SBPlatform::GetEnvironment() { 650 LLDB_INSTRUMENT_VA(this); 651 PlatformSP platform_sp(GetSP()); 652 653 if (platform_sp) { 654 return SBEnvironment(platform_sp->GetEnvironment()); 655 } 656 657 return SBEnvironment(); 658 } 659 660 SBError SBPlatform::SetLocateModuleCallback( 661 lldb::SBPlatformLocateModuleCallback callback, void *callback_baton) { 662 LLDB_INSTRUMENT_VA(this, callback, callback_baton); 663 PlatformSP platform_sp(GetSP()); 664 if (!platform_sp) 665 return SBError("invalid platform"); 666 667 if (!callback) { 668 // Clear the callback. 669 platform_sp->SetLocateModuleCallback(nullptr); 670 return SBError(); 671 } 672 673 // Platform.h does not accept lldb::SBPlatformLocateModuleCallback directly 674 // because of the SBModuleSpec and SBFileSpec dependencies. Use a lambda to 675 // convert ModuleSpec/FileSpec <--> SBModuleSpec/SBFileSpec for the callback 676 // arguments. 677 platform_sp->SetLocateModuleCallback( 678 [callback, callback_baton](const ModuleSpec &module_spec, 679 FileSpec &module_file_spec, 680 FileSpec &symbol_file_spec) { 681 SBModuleSpec module_spec_sb(module_spec); 682 SBFileSpec module_file_spec_sb; 683 SBFileSpec symbol_file_spec_sb; 684 685 SBError error = callback(callback_baton, module_spec_sb, 686 module_file_spec_sb, symbol_file_spec_sb); 687 688 if (error.Success()) { 689 module_file_spec = module_file_spec_sb.ref(); 690 symbol_file_spec = symbol_file_spec_sb.ref(); 691 } 692 693 return error.ref(); 694 }); 695 return SBError(); 696 } 697