1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 11830 $
6  * $Id: debuggerdriver.cpp 11830 2019-08-28 22:59:36Z pecanh $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/debuggergdb/debuggerdriver.cpp $
8  */
9 
10 #include <sdk.h>
11 #include "debuggerdriver.h"
12 #include "debuggergdb.h"
13 #include "macrosmanager.h"
14 
15 #include <cbdebugger_interfaces.h>
16 
DebuggerDriver(DebuggerGDB * plugin)17 DebuggerDriver::DebuggerDriver(DebuggerGDB* plugin)
18     : m_pDBG(plugin),
19     m_ProgramIsStopped(true),
20     m_ChildPID(0),
21     m_QueueBusy(false),
22     m_currentFrameNo(0),
23     m_userSelectedFrameNo(-1)
24 {
25     //ctor
26 }
27 
~DebuggerDriver()28 DebuggerDriver::~DebuggerDriver()
29 {
30     //dtor
31     for (size_t ii = 0; ii < m_DCmds.GetCount(); ++ii)
32         delete m_DCmds[ii];
33     m_DCmds.Clear();
34 }
35 
Log(const wxString & msg)36 void DebuggerDriver::Log(const wxString& msg)
37 {
38     m_pDBG->Log(msg);
39 }
40 
DebugLog(const wxString & msg)41 void DebuggerDriver::DebugLog(const wxString& msg)
42 {
43     m_pDBG->DebugLog(msg);
44 }
45 
ClearDirectories()46 void DebuggerDriver::ClearDirectories()
47 {
48     m_Dirs.Clear();
49 }
50 
AddDirectory(const wxString & dir)51 void DebuggerDriver::AddDirectory(const wxString& dir)
52 {
53     if (m_Dirs.Index(dir) == wxNOT_FOUND)
54         m_Dirs.Add(dir);
55 }
56 
SetWorkingDirectory(const wxString & dir)57 void DebuggerDriver::SetWorkingDirectory(const wxString& dir)
58 {
59     m_WorkingDir = dir;
60 }
61 
GetDebuggersWorkingDirectory() const62 wxString DebuggerDriver::GetDebuggersWorkingDirectory() const
63 {
64     if (m_WorkingDir.empty())
65         return wxEmptyString;
66     wxString oldDir = wxGetCwd();
67     wxSetWorkingDirectory(m_WorkingDir);
68     wxString newDir = wxGetCwd();
69     wxSetWorkingDirectory(oldDir);
70     return newDir;
71 }
72 
SetArguments(const wxString & args)73 void DebuggerDriver::SetArguments(const wxString& args)
74 {
75     m_Args = args;
76     Manager::Get()->GetMacrosManager()->ReplaceMacros(m_Args);
77 }
78 
ShowFile(const wxString & file,int line)79 void DebuggerDriver::ShowFile(const wxString& file, int line)
80 {
81     wxCommandEvent event(DEBUGGER_SHOW_FILE_LINE);
82     event.SetString(file);
83     event.SetInt(line);
84     m_pDBG->ProcessEvent(event);
85 }
86 
NotifyCursorChanged()87 void DebuggerDriver::NotifyCursorChanged()
88 {
89     if (!m_Cursor.changed || m_LastCursorAddress == m_Cursor.address)
90         return;
91     m_LastCursorAddress = m_Cursor.address;
92     wxCommandEvent event(DEBUGGER_CURSOR_CHANGED);
93     m_pDBG->ProcessEvent(event);
94 }
95 
NotifyDebuggeeContinued()96 void DebuggerDriver::NotifyDebuggeeContinued()
97 {
98     m_pDBG->DebuggeeContinued();
99     ResetCursor();
100 }
101 
ResetCursor()102 void DebuggerDriver::ResetCursor()
103 {
104     m_LastCursorAddress.Clear();
105     m_Cursor.address.Clear();
106     m_Cursor.file.Clear();
107     m_Cursor.function.Clear();
108     m_Cursor.line = -1;
109     m_Cursor.changed = false;
110 }
111 
QueueCommand(DebuggerCmd * dcmd,QueuePriority prio)112 void DebuggerDriver::QueueCommand(DebuggerCmd* dcmd, QueuePriority prio)
113 {
114 //    DebugLog(_T("Queueing command: ") + dcmd->m_Cmd);
115     if (prio == Low)
116         m_DCmds.Add(dcmd);
117     else
118         m_DCmds.Insert(dcmd, 0);
119     RunQueue();
120 }
121 
CurrentCommand()122 DebuggerCmd* DebuggerDriver::CurrentCommand()
123 {
124     return m_DCmds.GetCount() ? m_DCmds[0] : 0;
125 }
126 
RunQueue()127 void DebuggerDriver::RunQueue()
128 {
129     if (m_QueueBusy || !m_DCmds.GetCount() || !IsProgramStopped())
130         return;
131 
132     DebuggerCmd *command = CurrentCommand();
133 
134 //    Log(_T("Running command: ") + CurrentCommand()->m_Cmd);
135     // don't send a command if empty; most debuggers repeat the last command this way...
136     if (!command->m_Cmd.IsEmpty())
137     {
138         m_QueueBusy = true;
139         m_pDBG->DoSendCommand(command->m_Cmd);
140         if (command->IsContinueCommand())
141             m_ProgramIsStopped = false;
142     }
143 
144     // Call Action()
145     command->Action();
146 
147     // If the command was an action (i.e. no command specified,
148     // remove it from the queue and run the next command.
149     // For other commands, this happens in driver's ParseOutput().
150     if (command->m_Cmd.IsEmpty())
151     {
152         RemoveTopCommand(true);
153         RunQueue();
154     }
155 }
156 
RemoveTopCommand(bool deleteIt)157 void DebuggerDriver::RemoveTopCommand(bool deleteIt)
158 {
159     if (m_QueueBusy || !m_DCmds.GetCount())
160         return;
161 
162 //    Log(_T("Removing command: ") + CurrentCommand()->m_Cmd);
163     if (deleteIt)
164         delete m_DCmds[0];
165     m_DCmds.RemoveAt(0);
166 }
167 
GetStackFrames() const168 DebuggerDriver::StackFrameContainer const & DebuggerDriver::GetStackFrames() const
169 {
170     return m_backtrace;
171 }
172 
GetStackFrames()173 DebuggerDriver::StackFrameContainer& DebuggerDriver::GetStackFrames()
174 {
175     return m_backtrace;
176 }
177 
GetThreads() const178 const DebuggerDriver::ThreadsContainer & DebuggerDriver::GetThreads() const
179 {
180     return m_threads;
181 }
182 
GetThreads()183 DebuggerDriver::ThreadsContainer & DebuggerDriver::GetThreads()
184 {
185     return m_threads;
186 }
187 
SetCurrentFrame(int number,bool user_selected)188 void DebuggerDriver::SetCurrentFrame(int number, bool user_selected)
189 {
190     m_currentFrameNo = number;
191     if (user_selected)
192         m_userSelectedFrameNo = number;
193 }
194 
ResetCurrentFrame()195 void DebuggerDriver::ResetCurrentFrame()
196 {
197     m_currentFrameNo = 0;
198     m_userSelectedFrameNo = -1;
199 
200     if (Manager::Get()->GetDebuggerManager()->UpdateBacktrace())
201         Manager::Get()->GetDebuggerManager()->GetBacktraceDialog()->Reload();
202 }
203 
204