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