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