diff options
author | Greg Clayton <gclayton@apple.com> | 2010-06-23 01:19:29 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2010-06-23 01:19:29 +0000 |
commit | 6611103cfe7a8c08554816fc08abef2e2960e799 (patch) | |
tree | b940bb129b59af3cf6923f8d69f095d2d9fc8dca /lldb/source/Core/Debugger.cpp | |
parent | ef5a4383ad679e58743c540c25d6a1bab0c77423 (diff) | |
download | bcm5719-llvm-6611103cfe7a8c08554816fc08abef2e2960e799.tar.gz bcm5719-llvm-6611103cfe7a8c08554816fc08abef2e2960e799.zip |
Very large changes that were needed in order to allow multiple connections
to the debugger from GUI windows. Previously there was one global debugger
instance that could be accessed that had its own command interpreter and
current state (current target/process/thread/frame). When a GUI debugger
was attached, if it opened more than one window that each had a console
window, there were issues where the last one to setup the global debugger
object won and got control of the debugger.
To avoid this we now create instances of the lldb_private::Debugger that each
has its own state:
- target list for targets the debugger instance owns
- current process/thread/frame
- its own command interpreter
- its own input, output and error file handles to avoid conflicts
- its own input reader stack
So now clients should call:
SBDebugger::Initialize(); // (static function)
SBDebugger debugger (SBDebugger::Create());
// Use which ever file handles you wish
debugger.SetErrorFileHandle (stderr, false);
debugger.SetOutputFileHandle (stdout, false);
debugger.SetInputFileHandle (stdin, true);
// main loop
SBDebugger::Terminate(); // (static function)
SBDebugger::Initialize() and SBDebugger::Terminate() are ref counted to
ensure nothing gets destroyed too early when multiple clients might be
attached.
Cleaned up the command interpreter and the CommandObject and all subclasses
to take more appropriate arguments.
llvm-svn: 106615
Diffstat (limited to 'lldb/source/Core/Debugger.cpp')
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 189 |
1 files changed, 124 insertions, 65 deletions
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index c106d838fed..0b7676ca732 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -13,7 +13,7 @@ #include "lldb/Core/InputReader.h" #include "lldb/Core/State.h" #include "lldb/Core/Timer.h" - +#include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -22,115 +22,137 @@ using namespace lldb; using namespace lldb_private; -int Debugger::g_shared_debugger_refcount = 0; -bool Debugger::g_in_terminate = false; - -Debugger::DebuggerSP & -Debugger::GetDebuggerSP () -{ - static DebuggerSP g_shared_debugger_sp; - return g_shared_debugger_sp; -} +static uint32_t g_shared_debugger_refcount = 0; void Debugger::Initialize () { - g_shared_debugger_refcount++; - if (GetDebuggerSP().get() == NULL) - { - GetDebuggerSP().reset (new Debugger()); + if (g_shared_debugger_refcount == 0) lldb_private::Initialize(); - GetDebuggerSP()->GetCommandInterpreter().Initialize(); - } + g_shared_debugger_refcount++; } void Debugger::Terminate () { - g_shared_debugger_refcount--; - if (g_shared_debugger_refcount == 0) + if (g_shared_debugger_refcount > 0) { - // Because Terminate is called also in the destructor, we need to make sure - // that none of the calls to GetSharedInstance leads to a call to Initialize, - // thus bumping the refcount back to 1 & causing Debugger::~Debugger to try to - // re-terminate. So we use g_in_terminate to indicate this condition. - // When we can require at least Initialize to be called, we won't have to do - // this since then the GetSharedInstance won't have to auto-call Initialize... - - g_in_terminate = true; - int num_targets = GetDebuggerSP()->GetTargetList().GetNumTargets(); - for (int i = 0; i < num_targets; i++) + g_shared_debugger_refcount--; + if (g_shared_debugger_refcount == 0) { - ProcessSP process_sp(GetDebuggerSP()->GetTargetList().GetTargetAtIndex (i)->GetProcessSP()); - if (process_sp) - process_sp->Destroy(); + lldb_private::WillTerminate(); + lldb_private::Terminate(); } - GetDebuggerSP()->DisconnectInput(); - lldb_private::WillTerminate(); - GetDebuggerSP().reset(); } } -Debugger & -Debugger::GetSharedInstance() +typedef std::vector<DebuggerSP> DebuggerList; + +static Mutex & +GetDebuggerListMutex () +{ + static Mutex g_mutex(Mutex::eMutexTypeRecursive); + return g_mutex; +} + +static DebuggerList & +GetDebuggerList() +{ + // hide the static debugger list inside a singleton accessor to avoid + // global init contructors + static DebuggerList g_list; + return g_list; +} + + +DebuggerSP +Debugger::CreateInstance () +{ + DebuggerSP debugger_sp (new Debugger); + // Scope for locker + { + Mutex::Locker locker (GetDebuggerListMutex ()); + GetDebuggerList().push_back(debugger_sp); + } + return debugger_sp; +} + +lldb::DebuggerSP +Debugger::GetSP () { - // Don't worry about thread race conditions with the code below as - // lldb_private::Initialize(); does this in a thread safe way. I just - // want to avoid having to lock and unlock a mutex in - // lldb_private::Initialize(); every time we want to access the - // Debugger shared instance. + lldb::DebuggerSP debugger_sp; - // FIXME: We intend to require clients to call Initialize by hand (since they - // will also have to call Terminate by hand.) But for now it is not clear where - // we can reliably call these in JH. So the present version initializes on first use - // here, and terminates in the destructor. - if (g_shared_debugger_refcount == 0 && !g_in_terminate) - Initialize(); - - assert(GetDebuggerSP().get()!= NULL); - return *(GetDebuggerSP().get()); + Mutex::Locker locker (GetDebuggerListMutex ()); + DebuggerList &debugger_list = GetDebuggerList(); + DebuggerList::iterator pos, end = debugger_list.end(); + for (pos = debugger_list.begin(); pos != end; ++pos) + { + if ((*pos).get() == this) + { + debugger_sp = *pos; + break; + } + } + return debugger_sp; } + +TargetSP +Debugger::FindTargetWithProcessID (lldb::pid_t pid) +{ + lldb::TargetSP target_sp; + Mutex::Locker locker (GetDebuggerListMutex ()); + DebuggerList &debugger_list = GetDebuggerList(); + DebuggerList::iterator pos, end = debugger_list.end(); + for (pos = debugger_list.begin(); pos != end; ++pos) + { + target_sp = (*pos)->GetTargetList().FindTargetWithProcessID (pid); + if (target_sp) + break; + } + return target_sp; +} + + Debugger::Debugger () : m_input_comm("debugger.input"), m_input_file (), m_output_file (), m_error_file (), - m_async_execution (true), m_target_list (), m_listener ("lldb.Debugger"), m_source_manager (), - m_command_interpreter (eScriptLanguageDefault, false, &m_listener, m_source_manager), + m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)), + m_exe_ctx (), m_input_readers (), m_input_reader_data () { + m_command_interpreter_ap->Initialize (); } Debugger::~Debugger () { - // FIXME: - // Remove this once this version of lldb has made its way through a build. - Terminate(); + int num_targets = m_target_list.GetNumTargets(); + for (int i = 0; i < num_targets; i++) + { + ProcessSP process_sp (m_target_list.GetTargetAtIndex (i)->GetProcessSP()); + if (process_sp) + process_sp->Destroy(); + } + DisconnectInput(); } bool Debugger::GetAsyncExecution () { - return m_async_execution; + return !m_command_interpreter_ap->GetSynchronous(); } void Debugger::SetAsyncExecution (bool async_execution) { - static bool value_has_been_set = false; - - if (!value_has_been_set) - { - value_has_been_set = true; - m_async_execution = async_execution; - m_command_interpreter.SetSynchronous (!async_execution); - } + m_command_interpreter_ap->SetSynchronous (!async_execution); } void @@ -203,7 +225,8 @@ Debugger::GetErrorFileHandle () CommandInterpreter & Debugger::GetCommandInterpreter () { - return m_command_interpreter; + assert (m_command_interpreter_ap.get()); + return *m_command_interpreter_ap; } Listener & @@ -432,3 +455,39 @@ Debugger::ActivateInputReader (const InputReaderSP &reader_sp) } } } + +void +Debugger::UpdateExecutionContext (ExecutionContext *override_context) +{ + m_exe_ctx.Clear(); + + if (override_context != NULL) + { + m_exe_ctx.target = override_context->target; + m_exe_ctx.process = override_context->process; + m_exe_ctx.thread = override_context->thread; + m_exe_ctx.frame = override_context->frame; + } + else + { + TargetSP target_sp (GetCurrentTarget()); + if (target_sp) + { + m_exe_ctx.target = target_sp.get(); + m_exe_ctx.process = target_sp->GetProcessSP().get(); + if (m_exe_ctx.process && m_exe_ctx.process->IsRunning() == false) + { + m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetCurrentThread().get(); + if (m_exe_ctx.thread == NULL) + m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); + if (m_exe_ctx.thread) + { + m_exe_ctx.frame = m_exe_ctx.thread->GetCurrentFrame().get(); + if (m_exe_ctx.frame == NULL) + m_exe_ctx.frame = m_exe_ctx.thread->GetStackFrameAtIndex (0).get(); + } + } + } + } +} + |