1 //===-- SBDebugger.cpp ------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "lldb/API/SBDebugger.h" 15 16 #include "lldb/lldb-private.h" 17 18 #include "lldb/API/SBBroadcaster.h" 19 #include "lldb/API/SBCommandInterpreter.h" 20 #include "lldb/API/SBCommandReturnObject.h" 21 #include "lldb/API/SBError.h" 22 #include "lldb/API/SBEvent.h" 23 #include "lldb/API/SBFrame.h" 24 #include "lldb/API/SBListener.h" 25 #include "lldb/API/SBProcess.h" 26 #include "lldb/API/SBSourceManager.h" 27 #include "lldb/API/SBStream.h" 28 #include "lldb/API/SBStringList.h" 29 #include "lldb/API/SBStructuredData.h" 30 #include "lldb/API/SBTarget.h" 31 #include "lldb/API/SBThread.h" 32 #include "lldb/API/SBTypeCategory.h" 33 #include "lldb/API/SBTypeFilter.h" 34 #include "lldb/API/SBTypeFormat.h" 35 #include "lldb/API/SBTypeNameSpecifier.h" 36 #include "lldb/API/SBTypeSummary.h" 37 #include "lldb/API/SBTypeSynthetic.h" 38 #include "lldb/API/SystemInitializerFull.h" 39 40 #include "lldb/Core/Debugger.h" 41 #include "lldb/Core/PluginManager.h" 42 #include "lldb/Core/State.h" 43 #include "lldb/Core/StreamFile.h" 44 #include "lldb/Core/StructuredDataImpl.h" 45 #include "lldb/DataFormatters/DataVisualization.h" 46 #include "lldb/Host/XML.h" 47 #include "lldb/Initialization/SystemLifetimeManager.h" 48 #include "lldb/Interpreter/CommandInterpreter.h" 49 #include "lldb/Interpreter/OptionArgParser.h" 50 #include "lldb/Interpreter/OptionGroupPlatform.h" 51 #include "lldb/Target/Process.h" 52 #include "lldb/Target/TargetList.h" 53 #include "lldb/Utility/Args.h" 54 55 #include "llvm/ADT/STLExtras.h" 56 #include "llvm/ADT/StringRef.h" 57 #include "llvm/Support/DynamicLibrary.h" 58 #include "llvm/Support/ManagedStatic.h" 59 60 using namespace lldb; 61 using namespace lldb_private; 62 63 static llvm::sys::DynamicLibrary LoadPlugin(const lldb::DebuggerSP &debugger_sp, 64 const FileSpec &spec, 65 Status &error) { 66 llvm::sys::DynamicLibrary dynlib = 67 llvm::sys::DynamicLibrary::getPermanentLibrary(spec.GetPath().c_str()); 68 if (dynlib.isValid()) { 69 typedef bool (*LLDBCommandPluginInit)(lldb::SBDebugger & debugger); 70 71 lldb::SBDebugger debugger_sb(debugger_sp); 72 // This calls the bool lldb::PluginInitialize(lldb::SBDebugger debugger) 73 // function. 74 // TODO: mangle this differently for your system - on OSX, the first 75 // underscore needs to be removed and the second one stays 76 LLDBCommandPluginInit init_func = 77 (LLDBCommandPluginInit)(uintptr_t)dynlib.getAddressOfSymbol( 78 "_ZN4lldb16PluginInitializeENS_10SBDebuggerE"); 79 if (init_func) { 80 if (init_func(debugger_sb)) 81 return dynlib; 82 else 83 error.SetErrorString("plug-in refused to load " 84 "(lldb::PluginInitialize(lldb::SBDebugger) " 85 "returned false)"); 86 } else { 87 error.SetErrorString("plug-in is missing the required initialization: " 88 "lldb::PluginInitialize(lldb::SBDebugger)"); 89 } 90 } else { 91 if (spec.Exists()) 92 error.SetErrorString("this file does not represent a loadable dylib"); 93 else 94 error.SetErrorString("no such file"); 95 } 96 return llvm::sys::DynamicLibrary(); 97 } 98 99 static llvm::ManagedStatic<SystemLifetimeManager> g_debugger_lifetime; 100 101 SBError SBInputReader::Initialize( 102 lldb::SBDebugger &sb_debugger, 103 unsigned long (*)(void *, lldb::SBInputReader *, lldb::InputReaderAction, 104 char const *, unsigned long), 105 void *, lldb::InputReaderGranularity, char const *, char const *, bool) { 106 return SBError(); 107 } 108 109 void SBInputReader::SetIsDone(bool) {} 110 111 bool SBInputReader::IsActive() const { return false; } 112 113 SBDebugger::SBDebugger() = default; 114 115 SBDebugger::SBDebugger(const lldb::DebuggerSP &debugger_sp) 116 : m_opaque_sp(debugger_sp) {} 117 118 SBDebugger::SBDebugger(const SBDebugger &rhs) : m_opaque_sp(rhs.m_opaque_sp) {} 119 120 SBDebugger::~SBDebugger() = default; 121 122 SBDebugger &SBDebugger::operator=(const SBDebugger &rhs) { 123 if (this != &rhs) { 124 m_opaque_sp = rhs.m_opaque_sp; 125 } 126 return *this; 127 } 128 129 void SBDebugger::Initialize() { 130 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 131 132 if (log) 133 log->Printf("SBDebugger::Initialize ()"); 134 135 g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerFull>(), 136 LoadPlugin); 137 } 138 139 void SBDebugger::Terminate() { g_debugger_lifetime->Terminate(); } 140 141 void SBDebugger::Clear() { 142 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 143 144 if (log) 145 log->Printf("SBDebugger(%p)::Clear ()", 146 static_cast<void *>(m_opaque_sp.get())); 147 148 if (m_opaque_sp) 149 m_opaque_sp->ClearIOHandlers(); 150 151 m_opaque_sp.reset(); 152 } 153 154 SBDebugger SBDebugger::Create() { 155 return SBDebugger::Create(false, nullptr, nullptr); 156 } 157 158 SBDebugger SBDebugger::Create(bool source_init_files) { 159 return SBDebugger::Create(source_init_files, nullptr, nullptr); 160 } 161 162 SBDebugger SBDebugger::Create(bool source_init_files, 163 lldb::LogOutputCallback callback, void *baton) 164 165 { 166 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 167 168 SBDebugger debugger; 169 170 // Currently we have issues if this function is called simultaneously on two 171 // different threads. The issues mainly revolve around the fact that the 172 // lldb_private::FormatManager uses global collections and having two threads 173 // parsing the .lldbinit files can cause mayhem. So to get around this for 174 // now we need to use a mutex to prevent bad things from happening. 175 static std::recursive_mutex g_mutex; 176 std::lock_guard<std::recursive_mutex> guard(g_mutex); 177 178 debugger.reset(Debugger::CreateInstance(callback, baton)); 179 180 if (log) { 181 SBStream sstr; 182 debugger.GetDescription(sstr); 183 log->Printf("SBDebugger::Create () => SBDebugger(%p): %s", 184 static_cast<void *>(debugger.m_opaque_sp.get()), 185 sstr.GetData()); 186 } 187 188 SBCommandInterpreter interp = debugger.GetCommandInterpreter(); 189 if (source_init_files) { 190 interp.get()->SkipLLDBInitFiles(false); 191 interp.get()->SkipAppInitFiles(false); 192 SBCommandReturnObject result; 193 interp.SourceInitFileInHomeDirectory(result); 194 } else { 195 interp.get()->SkipLLDBInitFiles(true); 196 interp.get()->SkipAppInitFiles(true); 197 } 198 return debugger; 199 } 200 201 void SBDebugger::Destroy(SBDebugger &debugger) { 202 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 203 204 if (log) { 205 SBStream sstr; 206 debugger.GetDescription(sstr); 207 log->Printf("SBDebugger::Destroy () => SBDebugger(%p): %s", 208 static_cast<void *>(debugger.m_opaque_sp.get()), 209 sstr.GetData()); 210 } 211 212 Debugger::Destroy(debugger.m_opaque_sp); 213 214 if (debugger.m_opaque_sp.get() != nullptr) 215 debugger.m_opaque_sp.reset(); 216 } 217 218 void SBDebugger::MemoryPressureDetected() { 219 // Since this function can be call asynchronously, we allow it to be non- 220 // mandatory. We have seen deadlocks with this function when called so we 221 // need to safeguard against this until we can determine what is causing the 222 // deadlocks. 223 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 224 225 const bool mandatory = false; 226 if (log) { 227 log->Printf("SBDebugger::MemoryPressureDetected (), mandatory = %d", 228 mandatory); 229 } 230 231 ModuleList::RemoveOrphanSharedModules(mandatory); 232 } 233 234 bool SBDebugger::IsValid() const { return m_opaque_sp.get() != nullptr; } 235 236 void SBDebugger::SetAsync(bool b) { 237 if (m_opaque_sp) 238 m_opaque_sp->SetAsyncExecution(b); 239 } 240 241 bool SBDebugger::GetAsync() { 242 return (m_opaque_sp ? m_opaque_sp->GetAsyncExecution() : false); 243 } 244 245 void SBDebugger::SkipLLDBInitFiles(bool b) { 246 if (m_opaque_sp) 247 m_opaque_sp->GetCommandInterpreter().SkipLLDBInitFiles(b); 248 } 249 250 void SBDebugger::SkipAppInitFiles(bool b) { 251 if (m_opaque_sp) 252 m_opaque_sp->GetCommandInterpreter().SkipAppInitFiles(b); 253 } 254 255 // Shouldn't really be settable after initialization as this could cause lots 256 // of problems; don't want users trying to switch modes in the middle of a 257 // debugging session. 258 void SBDebugger::SetInputFileHandle(FILE *fh, bool transfer_ownership) { 259 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 260 261 if (log) 262 log->Printf( 263 "SBDebugger(%p)::SetInputFileHandle (fh=%p, transfer_ownership=%i)", 264 static_cast<void *>(m_opaque_sp.get()), static_cast<void *>(fh), 265 transfer_ownership); 266 267 if (m_opaque_sp) 268 m_opaque_sp->SetInputFileHandle(fh, transfer_ownership); 269 } 270 271 void SBDebugger::SetOutputFileHandle(FILE *fh, bool transfer_ownership) { 272 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 273 274 if (log) 275 log->Printf( 276 "SBDebugger(%p)::SetOutputFileHandle (fh=%p, transfer_ownership=%i)", 277 static_cast<void *>(m_opaque_sp.get()), static_cast<void *>(fh), 278 transfer_ownership); 279 280 if (m_opaque_sp) 281 m_opaque_sp->SetOutputFileHandle(fh, transfer_ownership); 282 } 283 284 void SBDebugger::SetErrorFileHandle(FILE *fh, bool transfer_ownership) { 285 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 286 287 if (log) 288 log->Printf( 289 "SBDebugger(%p)::SetErrorFileHandle (fh=%p, transfer_ownership=%i)", 290 static_cast<void *>(m_opaque_sp.get()), static_cast<void *>(fh), 291 transfer_ownership); 292 293 if (m_opaque_sp) 294 m_opaque_sp->SetErrorFileHandle(fh, transfer_ownership); 295 } 296 297 FILE *SBDebugger::GetInputFileHandle() { 298 if (m_opaque_sp) { 299 StreamFileSP stream_file_sp(m_opaque_sp->GetInputFile()); 300 if (stream_file_sp) 301 return stream_file_sp->GetFile().GetStream(); 302 } 303 return nullptr; 304 } 305 306 FILE *SBDebugger::GetOutputFileHandle() { 307 if (m_opaque_sp) { 308 StreamFileSP stream_file_sp(m_opaque_sp->GetOutputFile()); 309 if (stream_file_sp) 310 return stream_file_sp->GetFile().GetStream(); 311 } 312 return nullptr; 313 } 314 315 FILE *SBDebugger::GetErrorFileHandle() { 316 if (m_opaque_sp) { 317 StreamFileSP stream_file_sp(m_opaque_sp->GetErrorFile()); 318 if (stream_file_sp) 319 return stream_file_sp->GetFile().GetStream(); 320 } 321 return nullptr; 322 } 323 324 void SBDebugger::SaveInputTerminalState() { 325 if (m_opaque_sp) 326 m_opaque_sp->SaveInputTerminalState(); 327 } 328 329 void SBDebugger::RestoreInputTerminalState() { 330 if (m_opaque_sp) 331 m_opaque_sp->RestoreInputTerminalState(); 332 } 333 SBCommandInterpreter SBDebugger::GetCommandInterpreter() { 334 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 335 336 SBCommandInterpreter sb_interpreter; 337 if (m_opaque_sp) 338 sb_interpreter.reset(&m_opaque_sp->GetCommandInterpreter()); 339 340 if (log) 341 log->Printf( 342 "SBDebugger(%p)::GetCommandInterpreter () => SBCommandInterpreter(%p)", 343 static_cast<void *>(m_opaque_sp.get()), 344 static_cast<void *>(sb_interpreter.get())); 345 346 return sb_interpreter; 347 } 348 349 void SBDebugger::HandleCommand(const char *command) { 350 if (m_opaque_sp) { 351 TargetSP target_sp(m_opaque_sp->GetSelectedTarget()); 352 std::unique_lock<std::recursive_mutex> lock; 353 if (target_sp) 354 lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex()); 355 356 SBCommandInterpreter sb_interpreter(GetCommandInterpreter()); 357 SBCommandReturnObject result; 358 359 sb_interpreter.HandleCommand(command, result, false); 360 361 if (GetErrorFileHandle() != nullptr) 362 result.PutError(GetErrorFileHandle()); 363 if (GetOutputFileHandle() != nullptr) 364 result.PutOutput(GetOutputFileHandle()); 365 366 if (!m_opaque_sp->GetAsyncExecution()) { 367 SBProcess process(GetCommandInterpreter().GetProcess()); 368 ProcessSP process_sp(process.GetSP()); 369 if (process_sp) { 370 EventSP event_sp; 371 ListenerSP lldb_listener_sp = m_opaque_sp->GetListener(); 372 while (lldb_listener_sp->GetEventForBroadcaster( 373 process_sp.get(), event_sp, std::chrono::seconds(0))) { 374 SBEvent event(event_sp); 375 HandleProcessEvent(process, event, GetOutputFileHandle(), 376 GetErrorFileHandle()); 377 } 378 } 379 } 380 } 381 } 382 383 SBListener SBDebugger::GetListener() { 384 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 385 386 SBListener sb_listener; 387 if (m_opaque_sp) 388 sb_listener.reset(m_opaque_sp->GetListener()); 389 390 if (log) 391 log->Printf("SBDebugger(%p)::GetListener () => SBListener(%p)", 392 static_cast<void *>(m_opaque_sp.get()), 393 static_cast<void *>(sb_listener.get())); 394 395 return sb_listener; 396 } 397 398 void SBDebugger::HandleProcessEvent(const SBProcess &process, 399 const SBEvent &event, FILE *out, 400 FILE *err) { 401 if (!process.IsValid()) 402 return; 403 404 TargetSP target_sp(process.GetTarget().GetSP()); 405 if (!target_sp) 406 return; 407 408 const uint32_t event_type = event.GetType(); 409 char stdio_buffer[1024]; 410 size_t len; 411 412 std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex()); 413 414 if (event_type & 415 (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitStateChanged)) { 416 // Drain stdout when we stop just in case we have any bytes 417 while ((len = process.GetSTDOUT(stdio_buffer, sizeof(stdio_buffer))) > 0) 418 if (out != nullptr) 419 ::fwrite(stdio_buffer, 1, len, out); 420 } 421 422 if (event_type & 423 (Process::eBroadcastBitSTDERR | Process::eBroadcastBitStateChanged)) { 424 // Drain stderr when we stop just in case we have any bytes 425 while ((len = process.GetSTDERR(stdio_buffer, sizeof(stdio_buffer))) > 0) 426 if (err != nullptr) 427 ::fwrite(stdio_buffer, 1, len, err); 428 } 429 430 if (event_type & Process::eBroadcastBitStateChanged) { 431 StateType event_state = SBProcess::GetStateFromEvent(event); 432 433 if (event_state == eStateInvalid) 434 return; 435 436 bool is_stopped = StateIsStoppedState(event_state); 437 if (!is_stopped) 438 process.ReportEventState(event, out); 439 } 440 } 441 442 SBSourceManager SBDebugger::GetSourceManager() { 443 SBSourceManager sb_source_manager(*this); 444 return sb_source_manager; 445 } 446 447 bool SBDebugger::GetDefaultArchitecture(char *arch_name, size_t arch_name_len) { 448 if (arch_name && arch_name_len) { 449 ArchSpec default_arch = Target::GetDefaultArchitecture(); 450 451 if (default_arch.IsValid()) { 452 const std::string &triple_str = default_arch.GetTriple().str(); 453 if (!triple_str.empty()) 454 ::snprintf(arch_name, arch_name_len, "%s", triple_str.c_str()); 455 else 456 ::snprintf(arch_name, arch_name_len, "%s", 457 default_arch.GetArchitectureName()); 458 return true; 459 } 460 } 461 if (arch_name && arch_name_len) 462 arch_name[0] = '\0'; 463 return false; 464 } 465 466 bool SBDebugger::SetDefaultArchitecture(const char *arch_name) { 467 if (arch_name) { 468 ArchSpec arch(arch_name); 469 if (arch.IsValid()) { 470 Target::SetDefaultArchitecture(arch); 471 return true; 472 } 473 } 474 return false; 475 } 476 477 ScriptLanguage 478 SBDebugger::GetScriptingLanguage(const char *script_language_name) { 479 if (!script_language_name) return eScriptLanguageDefault; 480 return OptionArgParser::ToScriptLanguage( 481 llvm::StringRef(script_language_name), eScriptLanguageDefault, nullptr); 482 } 483 484 const char *SBDebugger::GetVersionString() { 485 return lldb_private::GetVersion(); 486 } 487 488 const char *SBDebugger::StateAsCString(StateType state) { 489 return lldb_private::StateAsCString(state); 490 } 491 492 static void AddBoolConfigEntry(StructuredData::Dictionary &dict, 493 llvm::StringRef name, bool value, 494 llvm::StringRef description) { 495 auto entry_up = llvm::make_unique<StructuredData::Dictionary>(); 496 entry_up->AddBooleanItem("value", value); 497 entry_up->AddStringItem("description", description); 498 dict.AddItem(name, std::move(entry_up)); 499 } 500 501 SBStructuredData SBDebugger::GetBuildConfiguration() { 502 auto config_up = llvm::make_unique<StructuredData::Dictionary>(); 503 AddBoolConfigEntry( 504 *config_up, "xml", XMLDocument::XMLEnabled(), 505 "A boolean value that indicates if XML support is enabled in LLDB"); 506 507 SBStructuredData data; 508 data.m_impl_up->SetObjectSP(std::move(config_up)); 509 return data; 510 } 511 512 bool SBDebugger::StateIsRunningState(StateType state) { 513 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 514 515 const bool result = lldb_private::StateIsRunningState(state); 516 if (log) 517 log->Printf("SBDebugger::StateIsRunningState (state=%s) => %i", 518 StateAsCString(state), result); 519 520 return result; 521 } 522 523 bool SBDebugger::StateIsStoppedState(StateType state) { 524 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 525 526 const bool result = lldb_private::StateIsStoppedState(state, false); 527 if (log) 528 log->Printf("SBDebugger::StateIsStoppedState (state=%s) => %i", 529 StateAsCString(state), result); 530 531 return result; 532 } 533 534 lldb::SBTarget SBDebugger::CreateTarget(const char *filename, 535 const char *target_triple, 536 const char *platform_name, 537 bool add_dependent_modules, 538 lldb::SBError &sb_error) { 539 SBTarget sb_target; 540 TargetSP target_sp; 541 if (m_opaque_sp) { 542 sb_error.Clear(); 543 OptionGroupPlatform platform_options(false); 544 platform_options.SetPlatformName(platform_name); 545 546 sb_error.ref() = m_opaque_sp->GetTargetList().CreateTarget( 547 *m_opaque_sp, filename, target_triple, add_dependent_modules, 548 &platform_options, target_sp); 549 550 if (sb_error.Success()) 551 sb_target.SetSP(target_sp); 552 } else { 553 sb_error.SetErrorString("invalid debugger"); 554 } 555 556 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 557 if (log) 558 log->Printf("SBDebugger(%p)::CreateTarget (filename=\"%s\", triple=%s, " 559 "platform_name=%s, add_dependent_modules=%u, error=%s) => " 560 "SBTarget(%p)", 561 static_cast<void *>(m_opaque_sp.get()), filename, target_triple, 562 platform_name, add_dependent_modules, sb_error.GetCString(), 563 static_cast<void *>(target_sp.get())); 564 565 return sb_target; 566 } 567 568 SBTarget 569 SBDebugger::CreateTargetWithFileAndTargetTriple(const char *filename, 570 const char *target_triple) { 571 SBTarget sb_target; 572 TargetSP target_sp; 573 if (m_opaque_sp) { 574 const bool add_dependent_modules = true; 575 Status error(m_opaque_sp->GetTargetList().CreateTarget( 576 *m_opaque_sp, filename, target_triple, add_dependent_modules, nullptr, 577 target_sp)); 578 sb_target.SetSP(target_sp); 579 } 580 581 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 582 if (log) 583 log->Printf("SBDebugger(%p)::CreateTargetWithFileAndTargetTriple " 584 "(filename=\"%s\", triple=%s) => SBTarget(%p)", 585 static_cast<void *>(m_opaque_sp.get()), filename, target_triple, 586 static_cast<void *>(target_sp.get())); 587 588 return sb_target; 589 } 590 591 SBTarget SBDebugger::CreateTargetWithFileAndArch(const char *filename, 592 const char *arch_cstr) { 593 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 594 595 SBTarget sb_target; 596 TargetSP target_sp; 597 if (m_opaque_sp) { 598 Status error; 599 const bool add_dependent_modules = true; 600 601 error = m_opaque_sp->GetTargetList().CreateTarget( 602 *m_opaque_sp, filename, arch_cstr, add_dependent_modules, nullptr, 603 target_sp); 604 605 if (error.Success()) { 606 m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp.get()); 607 sb_target.SetSP(target_sp); 608 } 609 } 610 611 if (log) 612 log->Printf("SBDebugger(%p)::CreateTargetWithFileAndArch (filename=\"%s\", " 613 "arch=%s) => SBTarget(%p)", 614 static_cast<void *>(m_opaque_sp.get()), filename, arch_cstr, 615 static_cast<void *>(target_sp.get())); 616 617 return sb_target; 618 } 619 620 SBTarget SBDebugger::CreateTarget(const char *filename) { 621 SBTarget sb_target; 622 TargetSP target_sp; 623 if (m_opaque_sp) { 624 Status error; 625 const bool add_dependent_modules = true; 626 error = m_opaque_sp->GetTargetList().CreateTarget( 627 *m_opaque_sp, filename, "", add_dependent_modules, nullptr, target_sp); 628 629 if (error.Success()) { 630 m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp.get()); 631 sb_target.SetSP(target_sp); 632 } 633 } 634 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 635 if (log) 636 log->Printf( 637 "SBDebugger(%p)::CreateTarget (filename=\"%s\") => SBTarget(%p)", 638 static_cast<void *>(m_opaque_sp.get()), filename, 639 static_cast<void *>(target_sp.get())); 640 return sb_target; 641 } 642 643 SBTarget SBDebugger::GetDummyTarget() { 644 SBTarget sb_target; 645 if (m_opaque_sp) { 646 sb_target.SetSP(m_opaque_sp->GetDummyTarget()->shared_from_this()); 647 } 648 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 649 if (log) 650 log->Printf( 651 "SBDebugger(%p)::GetDummyTarget() => SBTarget(%p)", 652 static_cast<void *>(m_opaque_sp.get()), 653 static_cast<void *>(sb_target.GetSP().get())); 654 return sb_target; 655 } 656 657 bool SBDebugger::DeleteTarget(lldb::SBTarget &target) { 658 bool result = false; 659 if (m_opaque_sp) { 660 TargetSP target_sp(target.GetSP()); 661 if (target_sp) { 662 // No need to lock, the target list is thread safe 663 result = m_opaque_sp->GetTargetList().DeleteTarget(target_sp); 664 target_sp->Destroy(); 665 target.Clear(); 666 const bool mandatory = true; 667 ModuleList::RemoveOrphanSharedModules(mandatory); 668 } 669 } 670 671 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 672 if (log) 673 log->Printf("SBDebugger(%p)::DeleteTarget (SBTarget(%p)) => %i", 674 static_cast<void *>(m_opaque_sp.get()), 675 static_cast<void *>(target.m_opaque_sp.get()), result); 676 677 return result; 678 } 679 680 SBTarget SBDebugger::GetTargetAtIndex(uint32_t idx) { 681 SBTarget sb_target; 682 if (m_opaque_sp) { 683 // No need to lock, the target list is thread safe 684 sb_target.SetSP(m_opaque_sp->GetTargetList().GetTargetAtIndex(idx)); 685 } 686 return sb_target; 687 } 688 689 uint32_t SBDebugger::GetIndexOfTarget(lldb::SBTarget target) { 690 691 lldb::TargetSP target_sp = target.GetSP(); 692 if (!target_sp) 693 return UINT32_MAX; 694 695 if (!m_opaque_sp) 696 return UINT32_MAX; 697 698 return m_opaque_sp->GetTargetList().GetIndexOfTarget(target.GetSP()); 699 } 700 701 SBTarget SBDebugger::FindTargetWithProcessID(lldb::pid_t pid) { 702 SBTarget sb_target; 703 if (m_opaque_sp) { 704 // No need to lock, the target list is thread safe 705 sb_target.SetSP(m_opaque_sp->GetTargetList().FindTargetWithProcessID(pid)); 706 } 707 return sb_target; 708 } 709 710 SBTarget SBDebugger::FindTargetWithFileAndArch(const char *filename, 711 const char *arch_name) { 712 SBTarget sb_target; 713 if (m_opaque_sp && filename && filename[0]) { 714 // No need to lock, the target list is thread safe 715 ArchSpec arch = Platform::GetAugmentedArchSpec( 716 m_opaque_sp->GetPlatformList().GetSelectedPlatform().get(), arch_name); 717 TargetSP target_sp( 718 m_opaque_sp->GetTargetList().FindTargetWithExecutableAndArchitecture( 719 FileSpec(filename, false), arch_name ? &arch : nullptr)); 720 sb_target.SetSP(target_sp); 721 } 722 return sb_target; 723 } 724 725 SBTarget SBDebugger::FindTargetWithLLDBProcess(const ProcessSP &process_sp) { 726 SBTarget sb_target; 727 if (m_opaque_sp) { 728 // No need to lock, the target list is thread safe 729 sb_target.SetSP( 730 m_opaque_sp->GetTargetList().FindTargetWithProcess(process_sp.get())); 731 } 732 return sb_target; 733 } 734 735 uint32_t SBDebugger::GetNumTargets() { 736 if (m_opaque_sp) { 737 // No need to lock, the target list is thread safe 738 return m_opaque_sp->GetTargetList().GetNumTargets(); 739 } 740 return 0; 741 } 742 743 SBTarget SBDebugger::GetSelectedTarget() { 744 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 745 746 SBTarget sb_target; 747 TargetSP target_sp; 748 if (m_opaque_sp) { 749 // No need to lock, the target list is thread safe 750 target_sp = m_opaque_sp->GetTargetList().GetSelectedTarget(); 751 sb_target.SetSP(target_sp); 752 } 753 754 if (log) { 755 SBStream sstr; 756 sb_target.GetDescription(sstr, eDescriptionLevelBrief); 757 log->Printf("SBDebugger(%p)::GetSelectedTarget () => SBTarget(%p): %s", 758 static_cast<void *>(m_opaque_sp.get()), 759 static_cast<void *>(target_sp.get()), sstr.GetData()); 760 } 761 762 return sb_target; 763 } 764 765 void SBDebugger::SetSelectedTarget(SBTarget &sb_target) { 766 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 767 768 TargetSP target_sp(sb_target.GetSP()); 769 if (m_opaque_sp) { 770 m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp.get()); 771 } 772 if (log) { 773 SBStream sstr; 774 sb_target.GetDescription(sstr, eDescriptionLevelBrief); 775 log->Printf("SBDebugger(%p)::SetSelectedTarget () => SBTarget(%p): %s", 776 static_cast<void *>(m_opaque_sp.get()), 777 static_cast<void *>(target_sp.get()), sstr.GetData()); 778 } 779 } 780 781 SBPlatform SBDebugger::GetSelectedPlatform() { 782 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 783 784 SBPlatform sb_platform; 785 DebuggerSP debugger_sp(m_opaque_sp); 786 if (debugger_sp) { 787 sb_platform.SetSP(debugger_sp->GetPlatformList().GetSelectedPlatform()); 788 } 789 if (log) 790 log->Printf("SBDebugger(%p)::GetSelectedPlatform () => SBPlatform(%p): %s", 791 static_cast<void *>(m_opaque_sp.get()), 792 static_cast<void *>(sb_platform.GetSP().get()), 793 sb_platform.GetName()); 794 return sb_platform; 795 } 796 797 void SBDebugger::SetSelectedPlatform(SBPlatform &sb_platform) { 798 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 799 800 DebuggerSP debugger_sp(m_opaque_sp); 801 if (debugger_sp) { 802 debugger_sp->GetPlatformList().SetSelectedPlatform(sb_platform.GetSP()); 803 } 804 805 if (log) 806 log->Printf("SBDebugger(%p)::SetSelectedPlatform (SBPlatform(%p) %s)", 807 static_cast<void *>(m_opaque_sp.get()), 808 static_cast<void *>(sb_platform.GetSP().get()), 809 sb_platform.GetName()); 810 } 811 812 uint32_t SBDebugger::GetNumPlatforms() { 813 if (m_opaque_sp) { 814 // No need to lock, the platform list is thread safe 815 return m_opaque_sp->GetPlatformList().GetSize(); 816 } 817 return 0; 818 } 819 820 SBPlatform SBDebugger::GetPlatformAtIndex(uint32_t idx) { 821 SBPlatform sb_platform; 822 if (m_opaque_sp) { 823 // No need to lock, the platform list is thread safe 824 sb_platform.SetSP(m_opaque_sp->GetPlatformList().GetAtIndex(idx)); 825 } 826 return sb_platform; 827 } 828 829 uint32_t SBDebugger::GetNumAvailablePlatforms() { 830 uint32_t idx = 0; 831 while (true) { 832 if (!PluginManager::GetPlatformPluginNameAtIndex(idx)) { 833 break; 834 } 835 ++idx; 836 } 837 // +1 for the host platform, which should always appear first in the list. 838 return idx + 1; 839 } 840 841 SBStructuredData SBDebugger::GetAvailablePlatformInfoAtIndex(uint32_t idx) { 842 SBStructuredData data; 843 auto platform_dict = llvm::make_unique<StructuredData::Dictionary>(); 844 llvm::StringRef name_str("name"), desc_str("description"); 845 846 if (idx == 0) { 847 PlatformSP host_platform_sp(Platform::GetHostPlatform()); 848 platform_dict->AddStringItem( 849 name_str, host_platform_sp->GetPluginName().GetStringRef()); 850 platform_dict->AddStringItem( 851 desc_str, llvm::StringRef(host_platform_sp->GetDescription())); 852 } else if (idx > 0) { 853 const char *plugin_name = 854 PluginManager::GetPlatformPluginNameAtIndex(idx - 1); 855 if (!plugin_name) { 856 return data; 857 } 858 platform_dict->AddStringItem(name_str, llvm::StringRef(plugin_name)); 859 860 const char *plugin_desc = 861 PluginManager::GetPlatformPluginDescriptionAtIndex(idx - 1); 862 if (!plugin_desc) { 863 return data; 864 } 865 platform_dict->AddStringItem(desc_str, llvm::StringRef(plugin_desc)); 866 } 867 868 data.m_impl_up->SetObjectSP( 869 StructuredData::ObjectSP(platform_dict.release())); 870 return data; 871 } 872 873 void SBDebugger::DispatchInput(void *baton, const void *data, size_t data_len) { 874 DispatchInput(data, data_len); 875 } 876 877 void SBDebugger::DispatchInput(const void *data, size_t data_len) { 878 // Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); 879 // 880 // if (log) 881 // log->Printf ("SBDebugger(%p)::DispatchInput (data=\"%.*s\", 882 // size_t=%" PRIu64 ")", 883 // m_opaque_sp.get(), 884 // (int) data_len, 885 // (const char *) data, 886 // (uint64_t)data_len); 887 // 888 // if (m_opaque_sp) 889 // m_opaque_sp->DispatchInput ((const char *) data, data_len); 890 } 891 892 void SBDebugger::DispatchInputInterrupt() { 893 if (m_opaque_sp) 894 m_opaque_sp->DispatchInputInterrupt(); 895 } 896 897 void SBDebugger::DispatchInputEndOfFile() { 898 if (m_opaque_sp) 899 m_opaque_sp->DispatchInputEndOfFile(); 900 } 901 902 void SBDebugger::PushInputReader(SBInputReader &reader) {} 903 904 void SBDebugger::RunCommandInterpreter(bool auto_handle_events, 905 bool spawn_thread) { 906 if (m_opaque_sp) { 907 CommandInterpreterRunOptions options; 908 909 m_opaque_sp->GetCommandInterpreter().RunCommandInterpreter( 910 auto_handle_events, spawn_thread, options); 911 } 912 } 913 914 void SBDebugger::RunCommandInterpreter(bool auto_handle_events, 915 bool spawn_thread, 916 SBCommandInterpreterRunOptions &options, 917 int &num_errors, bool &quit_requested, 918 bool &stopped_for_crash) 919 920 { 921 if (m_opaque_sp) { 922 CommandInterpreter &interp = m_opaque_sp->GetCommandInterpreter(); 923 interp.RunCommandInterpreter(auto_handle_events, spawn_thread, 924 options.ref()); 925 num_errors = interp.GetNumErrors(); 926 quit_requested = interp.GetQuitRequested(); 927 stopped_for_crash = interp.GetStoppedForCrash(); 928 } 929 } 930 931 SBError SBDebugger::RunREPL(lldb::LanguageType language, 932 const char *repl_options) { 933 SBError error; 934 if (m_opaque_sp) 935 error.ref() = m_opaque_sp->RunREPL(language, repl_options); 936 else 937 error.SetErrorString("invalid debugger"); 938 return error; 939 } 940 941 void SBDebugger::reset(const DebuggerSP &debugger_sp) { 942 m_opaque_sp = debugger_sp; 943 } 944 945 Debugger *SBDebugger::get() const { return m_opaque_sp.get(); } 946 947 Debugger &SBDebugger::ref() const { 948 assert(m_opaque_sp.get()); 949 return *m_opaque_sp; 950 } 951 952 const lldb::DebuggerSP &SBDebugger::get_sp() const { return m_opaque_sp; } 953 954 SBDebugger SBDebugger::FindDebuggerWithID(int id) { 955 // No need to lock, the debugger list is thread safe 956 SBDebugger sb_debugger; 957 DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(id); 958 if (debugger_sp) 959 sb_debugger.reset(debugger_sp); 960 return sb_debugger; 961 } 962 963 const char *SBDebugger::GetInstanceName() { 964 return (m_opaque_sp ? m_opaque_sp->GetInstanceName().AsCString() : nullptr); 965 } 966 967 SBError SBDebugger::SetInternalVariable(const char *var_name, const char *value, 968 const char *debugger_instance_name) { 969 SBError sb_error; 970 DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName( 971 ConstString(debugger_instance_name))); 972 Status error; 973 if (debugger_sp) { 974 ExecutionContext exe_ctx( 975 debugger_sp->GetCommandInterpreter().GetExecutionContext()); 976 error = debugger_sp->SetPropertyValue(&exe_ctx, eVarSetOperationAssign, 977 var_name, value); 978 } else { 979 error.SetErrorStringWithFormat("invalid debugger instance name '%s'", 980 debugger_instance_name); 981 } 982 if (error.Fail()) 983 sb_error.SetError(error); 984 return sb_error; 985 } 986 987 SBStringList 988 SBDebugger::GetInternalVariableValue(const char *var_name, 989 const char *debugger_instance_name) { 990 SBStringList ret_value; 991 DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName( 992 ConstString(debugger_instance_name))); 993 Status error; 994 if (debugger_sp) { 995 ExecutionContext exe_ctx( 996 debugger_sp->GetCommandInterpreter().GetExecutionContext()); 997 lldb::OptionValueSP value_sp( 998 debugger_sp->GetPropertyValue(&exe_ctx, var_name, false, error)); 999 if (value_sp) { 1000 StreamString value_strm; 1001 value_sp->DumpValue(&exe_ctx, value_strm, OptionValue::eDumpOptionValue); 1002 const std::string &value_str = value_strm.GetString(); 1003 if (!value_str.empty()) { 1004 StringList string_list; 1005 string_list.SplitIntoLines(value_str); 1006 return SBStringList(&string_list); 1007 } 1008 } 1009 } 1010 return SBStringList(); 1011 } 1012 1013 uint32_t SBDebugger::GetTerminalWidth() const { 1014 return (m_opaque_sp ? m_opaque_sp->GetTerminalWidth() : 0); 1015 } 1016 1017 void SBDebugger::SetTerminalWidth(uint32_t term_width) { 1018 if (m_opaque_sp) 1019 m_opaque_sp->SetTerminalWidth(term_width); 1020 } 1021 1022 const char *SBDebugger::GetPrompt() const { 1023 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 1024 1025 if (log) 1026 log->Printf("SBDebugger(%p)::GetPrompt () => \"%s\"", 1027 static_cast<void *>(m_opaque_sp.get()), 1028 (m_opaque_sp ? m_opaque_sp->GetPrompt().str().c_str() : "")); 1029 1030 return (m_opaque_sp ? ConstString(m_opaque_sp->GetPrompt()).GetCString() 1031 : nullptr); 1032 } 1033 1034 void SBDebugger::SetPrompt(const char *prompt) { 1035 if (m_opaque_sp) 1036 m_opaque_sp->SetPrompt(llvm::StringRef::withNullAsEmpty(prompt)); 1037 } 1038 1039 ScriptLanguage SBDebugger::GetScriptLanguage() const { 1040 return (m_opaque_sp ? m_opaque_sp->GetScriptLanguage() : eScriptLanguageNone); 1041 } 1042 1043 void SBDebugger::SetScriptLanguage(ScriptLanguage script_lang) { 1044 if (m_opaque_sp) { 1045 m_opaque_sp->SetScriptLanguage(script_lang); 1046 } 1047 } 1048 1049 bool SBDebugger::SetUseExternalEditor(bool value) { 1050 return (m_opaque_sp ? m_opaque_sp->SetUseExternalEditor(value) : false); 1051 } 1052 1053 bool SBDebugger::GetUseExternalEditor() { 1054 return (m_opaque_sp ? m_opaque_sp->GetUseExternalEditor() : false); 1055 } 1056 1057 bool SBDebugger::SetUseColor(bool value) { 1058 return (m_opaque_sp ? m_opaque_sp->SetUseColor(value) : false); 1059 } 1060 1061 bool SBDebugger::GetUseColor() const { 1062 return (m_opaque_sp ? m_opaque_sp->GetUseColor() : false); 1063 } 1064 1065 bool SBDebugger::GetDescription(SBStream &description) { 1066 Stream &strm = description.ref(); 1067 1068 if (m_opaque_sp) { 1069 const char *name = m_opaque_sp->GetInstanceName().AsCString(); 1070 user_id_t id = m_opaque_sp->GetID(); 1071 strm.Printf("Debugger (instance: \"%s\", id: %" PRIu64 ")", name, id); 1072 } else 1073 strm.PutCString("No value"); 1074 1075 return true; 1076 } 1077 1078 user_id_t SBDebugger::GetID() { 1079 return (m_opaque_sp ? m_opaque_sp->GetID() : LLDB_INVALID_UID); 1080 } 1081 1082 SBError SBDebugger::SetCurrentPlatform(const char *platform_name_cstr) { 1083 SBError sb_error; 1084 if (m_opaque_sp) { 1085 if (platform_name_cstr && platform_name_cstr[0]) { 1086 ConstString platform_name(platform_name_cstr); 1087 PlatformSP platform_sp(Platform::Find(platform_name)); 1088 1089 if (platform_sp) { 1090 // Already have a platform with this name, just select it 1091 m_opaque_sp->GetPlatformList().SetSelectedPlatform(platform_sp); 1092 } else { 1093 // We don't have a platform by this name yet, create one 1094 platform_sp = Platform::Create(platform_name, sb_error.ref()); 1095 if (platform_sp) { 1096 // We created the platform, now append and select it 1097 bool make_selected = true; 1098 m_opaque_sp->GetPlatformList().Append(platform_sp, make_selected); 1099 } 1100 } 1101 } else { 1102 sb_error.ref().SetErrorString("invalid platform name"); 1103 } 1104 } else { 1105 sb_error.ref().SetErrorString("invalid debugger"); 1106 } 1107 return sb_error; 1108 } 1109 1110 bool SBDebugger::SetCurrentPlatformSDKRoot(const char *sysroot) { 1111 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); 1112 if (m_opaque_sp) { 1113 PlatformSP platform_sp( 1114 m_opaque_sp->GetPlatformList().GetSelectedPlatform()); 1115 1116 if (platform_sp) { 1117 if (log && sysroot) 1118 log->Printf("SBDebugger::SetCurrentPlatformSDKRoot (\"%s\")", sysroot); 1119 platform_sp->SetSDKRootDirectory(ConstString(sysroot)); 1120 return true; 1121 } 1122 } 1123 return false; 1124 } 1125 1126 bool SBDebugger::GetCloseInputOnEOF() const { 1127 return (m_opaque_sp ? m_opaque_sp->GetCloseInputOnEOF() : false); 1128 } 1129 1130 void SBDebugger::SetCloseInputOnEOF(bool b) { 1131 if (m_opaque_sp) 1132 m_opaque_sp->SetCloseInputOnEOF(b); 1133 } 1134 1135 SBTypeCategory SBDebugger::GetCategory(const char *category_name) { 1136 if (!category_name || *category_name == 0) 1137 return SBTypeCategory(); 1138 1139 TypeCategoryImplSP category_sp; 1140 1141 if (DataVisualization::Categories::GetCategory(ConstString(category_name), 1142 category_sp, false)) 1143 return SBTypeCategory(category_sp); 1144 else 1145 return SBTypeCategory(); 1146 } 1147 1148 SBTypeCategory SBDebugger::GetCategory(lldb::LanguageType lang_type) { 1149 TypeCategoryImplSP category_sp; 1150 if (DataVisualization::Categories::GetCategory(lang_type, category_sp)) 1151 return SBTypeCategory(category_sp); 1152 else 1153 return SBTypeCategory(); 1154 } 1155 1156 SBTypeCategory SBDebugger::CreateCategory(const char *category_name) { 1157 if (!category_name || *category_name == 0) 1158 return SBTypeCategory(); 1159 1160 TypeCategoryImplSP category_sp; 1161 1162 if (DataVisualization::Categories::GetCategory(ConstString(category_name), 1163 category_sp, true)) 1164 return SBTypeCategory(category_sp); 1165 else 1166 return SBTypeCategory(); 1167 } 1168 1169 bool SBDebugger::DeleteCategory(const char *category_name) { 1170 if (!category_name || *category_name == 0) 1171 return false; 1172 1173 return DataVisualization::Categories::Delete(ConstString(category_name)); 1174 } 1175 1176 uint32_t SBDebugger::GetNumCategories() { 1177 return DataVisualization::Categories::GetCount(); 1178 } 1179 1180 SBTypeCategory SBDebugger::GetCategoryAtIndex(uint32_t index) { 1181 return SBTypeCategory( 1182 DataVisualization::Categories::GetCategoryAtIndex(index)); 1183 } 1184 1185 SBTypeCategory SBDebugger::GetDefaultCategory() { 1186 return GetCategory("default"); 1187 } 1188 1189 SBTypeFormat SBDebugger::GetFormatForType(SBTypeNameSpecifier type_name) { 1190 SBTypeCategory default_category_sb = GetDefaultCategory(); 1191 if (default_category_sb.GetEnabled()) 1192 return default_category_sb.GetFormatForType(type_name); 1193 return SBTypeFormat(); 1194 } 1195 1196 #ifndef LLDB_DISABLE_PYTHON 1197 SBTypeSummary SBDebugger::GetSummaryForType(SBTypeNameSpecifier type_name) { 1198 if (!type_name.IsValid()) 1199 return SBTypeSummary(); 1200 return SBTypeSummary(DataVisualization::GetSummaryForType(type_name.GetSP())); 1201 } 1202 #endif // LLDB_DISABLE_PYTHON 1203 1204 SBTypeFilter SBDebugger::GetFilterForType(SBTypeNameSpecifier type_name) { 1205 if (!type_name.IsValid()) 1206 return SBTypeFilter(); 1207 return SBTypeFilter(DataVisualization::GetFilterForType(type_name.GetSP())); 1208 } 1209 1210 #ifndef LLDB_DISABLE_PYTHON 1211 SBTypeSynthetic SBDebugger::GetSyntheticForType(SBTypeNameSpecifier type_name) { 1212 if (!type_name.IsValid()) 1213 return SBTypeSynthetic(); 1214 return SBTypeSynthetic( 1215 DataVisualization::GetSyntheticForType(type_name.GetSP())); 1216 } 1217 #endif // LLDB_DISABLE_PYTHON 1218 1219 static llvm::ArrayRef<const char *> GetCategoryArray(const char **categories) { 1220 if (categories == nullptr) 1221 return {}; 1222 size_t len = 0; 1223 while (categories[len] != nullptr) 1224 ++len; 1225 return llvm::makeArrayRef(categories, len); 1226 } 1227 1228 bool SBDebugger::EnableLog(const char *channel, const char **categories) { 1229 if (m_opaque_sp) { 1230 uint32_t log_options = 1231 LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; 1232 std::string error; 1233 llvm::raw_string_ostream error_stream(error); 1234 return m_opaque_sp->EnableLog(channel, GetCategoryArray(categories), "", 1235 log_options, error_stream); 1236 } else 1237 return false; 1238 } 1239 1240 void SBDebugger::SetLoggingCallback(lldb::LogOutputCallback log_callback, 1241 void *baton) { 1242 if (m_opaque_sp) { 1243 return m_opaque_sp->SetLoggingCallback(log_callback, baton); 1244 } 1245 } 1246