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: 11877 $
6  * $Id: debuggergdb.cpp 11877 2019-10-16 07:24:24Z fuscated $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/debuggergdb/debuggergdb.cpp $
8  */
9 
10 #include <sdk.h>
11 #include <algorithm> // std::remove_if
12 
13 #ifndef CB_PRECOMP
14     #include <wx/app.h>
15     #include <wx/txtstrm.h>
16     #include <wx/regex.h>
17     #include <wx/msgdlg.h>
18     #include <wx/frame.h> // GetMenuBar
19     #include <wx/menu.h>
20     #include <wx/filedlg.h>
21 
22     #include "cbproject.h"
23     #include "manager.h"
24     #include "configmanager.h"
25     #include "logmanager.h" // for F
26     #include "projectmanager.h"
27     #include "pluginmanager.h"
28     #include "editormanager.h"
29     #include "macrosmanager.h"
30     #include "cbeditor.h"
31     #include "projectbuildtarget.h"
32     #include "sdk_events.h"
33     #include "compilerfactory.h"
34     #include "xtra_res.h"
35 
36     #include "scrollingdialog.h"
37     #include "globals.h"
38 #endif
39 
40 #include <wx/tokenzr.h>
41 #include "editarraystringdlg.h"
42 #include "annoyingdialog.h"
43 #include "cbstyledtextctrl.h"
44 #include "compilercommandgenerator.h"
45 
46 #include <cbdebugger_interfaces.h>
47 #include "editbreakpointdlg.h"
48 
49 #include "databreakpointdlg.h"
50 #include "debuggerdriver.h"
51 #include "debuggergdb.h"
52 #include "debuggeroptionsdlg.h"
53 #include "debuggeroptionsprjdlg.h"
54 #include "editwatchdlg.h"
55 
56 // function pointer to DebugBreakProcess under windows (XP+)
57 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
58 #include "Tlhelp32.h"
59 typedef BOOL WINAPI   (*DebugBreakProcessApiCall)       (HANDLE);
60 typedef HANDLE WINAPI (*CreateToolhelp32SnapshotApiCall)(DWORD  dwFlags,   DWORD             th32ProcessID);
61 typedef BOOL WINAPI   (*Process32FirstApiCall)          (HANDLE hSnapshot, LPPROCESSENTRY32W lppe);
62 typedef BOOL WINAPI   (*Process32NextApiCall)           (HANDLE hSnapshot, LPPROCESSENTRY32W lppe);
63 
64 DebugBreakProcessApiCall        DebugBreakProcessFunc = 0;
65 CreateToolhelp32SnapshotApiCall CreateToolhelp32SnapshotFunc = 0;
66 Process32FirstApiCall           Process32FirstFunc = 0;
67 Process32NextApiCall            Process32NextFunc = 0;
68 
69 HINSTANCE kernelLib = 0;
70 
71 #endif
72 
73 #ifdef __WXMSW__
74 // disable the CTRL_C event
HandlerRoutine(cb_unused DWORD dwCtrlType)75 inline BOOL WINAPI HandlerRoutine(cb_unused DWORD dwCtrlType)
76 {
77     return TRUE;
78 }
79 #endif
80 
81 // valid debugger command constants
82 enum DebugCommandConst
83 {
84     CMD_CONTINUE,
85     CMD_STEP,
86     CMD_STEPIN,
87     CMD_STEPOUT,
88     CMD_STEP_INSTR,
89     CMD_STEP_INTO_INSTR,
90     CMD_STOP,
91     CMD_BACKTRACE,
92     CMD_DISASSEMBLE,
93     CMD_REGISTERS,
94     CMD_MEMORYDUMP,
95     CMD_RUNNINGTHREADS
96 };
97 
98 const wxString g_EscapeChar = wxChar(26);
99 
100 namespace
101 {
102 long idMenuInfoFrame = wxNewId();
103 long idMenuInfoDLL = wxNewId();
104 long idMenuInfoFiles = wxNewId();
105 long idMenuInfoFPU = wxNewId();
106 long idMenuInfoSignals = wxNewId();
107 
108 long idMenuInfoPrintElementsUnlimited = wxNewId();
109 long idMenuInfoPrintElements20 = wxNewId();
110 long idMenuInfoPrintElements50 = wxNewId();
111 long idMenuInfoPrintElements100 = wxNewId();
112 long idMenuInfoPrintElements200 = wxNewId();
113 
114 long idMenuInfoCatchThrow = wxNewId();
115 
116 long idGDBProcess = wxNewId();
117 long idTimerPollDebugger = wxNewId();
118 
119 long idMenuWatchDereference = wxNewId();
120 
121 // this auto-registers the plugin
122 PluginRegistrant<DebuggerGDB> reg(_T("Debugger"));
123 }
124 
BEGIN_EVENT_TABLE(DebuggerGDB,cbDebuggerPlugin)125 BEGIN_EVENT_TABLE(DebuggerGDB, cbDebuggerPlugin)
126     EVT_MENU(idMenuInfoFrame, DebuggerGDB::OnInfoFrame)
127     EVT_MENU(idMenuInfoDLL, DebuggerGDB::OnInfoDLL)
128     EVT_MENU(idMenuInfoFiles, DebuggerGDB::OnInfoFiles)
129     EVT_MENU(idMenuInfoFPU, DebuggerGDB::OnInfoFPU)
130     EVT_MENU(idMenuInfoSignals, DebuggerGDB::OnInfoSignals)
131 
132     EVT_MENU(idMenuWatchDereference, DebuggerGDB::OnMenuWatchDereference)
133 
134     EVT_PIPEDPROCESS_STDOUT(idGDBProcess, DebuggerGDB::OnGDBOutput)
135     EVT_PIPEDPROCESS_STDERR(idGDBProcess, DebuggerGDB::OnGDBError)
136     EVT_PIPEDPROCESS_TERMINATED(idGDBProcess, DebuggerGDB::OnGDBTerminated)
137 
138     EVT_IDLE(DebuggerGDB::OnIdle)
139     EVT_TIMER(idTimerPollDebugger, DebuggerGDB::OnTimer)
140 
141     EVT_COMMAND(-1, DEBUGGER_CURSOR_CHANGED, DebuggerGDB::OnCursorChanged)
142     EVT_COMMAND(-1, DEBUGGER_SHOW_FILE_LINE, DebuggerGDB::OnShowFile)
143 
144     EVT_UPDATE_UI(idMenuInfoPrintElementsUnlimited, DebuggerGDB::OnUpdateTools)
145     EVT_UPDATE_UI(idMenuInfoPrintElements20, DebuggerGDB::OnUpdateTools)
146     EVT_UPDATE_UI(idMenuInfoPrintElements50, DebuggerGDB::OnUpdateTools)
147     EVT_UPDATE_UI(idMenuInfoPrintElements100, DebuggerGDB::OnUpdateTools)
148     EVT_UPDATE_UI(idMenuInfoPrintElements200, DebuggerGDB::OnUpdateTools)
149 
150     EVT_MENU(idMenuInfoPrintElementsUnlimited, DebuggerGDB::OnPrintElements)
151     EVT_MENU(idMenuInfoPrintElements20, DebuggerGDB::OnPrintElements)
152     EVT_MENU(idMenuInfoPrintElements50, DebuggerGDB::OnPrintElements)
153     EVT_MENU(idMenuInfoPrintElements100, DebuggerGDB::OnPrintElements)
154     EVT_MENU(idMenuInfoPrintElements200, DebuggerGDB::OnPrintElements)
155 
156     EVT_UPDATE_UI(idMenuInfoCatchThrow, DebuggerGDB::OnUpdateCatchThrow)
157     EVT_MENU(idMenuInfoCatchThrow, DebuggerGDB::OnCatchThrow)
158 END_EVENT_TABLE()
159 
160 DebuggerGDB::DebuggerGDB() :
161     cbDebuggerPlugin(wxT("GDB/CDB debugger"), wxT("gdb_debugger")),
162     m_State(this),
163     m_pProcess(0L),
164     m_LastExitCode(0),
165     m_Pid(0),
166     m_PidToAttach(0),
167     m_NoDebugInfo(false),
168     m_StoppedOnSignal(false),
169     m_pProject(0),
170     m_bIsConsole(false),
171     m_stopDebuggerConsoleClosed(false),
172     m_nConsolePid(0),
173     m_TemporaryBreak(false),
174     m_printElements(200)
175 {
176     if (!Manager::LoadResource(_T("debugger.zip")))
177     {
178         NotifyMissingFile(_T("debugger.zip"));
179     }
180 
181     // get a function pointer to DebugBreakProcess under windows (XP+)
182     #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
183     kernelLib = LoadLibrary(TEXT("kernel32.dll"));
184     if (kernelLib)
185     {
186         DebugBreakProcessFunc = (DebugBreakProcessApiCall)GetProcAddress(kernelLib, "DebugBreakProcess");
187         //Windows XP
188         CreateToolhelp32SnapshotFunc = (CreateToolhelp32SnapshotApiCall)GetProcAddress(kernelLib, "CreateToolhelp32Snapshot");
189         Process32FirstFunc = (Process32FirstApiCall)GetProcAddress(kernelLib, "Process32First");
190         Process32NextFunc = (Process32NextApiCall)GetProcAddress(kernelLib, "Process32Next");
191     }
192     #endif
193 }
194 
~DebuggerGDB()195 DebuggerGDB::~DebuggerGDB()
196 {
197     #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
198     if (kernelLib)
199         FreeLibrary(kernelLib);
200     #endif
201 }
202 
OnAttachReal()203 void DebuggerGDB::OnAttachReal()
204 {
205     m_TimerPollDebugger.SetOwner(this, idTimerPollDebugger);
206 
207     // register event sink
208     Manager::Get()->RegisterEventSink(cbEVT_BUILDTARGET_SELECTED, new cbEventFunctor<DebuggerGDB, CodeBlocksEvent>(this, &DebuggerGDB::OnBuildTargetSelected));
209 }
210 
OnReleaseReal(cb_unused bool appShutDown)211 void DebuggerGDB::OnReleaseReal(cb_unused bool appShutDown)
212 {
213     //Close debug session when appShutDown
214     if (m_State.HasDriver())
215     {
216         Stop();
217         wxYieldIfNeeded();
218     }
219 
220     m_State.CleanUp();
221     KillConsole();
222 }
223 
SupportsFeature(cbDebuggerFeature::Flags flag)224 bool DebuggerGDB::SupportsFeature(cbDebuggerFeature::Flags flag)
225 {
226     DebuggerConfiguration &config = GetActiveConfigEx();
227 
228     if (config.IsGDB())
229     {
230         switch (flag)
231         {
232         case cbDebuggerFeature::Breakpoints:
233         case cbDebuggerFeature::Callstack:
234         case cbDebuggerFeature::CPURegisters:
235         case cbDebuggerFeature::Disassembly:
236         case cbDebuggerFeature::Watches:
237         case cbDebuggerFeature::ValueTooltips:
238         case cbDebuggerFeature::ExamineMemory:
239         case cbDebuggerFeature::Threads:
240         case cbDebuggerFeature::RunToCursor:
241         case cbDebuggerFeature::SetNextStatement:
242             return true;
243         default:
244             return false;
245         }
246     }
247     else
248     {
249         switch (flag)
250         {
251         case cbDebuggerFeature::Breakpoints:
252         case cbDebuggerFeature::Callstack:
253         case cbDebuggerFeature::CPURegisters:
254         case cbDebuggerFeature::Disassembly:
255         case cbDebuggerFeature::Watches:
256         case cbDebuggerFeature::ValueTooltips:
257             return true;
258         case cbDebuggerFeature::ExamineMemory:
259         case cbDebuggerFeature::Threads:
260         case cbDebuggerFeature::RunToCursor:
261         case cbDebuggerFeature::SetNextStatement:
262         default:
263             return false;
264         }
265     }
266 
267     return false;
268 }
269 
LoadConfig(const ConfigManagerWrapper & config)270 cbDebuggerConfiguration* DebuggerGDB::LoadConfig(const ConfigManagerWrapper &config)
271 {
272     return new DebuggerConfiguration(config);
273 }
274 
GetActiveConfigEx()275 DebuggerConfiguration& DebuggerGDB::GetActiveConfigEx()
276 {
277     return static_cast<DebuggerConfiguration&>(GetActiveConfig());
278 }
279 
GetProjectConfigurationPanel(wxWindow * parent,cbProject * project)280 cbConfigurationPanel* DebuggerGDB::GetProjectConfigurationPanel(wxWindow* parent, cbProject* project)
281 {
282     DebuggerOptionsProjectDlg* dlg = new DebuggerOptionsProjectDlg(parent, this, project);
283     return dlg;
284 }
285 
OnConfigurationChange(cb_unused bool isActive)286 void DebuggerGDB::OnConfigurationChange(cb_unused bool isActive)
287 {
288     DebuggerConfiguration &config = GetActiveConfigEx();
289     bool locals = config.GetFlag(DebuggerConfiguration::WatchLocals);
290     bool funcArgs = config.GetFlag(DebuggerConfiguration::WatchFuncArgs);
291 
292     cbWatchesDlg *watchesDialog = Manager::Get()->GetDebuggerManager()->GetWatchesDialog();
293     bool update = false;
294 
295     if (!locals)
296     {
297         if (m_localsWatch)
298         {
299             watchesDialog->RemoveWatch(m_localsWatch);
300             m_localsWatch = cb::shared_ptr<GDBWatch>();
301         }
302     }
303     else if (!m_localsWatch)
304         update = true;
305 
306     if (!funcArgs)
307     {
308         if (m_funcArgsWatch)
309         {
310             watchesDialog->RemoveWatch(m_funcArgsWatch);
311             m_funcArgsWatch = cb::shared_ptr<GDBWatch>();
312         }
313     }
314     else if (!m_funcArgsWatch)
315         update = true;
316 
317     if (update)
318         RequestUpdate(cbDebuggerPlugin::Watches);
319 }
320 
ParseSearchDirs(const cbProject & project)321 wxArrayString DebuggerGDB::ParseSearchDirs(const cbProject &project)
322 {
323     wxArrayString dirs;
324     const TiXmlElement* elem = static_cast<const TiXmlElement*>(project.GetExtensionsNode());
325     if (elem)
326     {
327         const TiXmlElement* conf = elem->FirstChildElement("debugger");
328         if (conf)
329         {
330             const TiXmlElement* pathsElem = conf->FirstChildElement("search_path");
331             while (pathsElem)
332             {
333                 if (pathsElem->Attribute("add"))
334                 {
335                     const wxString &dir = cbC2U(pathsElem->Attribute("add"));
336                     if (dirs.Index(dir) == wxNOT_FOUND)
337                         dirs.Add(dir);
338                 }
339                 pathsElem = pathsElem->NextSiblingElement("search_path");
340             }
341         }
342     }
343 
344     return dirs;
345 }
346 
GetElementForSaving(cbProject & project,const char * elementsToClear)347 TiXmlElement* GetElementForSaving(cbProject &project, const char *elementsToClear)
348 {
349     TiXmlElement *elem = static_cast<TiXmlElement*>(project.GetExtensionsNode());
350 
351     // since rev4332, the project keeps a copy of the <Extensions> element
352     // and re-uses it when saving the project (so to avoid losing entries in it
353     // if plugins that use that element are not loaded atm).
354     // so, instead of blindly inserting the element, we must first check it's
355     // not already there (and if it is, clear its contents)
356     TiXmlElement* node = elem->FirstChildElement("debugger");
357     if (!node)
358         node = elem->InsertEndChild(TiXmlElement("debugger"))->ToElement();
359 
360     for (TiXmlElement* child = node->FirstChildElement(elementsToClear);
361          child;
362          child = node->FirstChildElement(elementsToClear))
363     {
364         node->RemoveChild(child);
365     }
366     return node;
367 }
368 
SetSearchDirs(cbProject & project,const wxArrayString & dirs)369 void DebuggerGDB::SetSearchDirs(cbProject &project, const wxArrayString &dirs)
370 {
371     TiXmlElement* node = GetElementForSaving(project, "search_path");
372     if (dirs.GetCount() > 0)
373     {
374         for (size_t i = 0; i < dirs.GetCount(); ++i)
375         {
376             TiXmlElement* path = node->InsertEndChild(TiXmlElement("search_path"))->ToElement();
377             path->SetAttribute("add", cbU2C(dirs[i]));
378         }
379     }
380 }
381 
ParseRemoteDebuggingMap(cbProject & project)382 RemoteDebuggingMap DebuggerGDB::ParseRemoteDebuggingMap(cbProject &project)
383 {
384     RemoteDebuggingMap map;
385     const TiXmlElement* elem = static_cast<const TiXmlElement*>(project.GetExtensionsNode());
386     if (elem)
387     {
388         const TiXmlElement* conf = elem->FirstChildElement("debugger");
389         if (conf)
390         {
391             const TiXmlElement* rdElem = conf->FirstChildElement("remote_debugging");
392             while (rdElem)
393             {
394                 wxString targetName = cbC2U(rdElem->Attribute("target"));
395                 ProjectBuildTarget* bt = project.GetBuildTarget(targetName);
396 
397                 const TiXmlElement* rdOpt = rdElem->FirstChildElement("options");
398                 if (rdOpt)
399                 {
400                     RemoteDebugging rd;
401 
402                     if (rdOpt->Attribute("conn_type"))
403                         rd.connType = (RemoteDebugging::ConnectionType)atol(rdOpt->Attribute("conn_type"));
404                     if (rdOpt->Attribute("serial_port"))
405                         rd.serialPort = cbC2U(rdOpt->Attribute("serial_port"));
406 
407                     if (rdOpt->Attribute("serial_baud"))
408                         rd.serialBaud = cbC2U(rdOpt->Attribute("serial_baud"));
409                     if (rd.serialBaud.empty())
410                         rd.serialBaud = wxT("115200");
411 
412                     if (rdOpt->Attribute("ip_address"))
413                         rd.ip = cbC2U(rdOpt->Attribute("ip_address"));
414                     if (rdOpt->Attribute("ip_port"))
415                         rd.ipPort = cbC2U(rdOpt->Attribute("ip_port"));
416                     if (rdOpt->Attribute("additional_cmds"))
417                         rd.additionalCmds = cbC2U(rdOpt->Attribute("additional_cmds"));
418                     if (rdOpt->Attribute("additional_cmds_before"))
419                         rd.additionalCmdsBefore = cbC2U(rdOpt->Attribute("additional_cmds_before"));
420                     if (rdOpt->Attribute("skip_ld_path"))
421                         rd.skipLDpath = cbC2U(rdOpt->Attribute("skip_ld_path")) != _T("0");
422                     if (rdOpt->Attribute("extended_remote"))
423                         rd.extendedRemote = cbC2U(rdOpt->Attribute("extended_remote")) != _T("0");
424                     if (rdOpt->Attribute("additional_shell_cmds_after"))
425                         rd.additionalShellCmdsAfter = cbC2U(rdOpt->Attribute("additional_shell_cmds_after"));
426                     if (rdOpt->Attribute("additional_shell_cmds_before"))
427                         rd.additionalShellCmdsBefore = cbC2U(rdOpt->Attribute("additional_shell_cmds_before"));
428 
429                     map.insert(map.end(), std::make_pair(bt, rd));
430                 }
431 
432                 rdElem = rdElem->NextSiblingElement("remote_debugging");
433             }
434         }
435     }
436     return map;
437 }
438 
SetRemoteDebuggingMap(cbProject & project,const RemoteDebuggingMap & rdMap)439 void DebuggerGDB::SetRemoteDebuggingMap(cbProject &project, const RemoteDebuggingMap &rdMap)
440 {
441     TiXmlElement* node = GetElementForSaving(project, "remote_debugging");
442 
443     if (!rdMap.empty())
444     {
445         typedef std::map<wxString, const RemoteDebugging*> MapTargetNameToRD;
446         MapTargetNameToRD mapTargetNameToRD;
447 
448         for (RemoteDebuggingMap::const_iterator it = rdMap.begin(); it != rdMap.end(); ++it)
449         {
450             wxString targetName = (it->first ? it->first->GetTitle() : wxString());
451             const RemoteDebugging& rd = it->second;
452             mapTargetNameToRD.emplace(targetName, &rd);
453         }
454 
455         for (MapTargetNameToRD::const_iterator it = mapTargetNameToRD.begin();
456              it != mapTargetNameToRD.end();
457              ++it)
458         {
459             const RemoteDebugging& rd = *it->second;
460 
461             // if no different than defaults, skip it
462             if (rd.serialPort.IsEmpty() && rd.serialBaud == wxT("115200")
463                 && rd.ip.IsEmpty() && rd.ipPort.IsEmpty()
464                 && !rd.skipLDpath && !rd.extendedRemote
465                 && rd.additionalCmds.IsEmpty() && rd.additionalCmdsBefore.IsEmpty()
466                 && rd.additionalShellCmdsAfter.IsEmpty()
467                 && rd.additionalShellCmdsBefore.IsEmpty())
468             {
469                 continue;
470             }
471 
472             TiXmlElement* rdnode = node->InsertEndChild(TiXmlElement("remote_debugging"))->ToElement();
473             if (!it->first.empty())
474                 rdnode->SetAttribute("target", cbU2C(it->first));
475 
476             TiXmlElement* tgtnode = rdnode->InsertEndChild(TiXmlElement("options"))->ToElement();
477             tgtnode->SetAttribute("conn_type", (int)rd.connType);
478             if (!rd.serialPort.IsEmpty())
479                 tgtnode->SetAttribute("serial_port", cbU2C(rd.serialPort));
480             if (rd.serialBaud != wxT("115200"))
481                 tgtnode->SetAttribute("serial_baud", cbU2C(rd.serialBaud));
482             if (!rd.ip.IsEmpty())
483                 tgtnode->SetAttribute("ip_address", cbU2C(rd.ip));
484             if (!rd.ipPort.IsEmpty())
485                 tgtnode->SetAttribute("ip_port", cbU2C(rd.ipPort));
486             if (!rd.additionalCmds.IsEmpty())
487                 tgtnode->SetAttribute("additional_cmds", cbU2C(rd.additionalCmds));
488             if (!rd.additionalCmdsBefore.IsEmpty())
489                 tgtnode->SetAttribute("additional_cmds_before", cbU2C(rd.additionalCmdsBefore));
490             if (rd.skipLDpath)
491                 tgtnode->SetAttribute("skip_ld_path", "1");
492             if (rd.extendedRemote)
493                 tgtnode->SetAttribute("extended_remote", "1");
494             if (!rd.additionalShellCmdsAfter.IsEmpty())
495                 tgtnode->SetAttribute("additional_shell_cmds_after", cbU2C(rd.additionalShellCmdsAfter));
496             if (!rd.additionalShellCmdsBefore.IsEmpty())
497                 tgtnode->SetAttribute("additional_shell_cmds_before", cbU2C(rd.additionalShellCmdsBefore));
498         }
499     }
500 }
501 
DoWatches()502 void DebuggerGDB::DoWatches()
503 {
504     if (!m_pProcess)
505         return;
506 
507     DebuggerConfiguration &config = GetActiveConfigEx();
508 
509     bool locals = config.GetFlag(DebuggerConfiguration::WatchLocals);
510     bool funcArgs = config.GetFlag(DebuggerConfiguration::WatchFuncArgs);
511 
512     if (locals)
513     {
514         if (m_localsWatch == nullptr)
515         {
516             m_localsWatch = cb::shared_ptr<GDBWatch>(new GDBWatch(wxT("Locals")));
517             m_localsWatch->Expand(true);
518             m_localsWatch->MarkAsChanged(false);
519             cbWatchesDlg *watchesDialog = Manager::Get()->GetDebuggerManager()->GetWatchesDialog();
520             watchesDialog->AddSpecialWatch(m_localsWatch, true);
521         }
522     }
523 
524     if (funcArgs)
525     {
526         if (m_funcArgsWatch == nullptr)
527         {
528             m_funcArgsWatch = cb::shared_ptr<GDBWatch>(new GDBWatch(wxT("Function arguments")));
529             m_funcArgsWatch->Expand(true);
530             m_funcArgsWatch->MarkAsChanged(false);
531             cbWatchesDlg *watchesDialog = Manager::Get()->GetDebuggerManager()->GetWatchesDialog();
532             watchesDialog->AddSpecialWatch(m_funcArgsWatch, true);
533         }
534     }
535 
536     m_State.GetDriver()->UpdateWatches(m_localsWatch, m_funcArgsWatch, m_watches, false);
537 }
538 
GetShellString()539 static wxString GetShellString()
540 {
541     if (platform::windows)
542         return wxEmptyString;
543     wxString shell = Manager::Get()->GetConfigManager(_T("app"))->Read(_T("/console_shell"),
544                                                                        DEFAULT_CONSOLE_SHELL);
545     // GDB expects the SHELL variable's value to be a path to the shell's executable, so we need to
546     // remove all parameters and do some trimming.
547     shell.Trim(false);
548     wxString::size_type pos = shell.find(wxT(' '));
549     if (pos != wxString::npos)
550         shell.erase(pos);
551     shell.Trim();
552     return shell;
553 }
554 
LaunchProcessWithShell(const wxString & cmd,wxProcess * process,const wxString & cwd)555 int DebuggerGDB::LaunchProcessWithShell(const wxString &cmd, wxProcess *process,
556                                         const wxString &cwd)
557 {
558     wxString shell = GetShellString();
559 #if wxCHECK_VERSION(3, 0, 0)
560     wxExecuteEnv execEnv;
561     execEnv.cwd = cwd;
562     // Read the current environment variables and then make changes to them.
563     wxGetEnvMap(&execEnv.env);
564     if (!shell.empty())
565     {
566         Log(wxString::Format(wxT("Setting SHELL to '%s'"), shell.wx_str()));
567         execEnv.env["SHELL"] = shell;
568     }
569     return wxExecute(cmd, wxEXEC_ASYNC, process, &execEnv);
570 #else
571     if (!shell.empty())
572     {
573         Log(wxString::Format(wxT("Setting SHELL to '%s'"), shell.wx_str()));
574         wxSetEnv(wxT("SHELL"), shell);
575     }
576     (void)cwd;
577     return wxExecute(cmd, wxEXEC_ASYNC, process);
578 #endif // !wxCHECK_VERSION(3, 0, 0)
579 }
580 
LaunchProcess(const wxString & cmd,const wxString & cwd)581 int DebuggerGDB::LaunchProcess(const wxString& cmd, const wxString& cwd)
582 {
583     if (m_pProcess)
584         return -1;
585 
586     // start the gdb process
587     m_pProcess = new PipedProcess(&m_pProcess, this, idGDBProcess, true, cwd);
588     Log(_("Starting debugger: ") + cmd);
589     m_Pid = LaunchProcessWithShell(cmd, m_pProcess, cwd);
590 
591 #ifdef __WXMAC__
592     if (m_Pid == -1)
593     {
594         // Great! We got a fake PID. Time to Go Fish with our "ps" rod:
595 
596         m_Pid = 0;
597         pid_t mypid = getpid();
598         wxString mypidStr;
599         mypidStr << mypid;
600 
601         long pspid = 0;
602         wxString psCmd;
603         wxArrayString psOutput;
604         wxArrayString psErrors;
605 
606         psCmd << wxT("/bin/ps -o ppid,pid,command");
607         DebugLog(wxString::Format( _("Executing: %s"), psCmd.wx_str()) );
608         int result = wxExecute(psCmd, psOutput, psErrors, wxEXEC_SYNC);
609 
610         mypidStr << wxT(" ");
611 
612         for (int i = 0; i < psOutput.GetCount(); ++i)
613         { //  PPID   PID COMMAND
614            wxString psLine = psOutput.Item(i);
615            if (psLine.StartsWith(mypidStr) && psLine.Contains(wxT("gdb")))
616            {
617                wxString pidStr = psLine.Mid(mypidStr.Length());
618                pidStr = pidStr.BeforeFirst(' ');
619                if (pidStr.ToLong(&pspid))
620                {
621                    m_Pid = pspid;
622                    break;
623                }
624            }
625          }
626 
627         for (int i = 0; i < psErrors.GetCount(); ++i)
628             DebugLog(wxString::Format( _("PS Error:%s"), psErrors.Item(i).wx_str()) );
629     }
630 #endif
631 
632     if (!m_Pid)
633     {
634         delete m_pProcess;
635         m_pProcess = 0;
636         Log(_("failed"), Logger::error);
637         return -1;
638     }
639     else if (!m_pProcess->GetOutputStream())
640     {
641         delete m_pProcess;
642         m_pProcess = 0;
643         Log(_("failed (to get debugger's stdin)"), Logger::error);
644         return -2;
645     }
646     else if (!m_pProcess->GetInputStream())
647     {
648         delete m_pProcess;
649         m_pProcess = 0;
650         Log(_("failed (to get debugger's stdout)"), Logger::error);
651         return -2;
652     }
653     else if (!m_pProcess->GetErrorStream())
654     {
655         delete m_pProcess;
656         m_pProcess = 0;
657         Log(_("failed (to get debugger's stderr)"), Logger::error);
658         return -2;
659     }
660     Log(_("done"));
661     return 0;
662 }
663 
IsStopped() const664 bool DebuggerGDB::IsStopped() const
665 {
666     return !m_State.HasDriver() || m_State.GetDriver()->IsProgramStopped();
667 }
668 
IsBusy() const669 bool DebuggerGDB::IsBusy() const
670 {
671     return m_State.HasDriver() && m_State.GetDriver()->IsQueueBusy();
672 }
673 
674 
Debug(bool breakOnEntry)675 bool DebuggerGDB::Debug(bool breakOnEntry)
676 {
677     // if already running, return
678     if (m_pProcess || WaitingCompilerToFinish())
679         return false;
680 
681     m_pProject = 0;
682     m_NoDebugInfo = false;
683 
684     // can only debug projects or attach to processes
685     ProjectManager* prjMan = Manager::Get()->GetProjectManager();
686     cbProject* project = prjMan->GetActiveProject();
687     if (!project && m_PidToAttach == 0)
688         return false;
689 
690     m_pProject = project;
691     if (m_pProject && m_ActiveBuildTarget.IsEmpty())
692         m_ActiveBuildTarget = m_pProject->GetActiveBuildTarget();
693 
694     m_Canceled = false;
695     if (!EnsureBuildUpToDate(breakOnEntry ? StartTypeStepInto : StartTypeRun))
696         return false;
697 
698     // if not waiting for the compiler, start debugging now
699     // but first check if the driver has already been started:
700     // if the build process was ultra-fast (i.e. nothing to be done),
701     // it may have already called DoDebug() and m_WaitingCompilerToFinish
702     // would already be set to false
703     // by checking the driver availability, we avoid calling DoDebug
704     // a second consecutive time...
705     // the same applies for m_Canceled: it is true if DoDebug() was launched but
706     // returned an error
707     if (!WaitingCompilerToFinish() && !m_State.HasDriver() && !m_Canceled)
708     {
709         return DoDebug(breakOnEntry) == 0;
710     }
711 
712     return true;
713 }
714 
DoDebug(bool breakOnEntry)715 int DebuggerGDB::DoDebug(bool breakOnEntry)
716 {
717     // set this to true before every error exit point in this function
718     m_Canceled = false;
719     // Init these just in case.
720     m_bIsConsole = false;
721     m_nConsolePid = 0;
722     ProjectManager* prjMan = Manager::Get()->GetProjectManager();
723 
724     // select the build target to debug
725     ProjectBuildTarget* target = 0;
726     Compiler* actualCompiler = 0;
727     if ( (m_PidToAttach == 0) && m_pProject)
728     {
729         Log(_("Selecting target: "));
730         if (!m_pProject->BuildTargetValid(m_ActiveBuildTarget, false))
731         {
732             int tgtIdx = m_pProject->SelectTarget();
733             if (tgtIdx == -1)
734             {
735                 Log(_("canceled"));
736                 m_Canceled = true;
737                 return 3;
738             }
739             target = m_pProject->GetBuildTarget(tgtIdx);
740             m_ActiveBuildTarget = (target ? target->GetTitle() : wxString(wxEmptyString));
741         }
742         else
743             target = m_pProject->GetBuildTarget(m_ActiveBuildTarget);
744 
745         // make sure it's not a commands-only target
746         if (target && target->GetTargetType() == ttCommandsOnly)
747         {
748             cbMessageBox(_("The selected target is only running pre/post build step commands\n"
749                            "Can't debug such a target..."), _("Information"), wxICON_INFORMATION);
750             Log(_("aborted"));
751             return 3;
752         }
753         if (target) Log(target->GetTitle());
754 
755         // find the target's compiler (to see which debugger to use)
756         actualCompiler = CompilerFactory::GetCompiler(target ? target->GetCompilerID()
757                                                              : m_pProject->GetCompilerID());
758     }
759     else
760         actualCompiler = CompilerFactory::GetDefaultCompiler();
761 
762     if (!actualCompiler)
763     {
764         wxString msg;
765         msg.Printf(_("This %s is configured to use an invalid debugger.\nThe operation failed..."), target ? _("target") : _("project"));
766         cbMessageBox(msg, _("Error"), wxICON_ERROR);
767         m_Canceled = true;
768         return 9;
769     }
770 
771     // is gdb accessible, i.e. can we find it?
772     wxString cmdexe;
773     cmdexe = GetActiveConfigEx().GetDebuggerExecutable();
774     cmdexe.Trim();
775     cmdexe.Trim(true);
776     if (cmdexe.IsEmpty())
777     {
778         Log(_("ERROR: You need to specify a debugger program in the debuggers's settings."), Logger::error);
779 
780         if (platform::windows)
781         {
782             Log(_("(For MinGW compilers, it's 'gdb.exe' (without the quotes))"), Logger::error);
783             Log(_("(For MSVC compilers, it's 'cdb.exe' (without the quotes))"), Logger::error);
784         }
785         else
786         {
787             Log(_("(For GCC compilers, it's 'gdb' (without the quotes))"), Logger::error);
788         }
789 
790         m_Canceled = true;
791         return -1;
792     }
793 
794     // start debugger driver based on target compiler, or default compiler if no target
795     if (!m_State.StartDriver(target))
796     {
797         cbMessageBox(_T("Could not decide which debugger to use!"), _T("Error"), wxICON_ERROR);
798         m_Canceled = true;
799         return -1;
800     }
801 
802     // Notify debugger plugins so they could start a GDB server process
803     PluginManager *plm = Manager::Get()->GetPluginManager();
804     CodeBlocksEvent evt(cbEVT_DEBUGGER_STARTED);
805     plm->NotifyPlugins(evt);
806     int nRet = evt.GetInt();
807     if (nRet < 0)
808     {
809         cbMessageBox(_T("A plugin interrupted the debug process."));
810         Log(_("Aborted by plugin"));
811         m_Canceled = true;
812         return -1;
813     }
814     // Continue
815 
816     // create gdb launch command
817     wxString cmd;
818 
819     // prepare the driver
820     wxString cmdline;
821     if (m_PidToAttach == 0)
822     {
823         m_State.GetDriver()->ClearDirectories();
824         // add other open projects dirs as search dirs (only if option is enabled)
825         if (GetActiveConfigEx().GetFlag(DebuggerConfiguration::AddOtherProjectDirs))
826         {
827             // add as include dirs all open project base dirs
828             ProjectsArray* projects = prjMan->GetProjects();
829             for (unsigned int i = 0; i < projects->GetCount(); ++i)
830             {
831                 cbProject* it = projects->Item(i);
832                 // skip if it's THE project (added last)
833                 if (it == m_pProject)
834                     continue;
835                 AddSourceDir(it->GetBasePath());
836                 AddSourceDir(it->GetCommonTopLevelPath());
837             }
838         }
839 
840         // Note: I've done some testing and parsing 1000 strings takes 2-3ms, so this isn't really
841         // a problem. The code adding the source dirs to the debugger driver is a lot slower!
842         // now add all per-project user-set search dirs
843         const wxArrayString& pdirs = ParseSearchDirs(*m_pProject);
844         for (size_t i = 0; i < pdirs.GetCount(); ++i)
845             AddSourceDir(pdirs[i]);
846 
847         // lastly, add THE project as source dir
848         if (m_pProject)
849         {
850             AddSourceDir(m_pProject->GetBasePath());
851             AddSourceDir(m_pProject->GetCommonTopLevelPath());
852         }
853 
854         // set the file to debug (depends on the target type)
855         wxString debuggee, path;
856         if ( !GetDebuggee(debuggee, path, target) )
857         {
858             m_Canceled = true;
859             return -3;
860         }
861 
862         if (!path.empty())
863         {
864             ConvertToGDBDirectory(path);
865             if (path != _T(".")) // avoid silly message "changing to ."
866             {
867                 Log(_("Changing directory to: ") + path);
868                 m_State.GetDriver()->SetWorkingDirectory(path);
869             }
870         }
871 
872         if (target && !target->GetExecutionParameters().IsEmpty())
873             m_State.GetDriver()->SetArguments(target->GetExecutionParameters());
874 
875         cmdline = m_State.GetDriver()->GetCommandLine(cmdexe, debuggee, GetActiveConfigEx().GetUserArguments());
876     }
877     else // m_PidToAttach != 0
878         cmdline = m_State.GetDriver()->GetCommandLine(cmdexe, m_PidToAttach, GetActiveConfigEx().GetUserArguments());
879 
880     RemoteDebugging rd;
881 
882     if (m_pProject)
883     {
884         // Note: This is parsing the remote debugging info on every start. It is not fast but it is
885         //       not slow - parsing the info for 500 targets takes 2-3ms, which is fine.
886         //       One easy optimization is to parse  the info only for the project and the target
887         //       which is being debugged.
888         const RemoteDebuggingMap &remoteDebuggingMap = ParseRemoteDebuggingMap(*m_pProject);
889         // project settings
890         RemoteDebuggingMap::const_iterator it = remoteDebuggingMap.find(nullptr);
891         if (it != remoteDebuggingMap.end())
892             rd = it->second;
893 
894         // target settings
895         it = remoteDebuggingMap.find(target);
896         if (it != remoteDebuggingMap.end())
897             rd.MergeWith(it->second);
898     }
899 
900 //////////////////killerbot : most probably here : execute the shell commands (we could access the per target debugger settings)
901     wxString oldLibPath; // keep old PATH/LD_LIBRARY_PATH contents
902     if (!rd.skipLDpath)
903     {
904         wxGetEnv(CB_LIBRARY_ENVVAR, &oldLibPath);
905 
906         // setup dynamic linker path
907         if (actualCompiler && target)
908         {
909             wxString newLibPath;
910             const wxString libPathSep = platform::windows ? _T(";") : _T(":");
911             newLibPath << _T(".") << libPathSep;
912 
913             CompilerCommandGenerator *generator = actualCompiler->GetCommandGenerator(m_pProject);
914             newLibPath << GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep);
915             delete generator;
916 
917             if (newLibPath.Mid(newLibPath.Length() - 1, 1) != libPathSep)
918                 newLibPath << libPathSep;
919             newLibPath << oldLibPath;
920             wxSetEnv(CB_LIBRARY_ENVVAR, newLibPath);
921             Log(wxString(_("Set variable: ")) + CB_LIBRARY_ENVVAR wxT("=") + newLibPath);
922         }
923     }
924 
925     #ifdef __WXMSW__
926     if (!m_State.GetDriver()->UseDebugBreakProcess())
927     {
928         AllocConsole();
929         SetConsoleTitleA("Codeblocks debug console - DO NOT CLOSE!");
930         SetConsoleCtrlHandler(HandlerRoutine, TRUE);
931         m_bIsConsole = true;
932 
933         HWND windowHandle = GetConsoleWindow();
934         if (windowHandle)
935             ShowWindow(windowHandle, SW_HIDE);
936     }
937     #endif
938     // start the gdb process
939     wxString wdir = m_State.GetDriver()->GetDebuggersWorkingDirectory();
940     if (wdir.empty())
941         wdir = m_pProject ? m_pProject->GetBasePath() : _T(".");
942     DebugLog(_T("Command-line: ") + cmdline);
943     DebugLog(_T("Working dir : ") + wdir);
944     int ret = LaunchProcess(cmdline, wdir);
945 
946     if (!rd.skipLDpath)
947     {
948         // restore dynamic linker path
949         wxSetEnv(CB_LIBRARY_ENVVAR, oldLibPath);
950     }
951 
952     if (ret != 0)
953     {
954         m_Canceled = true;
955         return ret;
956     }
957 
958     wxString out;
959     // start polling gdb's output
960     m_TimerPollDebugger.Start(20);
961 
962     // although I don't really like these do-nothing loops, we must wait a small amount of time
963     // for gdb to see if it really started: it may fail to load shared libs or whatever
964     // the reason this is added is because I had a case where gdb would error and bail out
965     // *while* the driver->Prepare() call was running below and hell broke loose...
966     int i = 50;
967     while (i)
968     {
969         wxMilliSleep(1);
970         Manager::Yield();
971         --i;
972     }
973     if (!m_State.HasDriver())
974         return -1;
975 
976     bool isConsole = (target && target->GetTargetType() == ttConsoleOnly);
977     m_State.GetDriver()->Prepare(isConsole, m_printElements, rd);
978     m_State.ApplyBreakpoints();
979 
980    #ifndef __WXMSW__
981     // create xterm and issue tty "/dev/pts/#" to GDB where
982     // # is the tty for the newly created xterm
983     m_bIsConsole = target && target->GetUseConsoleRunner();
984     if (m_bIsConsole)
985     {
986         wxString consoleTty;
987         m_nConsolePid = RunNixConsole(consoleTty);
988         if (m_nConsolePid > 0)
989         {
990             m_stopDebuggerConsoleClosed = true;
991             wxString gdbTtyCmd;
992             gdbTtyCmd << wxT("tty ") << consoleTty;
993             m_State.GetDriver()->QueueCommand(new DebuggerCmd(m_State.GetDriver(), gdbTtyCmd, true));
994             DebugLog(wxString::Format( _("Queued:[%s]"), gdbTtyCmd.wx_str()) );
995         }
996     }//if
997    #endif//ndef __WXMSW__
998 
999     // Don't issue 'run' if attaching to a process (Bug #1391904)
1000     if (m_PidToAttach == 0)
1001         m_State.GetDriver()->Start(breakOnEntry);
1002     else
1003         m_State.GetDriver()->Attach(m_PidToAttach);
1004 
1005     // switch to the user-defined layout for debugging
1006     if (m_pProcess)
1007         SwitchToDebuggingLayout();
1008 
1009     return 0;
1010 } // Debug
1011 
AddSourceDir(const wxString & dir)1012 void DebuggerGDB::AddSourceDir(const wxString& dir)
1013 {
1014     if (!m_State.HasDriver() || dir.IsEmpty())
1015         return;
1016     wxString filename = dir;
1017     Manager::Get()->GetMacrosManager()->ReplaceEnvVars(filename); // apply env vars
1018     Log(_("Adding source dir: ") + filename);
1019     ConvertToGDBDirectory(filename, _T(""), false);
1020     m_State.GetDriver()->AddDirectory(filename);
1021 }
1022 
1023 // static
StripQuotes(wxString & str)1024 void DebuggerGDB::StripQuotes(wxString& str)
1025 {
1026     if (str.GetChar(0) == _T('\"') && str.GetChar(str.Length() - 1) == _T('\"'))
1027         str = str.Mid(1, str.Length() - 2);
1028 }
1029 
1030 // static
ConvertToGDBFriendly(wxString & str)1031 void DebuggerGDB::ConvertToGDBFriendly(wxString& str)
1032 {
1033     if (str.IsEmpty())
1034         return;
1035 
1036     str = UnixFilename(str);
1037     while (str.Replace(_T("\\"), _T("/")))
1038         ;
1039     while (str.Replace(_T("//"), _T("/")))
1040         ;
1041     if (str.Find(_T(' ')) != -1 && str.GetChar(0) != _T('"'))
1042         str = _T("\"") + str + _T("\"");
1043 }
1044 
1045 // static
ConvertToGDBFile(wxString & str)1046 void DebuggerGDB::ConvertToGDBFile(wxString& str)
1047 {
1048     wxFileName fname = str;
1049     str = fname.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
1050     DebuggerGDB::ConvertToGDBDirectory(str);
1051     str << fname.GetFullName();
1052 }
1053 
ConvertDirectory(wxString & str,wxString base,bool relative)1054 void DebuggerGDB::ConvertDirectory(wxString& str, wxString base, bool relative)
1055 {
1056     ConvertToGDBDirectory(str, base, relative);
1057 }
1058 
1059 // static
1060 //if relative == false, try to leave as an absolute path
ConvertToGDBDirectory(wxString & str,wxString base,bool relative)1061 void DebuggerGDB::ConvertToGDBDirectory(wxString& str, wxString base, bool relative)
1062 {
1063     if (str.IsEmpty())
1064         return;
1065 
1066     ConvertToGDBFriendly(str);
1067     ConvertToGDBFriendly(base);
1068     StripQuotes(str);
1069     StripQuotes(base);
1070 
1071     if (platform::windows)
1072     {
1073         int  ColonLocation   = str.Find(_T(':'));
1074         bool convert_path_83 = false;
1075         if (ColonLocation != wxNOT_FOUND)
1076             convert_path_83 = true;
1077         else if (!base.IsEmpty() && str.GetChar(0) != _T('/'))
1078         {
1079             if (base.GetChar(base.Length()) == _T('/'))
1080                 base = base.Mid(0, base.Length() - 2);
1081 
1082             while (!str.IsEmpty())
1083             {
1084                 base += _T("/") + str.BeforeFirst(_T('/'));
1085                 if (str.Find(_T('/')) != wxNOT_FOUND) str = str.AfterFirst(_T('/'));
1086                 else                                  str.Clear();
1087             }
1088             convert_path_83 = true;
1089         }
1090 
1091         // If can, get 8.3 name for path (Windows only)
1092         if (convert_path_83 && str.Contains(_T(' '))) // only if has spaces
1093         {
1094             wxFileName fn(str); // might contain a file name, too
1095             wxString path_83 = fn.GetShortPath();
1096             if (!path_83.IsEmpty())
1097                 str = path_83; // construct filename again
1098         }
1099 
1100         if (ColonLocation == wxNOT_FOUND || base.IsEmpty())
1101             relative = false; // Can't do it
1102     }
1103     else
1104     {
1105         if ((str.GetChar(0) != _T('/') && str.GetChar(0) != _T('~')) || base.IsEmpty())
1106             relative = false;
1107     }
1108 
1109     if (relative)
1110     {
1111         if (platform::windows)
1112         {
1113             if (str.Find(_T(':')) != wxNOT_FOUND)
1114                 str = str.Mid(str.Find(_T(':')) + 2, str.Length());
1115             if (base.Find(_T(':')) != wxNOT_FOUND)
1116                 base = base.Mid(base.Find(_T(':')) + 2, base.Length());
1117         }
1118         else
1119         {
1120             if      (str.GetChar(0) == _T('/'))  str  = str.Mid(1, str.Length());
1121             else if (str.GetChar(0) == _T('~'))  str  = str.Mid(2, str.Length());
1122 
1123             if      (base.GetChar(0) == _T('/')) base = base.Mid(1, base.Length());
1124             else if (base.GetChar(0) == _T('~')) base = base.Mid(2, base.Length());
1125         }
1126 
1127         while (!base.IsEmpty() && !str.IsEmpty())
1128         {
1129             if (str.BeforeFirst(_T('/')) == base.BeforeFirst(_T('/')))
1130             {
1131                 if (str.Find(_T('/')) == wxNOT_FOUND) str.Clear();
1132                 else                                  str = str.AfterFirst(_T('/'));
1133 
1134                 if (base.Find(_T('/')) == wxNOT_FOUND) base.Clear();
1135                 else                                   base = base.AfterFirst(_T('/'));
1136             }
1137             else break;
1138         }
1139         while (!base.IsEmpty())
1140         {
1141             str = _T("../") + str;
1142             if (base.Find(_T('/')) == wxNOT_FOUND) base.Clear();
1143             else                                   base = base.AfterFirst(_T('/'));
1144         }
1145     }
1146     ConvertToGDBFriendly(str);
1147 }
1148 
SendCommand(const wxString & cmd,bool debugLog)1149 void DebuggerGDB::SendCommand(const wxString& cmd, bool debugLog)
1150 {
1151     const wxString &cleandCmd = CleanStringValue(cmd);
1152     if (!debugLog)
1153         Log(_T("> ") + cleandCmd);
1154 
1155     if (debugLog)
1156         DoSendCommand(cleandCmd);
1157     else if (m_State.HasDriver())
1158         m_State.GetDriver()->QueueCommand(new DebuggerCmd(m_State.GetDriver(), cleandCmd, true));
1159 }
1160 
DoSendCommand(const wxString & cmd)1161 void DebuggerGDB::DoSendCommand(const wxString& cmd)
1162 {
1163     if (!m_pProcess || !IsStopped())
1164         return;
1165 
1166     if (HasDebugLog())
1167         DebugLog(wxT("> ") + cmd);
1168 
1169     m_pProcess->SendString(cmd);
1170 }
1171 
RequestUpdate(DebugWindows window)1172 void DebuggerGDB::RequestUpdate(DebugWindows window)
1173 {
1174     switch (window)
1175     {
1176         case Backtrace:
1177             RunCommand(CMD_BACKTRACE);
1178             break;
1179         case CPURegisters:
1180             RunCommand(CMD_REGISTERS);
1181             break;
1182         case Disassembly:
1183             RunCommand(CMD_DISASSEMBLE);
1184             break;
1185         case ExamineMemory:
1186             RunCommand(CMD_MEMORYDUMP);
1187             break;
1188         case MemoryRange:
1189             m_State.GetDriver()->UpdateMemoryRangeWatches(m_memoryRanges, false);
1190             break;
1191         case Threads:
1192             RunCommand(CMD_RUNNINGTHREADS);
1193             break;
1194         case Watches:
1195             if (IsWindowReallyShown(Manager::Get()->GetDebuggerManager()->GetWatchesDialog()->GetWindow()))
1196                 DoWatches();
1197             break;
1198         default:
1199             break;
1200     }
1201 }
1202 
RunCommand(int cmd)1203 void DebuggerGDB::RunCommand(int cmd)
1204 {
1205     // just check for the process
1206     if (!m_pProcess)
1207         return;
1208 
1209     bool debuggerContinued = false;
1210 
1211     switch (cmd)
1212     {
1213         case CMD_CONTINUE:
1214         {
1215             ClearActiveMarkFromAllEditors();
1216             if (m_State.HasDriver())
1217             {
1218                 Log(_("Continuing..."));
1219                 m_State.GetDriver()->Continue();
1220                 m_State.GetDriver()->ResetCurrentFrame();
1221                 debuggerContinued = true;
1222             }
1223             break;
1224         }
1225 
1226         case CMD_STEP:
1227         {
1228             ClearActiveMarkFromAllEditors();
1229             if (m_State.HasDriver())
1230             {
1231                 m_State.GetDriver()->Step();
1232                 m_State.GetDriver()->ResetCurrentFrame();
1233                 debuggerContinued = true;
1234             }
1235             break;
1236         }
1237 
1238         case CMD_STEP_INSTR:
1239         {
1240             ClearActiveMarkFromAllEditors();
1241             if (!Manager::Get()->GetDebuggerManager()->UpdateDisassembly())
1242             {
1243                 // first time users should have some help from us ;)
1244                 RunCommand(CMD_DISASSEMBLE);
1245             }
1246             if (m_State.HasDriver())
1247             {
1248                 m_State.GetDriver()->StepInstruction();
1249                 m_State.GetDriver()->ResetCurrentFrame();
1250                 m_State.GetDriver()->NotifyCursorChanged();
1251                 debuggerContinued = true;
1252             }
1253             break;
1254         }
1255 
1256         case CMD_STEP_INTO_INSTR:
1257         {
1258             ClearActiveMarkFromAllEditors();
1259             if (!Manager::Get()->GetDebuggerManager()->UpdateDisassembly())
1260             {
1261                 // first time users should have some help from us ;)
1262                 RunCommand(CMD_DISASSEMBLE);
1263             }
1264             if (m_State.HasDriver())
1265             {
1266                 m_State.GetDriver()->StepIntoInstruction();
1267                 m_State.GetDriver()->ResetCurrentFrame();
1268                 m_State.GetDriver()->NotifyCursorChanged();
1269                 debuggerContinued = true;
1270             }
1271             break;
1272         }
1273 
1274         case CMD_STEPIN:
1275         {
1276             ClearActiveMarkFromAllEditors();
1277             if (m_State.HasDriver())
1278             {
1279                 m_State.GetDriver()->StepIn();
1280                 m_State.GetDriver()->ResetCurrentFrame();
1281                 debuggerContinued = true;
1282             }
1283             break;
1284         }
1285 
1286         case CMD_STEPOUT:
1287         {
1288             ClearActiveMarkFromAllEditors();
1289             if (m_State.HasDriver())
1290             {
1291                 m_State.GetDriver()->StepOut();
1292                 m_State.GetDriver()->ResetCurrentFrame();
1293                 debuggerContinued = true;
1294             }
1295             break;
1296         }
1297 
1298         case CMD_STOP:
1299         {
1300             ClearActiveMarkFromAllEditors();
1301             if (m_State.HasDriver())
1302             {
1303                 m_State.GetDriver()->Stop();
1304                 m_State.GetDriver()->ResetCurrentFrame();
1305                 MarkAsStopped();
1306             }
1307             break;
1308         }
1309 
1310         case CMD_BACKTRACE:
1311         {
1312             if (m_State.HasDriver())
1313                 m_State.GetDriver()->Backtrace();
1314             break;
1315         }
1316 
1317         case CMD_DISASSEMBLE:
1318         {
1319             if (m_State.HasDriver())
1320                 m_State.GetDriver()->Disassemble();
1321             break;
1322         }
1323 
1324         case CMD_REGISTERS:
1325         {
1326             if (m_State.HasDriver())
1327                 m_State.GetDriver()->CPURegisters();
1328             break;
1329         }
1330 
1331         case CMD_MEMORYDUMP:
1332         {
1333             if (m_State.HasDriver())
1334                 m_State.GetDriver()->MemoryDump();
1335             break;
1336         }
1337 
1338         case CMD_RUNNINGTHREADS:
1339         {
1340             if (m_State.HasDriver())
1341                 m_State.GetDriver()->RunningThreads();
1342             break;
1343         }
1344 
1345         default: break;
1346     }
1347 
1348     if (debuggerContinued)
1349     {
1350         PluginManager *plm = Manager::Get()->GetPluginManager();
1351         CodeBlocksEvent evt(cbEVT_DEBUGGER_CONTINUED);
1352         evt.SetPlugin(this);
1353         plm->NotifyPlugins(evt);
1354     }
1355 }
1356 
GetStackFrameCount() const1357 int DebuggerGDB::GetStackFrameCount() const
1358 {
1359     return m_State.GetDriver()->GetStackFrames().size();
1360 }
1361 
GetStackFrame(int index) const1362 cb::shared_ptr<const cbStackFrame> DebuggerGDB::GetStackFrame(int index) const
1363 {
1364     return m_State.GetDriver()->GetStackFrames()[index];
1365 }
1366 
SwitchToFrame(int number)1367 void DebuggerGDB::SwitchToFrame(int number)
1368 {
1369     if (m_State.HasDriver())
1370     {
1371         m_State.GetDriver()->SetCurrentFrame(number, true);
1372         m_State.GetDriver()->SwitchToFrame(number);
1373 
1374         if (Manager::Get()->GetDebuggerManager()->UpdateBacktrace())
1375            Manager::Get()->GetDebuggerManager()->GetBacktraceDialog()->Reload();
1376     }
1377 }
1378 
GetActiveStackFrame() const1379 int DebuggerGDB::GetActiveStackFrame() const
1380 {
1381     return m_State.HasDriver() ? m_State.GetDriver()->GetCurrentFrame() : 0;
1382 }
1383 
GetThreadsCount() const1384 int DebuggerGDB::GetThreadsCount() const
1385 {
1386     if (!m_State.HasDriver())
1387         return 0;
1388     else
1389         return m_State.GetDriver()->GetThreads().size();
1390 }
1391 
GetThread(int index) const1392 cb::shared_ptr<const cbThread> DebuggerGDB::GetThread(int index) const
1393 {
1394     return m_State.GetDriver()->GetThreads()[index];
1395 }
1396 
SwitchToThread(int thread_number)1397 bool DebuggerGDB::SwitchToThread(int thread_number)
1398 {
1399     if (!m_State.HasDriver())
1400         return false;
1401     DebuggerDriver *driver = m_State.GetDriver();
1402     DebuggerDriver::ThreadsContainer const &threads = driver->GetThreads();
1403 
1404     for (DebuggerDriver::ThreadsContainer::const_iterator it = threads.begin(); it != threads.end(); ++it)
1405     {
1406         if ((*it)->GetNumber() == thread_number)
1407         {
1408             if (!(*it)->IsActive())
1409                 driver->SwitchThread(thread_number);
1410             return true;
1411         }
1412     }
1413     return false;
1414 }
1415 
AddBreakpoint(const wxString & filename,int line)1416 cb::shared_ptr<cbBreakpoint> DebuggerGDB::AddBreakpoint(const wxString& filename, int line)
1417 {
1418     bool debuggerIsRunning = !IsStopped();
1419     if (debuggerIsRunning)
1420         DoBreak(true);
1421 
1422     cb::shared_ptr<DebuggerBreakpoint> bp = m_State.AddBreakpoint(filename, line, false);
1423 
1424     if (debuggerIsRunning)
1425         Continue();
1426 
1427     return bp;
1428 }
1429 
AddDataBreakpoint(const wxString & dataExpression)1430 cb::shared_ptr<cbBreakpoint> DebuggerGDB::AddDataBreakpoint(const wxString& dataExpression)
1431 {
1432     DataBreakpointDlg dlg(Manager::Get()->GetAppWindow(), dataExpression, true, 1);
1433     PlaceWindow(&dlg);
1434     if (dlg.ShowModal() == wxID_OK)
1435     {
1436         const wxString& newDataExpression = dlg.GetDataExpression();
1437         int sel = dlg.GetSelection();
1438         cb::shared_ptr<DebuggerBreakpoint> bp = m_State.AddBreakpoint(newDataExpression, sel != 1, sel != 0);
1439         return bp;
1440     }
1441     else
1442         return cb::shared_ptr<cbBreakpoint>();
1443 }
1444 
GetBreakpointsCount() const1445 int DebuggerGDB::GetBreakpointsCount() const
1446 {
1447     return m_State.GetBreakpoints().size();
1448 }
1449 
GetBreakpoint(int index)1450 cb::shared_ptr<cbBreakpoint> DebuggerGDB::GetBreakpoint(int index)
1451 {
1452     BreakpointsList::const_iterator it = m_State.GetBreakpoints().begin();
1453     std::advance(it, index);
1454     cbAssert(it != m_State.GetBreakpoints().end());
1455     return *it;
1456 }
1457 
GetBreakpoint(int index) const1458 cb::shared_ptr<const cbBreakpoint> DebuggerGDB::GetBreakpoint(int index) const
1459 {
1460     BreakpointsList::const_iterator it = m_State.GetBreakpoints().begin();
1461     std::advance(it, index);
1462     cbAssert(it != m_State.GetBreakpoints().end());
1463     return *it;
1464 }
1465 
UpdateBreakpoint(cb::shared_ptr<cbBreakpoint> breakpoint)1466 void DebuggerGDB::UpdateBreakpoint(cb::shared_ptr<cbBreakpoint> breakpoint)
1467 {
1468     const BreakpointsList &breakpoints = m_State.GetBreakpoints();
1469     BreakpointsList::const_iterator it = std::find(breakpoints.begin(), breakpoints.end(), breakpoint);
1470     if (it == breakpoints.end())
1471         return;
1472     cb::shared_ptr<DebuggerBreakpoint> bp = cb::static_pointer_cast<DebuggerBreakpoint>(breakpoint);
1473     bool reset = false;
1474     switch (bp->type)
1475     {
1476         case DebuggerBreakpoint::bptCode:
1477         {
1478             EditBreakpointDlg dlg(*bp, Manager::Get()->GetAppWindow());
1479             PlaceWindow(&dlg);
1480             if (dlg.ShowModal() == wxID_OK)
1481             {
1482                 *bp = dlg.GetBreakpoint();
1483                 reset = true;
1484             }
1485             break;
1486         }
1487         case DebuggerBreakpoint::bptData:
1488         {
1489             int old_sel = 0;
1490             if (bp->breakOnRead && bp->breakOnWrite)
1491                 old_sel = 2;
1492             else if (!bp->breakOnRead && bp->breakOnWrite)
1493                 old_sel = 1;
1494             DataBreakpointDlg dlg(Manager::Get()->GetAppWindow(), bp->breakAddress, bp->enabled, old_sel);
1495             PlaceWindow(&dlg);
1496             if (dlg.ShowModal() == wxID_OK)
1497             {
1498                 bp->enabled = dlg.IsEnabled();
1499                 bp->breakOnRead = dlg.GetSelection() != 1;
1500                 bp->breakOnWrite = dlg.GetSelection() != 0;
1501                 bp->breakAddress = dlg.GetDataExpression();
1502                 reset = true;
1503             }
1504             break;
1505         }
1506         case DebuggerBreakpoint::bptFunction:
1507         default:
1508             return;
1509     }
1510 
1511     if (reset)
1512     {
1513         bool debuggerIsRunning = !IsStopped();
1514         if (debuggerIsRunning)
1515             DoBreak(true);
1516 
1517         m_State.ResetBreakpoint(bp);
1518 
1519         if (debuggerIsRunning)
1520             Continue();
1521     }
1522 }
1523 
DeleteBreakpoint(cb::shared_ptr<cbBreakpoint> breakpoint)1524 void DebuggerGDB::DeleteBreakpoint(cb::shared_ptr<cbBreakpoint> breakpoint)
1525 {
1526     bool debuggerIsRunning = !IsStopped();
1527     if (debuggerIsRunning)
1528         DoBreak(true);
1529 
1530     m_State.RemoveBreakpoint(cb::static_pointer_cast<DebuggerBreakpoint>(breakpoint));
1531 
1532     if (debuggerIsRunning)
1533         Continue();
1534 }
1535 
DeleteAllBreakpoints()1536 void DebuggerGDB::DeleteAllBreakpoints()
1537 {
1538     bool debuggerIsRunning = !IsStopped();
1539     if (debuggerIsRunning)
1540         DoBreak(true);
1541     m_State.RemoveAllBreakpoints();
1542 
1543     if (debuggerIsRunning)
1544         Continue();
1545 }
1546 
ShiftBreakpoint(int index,int lines_to_shift)1547 void DebuggerGDB::ShiftBreakpoint(int index, int lines_to_shift)
1548 {
1549     BreakpointsList breakpoints = m_State.GetBreakpoints();
1550     BreakpointsList::iterator it = breakpoints.begin();
1551     std::advance(it, index);
1552     if (it != breakpoints.end())
1553         m_State.ShiftBreakpoint(*it, lines_to_shift);
1554 }
1555 
EnableBreakpoint(cb::shared_ptr<cbBreakpoint> breakpoint,bool enable)1556 void DebuggerGDB::EnableBreakpoint(cb::shared_ptr<cbBreakpoint> breakpoint, bool enable)
1557 {
1558     bool debuggerIsRunning = !IsStopped();
1559     DebugLog(wxString::Format(wxT("DebuggerGDB::EnableBreakpoint(running=%d);"), debuggerIsRunning?1:0));
1560     if (debuggerIsRunning)
1561         DoBreak(true);
1562 
1563     cb::shared_ptr<DebuggerBreakpoint> bp = cb::static_pointer_cast<DebuggerBreakpoint>(breakpoint);
1564     bp->enabled = enable;
1565     m_State.ResetBreakpoint(bp);
1566 
1567     if (debuggerIsRunning)
1568         Continue();
1569 }
1570 
DeleteAllProjectBreakpoints(cbProject * project)1571 void DebuggerGDB::DeleteAllProjectBreakpoints(cbProject* project)
1572 {
1573     m_State.RemoveAllProjectBreakpoints(project);
1574 }
1575 
Continue()1576 void DebuggerGDB::Continue()
1577 {
1578     RunCommand(CMD_CONTINUE);
1579 }
1580 
Next()1581 void DebuggerGDB::Next()
1582 {
1583     RunCommand(CMD_STEP);
1584 }
1585 
NextInstruction()1586 void DebuggerGDB::NextInstruction()
1587 {
1588     RunCommand(CMD_STEP_INSTR);
1589 }
1590 
StepIntoInstruction()1591 void DebuggerGDB::StepIntoInstruction()
1592 {
1593     RunCommand(CMD_STEP_INTO_INSTR);
1594 }
1595 
Step()1596 void DebuggerGDB::Step()
1597 {
1598     RunCommand(CMD_STEPIN);
1599 }
1600 
Validate(const wxString & line,const char cb)1601 bool DebuggerGDB::Validate(const wxString& line, const char cb)
1602 {
1603     bool bResult = false;
1604 
1605     int bep = line.Find(cb)+1;
1606     int scs = line.Find(_T('\''))+1;
1607     int sce = line.Find(_T('\''),true)+1;
1608     int dcs = line.Find(_T('"'))+1;
1609     int dce = line.Find(_T('"'),true)+1;
1610     //No single and double quote
1611     if (!scs && !sce && !dcs && !dce) bResult = true;
1612     //No single/double quote in pair
1613     if (!(sce-scs) && !(dce-dcs)) bResult = true;
1614     //Outside of single quote
1615     if ((sce-scs) && ((bep < scs)||(bep >sce))) bResult = true;
1616     //Outside of double quote
1617     if ((dce-dcs) && ((bep < dcs)||(bep >dce))) bResult = true;
1618 
1619     return bResult;
1620 }
1621 
StepOut()1622 void DebuggerGDB::StepOut()
1623 {
1624     RunCommand(CMD_STEPOUT);
1625 }
1626 
RunToCursor(const wxString & filename,int line,const wxString & line_text)1627 bool DebuggerGDB::RunToCursor(const wxString& filename, int line, const wxString& line_text)
1628 {
1629     if (m_pProcess)
1630     {
1631         m_State.AddBreakpoint(filename, line, true, line_text);
1632         Manager::Get()->GetDebuggerManager()->GetBreakpointDialog()->Reload();
1633         Continue();
1634         return true;
1635     }
1636     else
1637     {
1638         if (!GetActiveConfigEx().GetFlag(DebuggerConfiguration::DoNotRun))
1639         {
1640             m_State.AddBreakpoint(filename, line, true, line_text);
1641             Manager::Get()->GetDebuggerManager()->GetBreakpointDialog()->Reload();
1642         }
1643         return Debug(false);
1644     }
1645 }
1646 
SetNextStatement(const wxString & filename,int line)1647 void DebuggerGDB::SetNextStatement(const wxString& filename, int line)
1648 {
1649     if (m_State.HasDriver() && IsStopped())
1650     {
1651         m_State.GetDriver()->SetNextStatement(filename, line);
1652     }
1653 }
1654 
Break()1655 void DebuggerGDB::Break()
1656 {
1657     DoBreak(false);
1658 }
1659 
DoBreak(bool temporary)1660 void DebuggerGDB::DoBreak(bool temporary)
1661 {
1662     m_TemporaryBreak = temporary;
1663 
1664     // m_Process is PipedProcess I/O; m_Pid is debugger pid
1665     if (m_pProcess && m_Pid && !IsStopped())
1666     {
1667         long childPid = m_State.GetDriver()->GetChildPID();
1668         long pid = childPid;
1669     #ifndef __WXMSW__
1670         if (pid > 0 && !wxProcess::Exists(pid))
1671         {
1672             DebugLog(wxString::Format(_("Child process (pid:%ld) doesn't exists"), pid), Logger::warning);
1673             pid = 0;
1674         }
1675         if (pid <= 0)
1676             pid = m_Pid; // try poking gdb directly
1677         // non-windows gdb can interrupt the running process. yay!
1678         if (pid <= 0) // look out for the "fake" PIDs (killall)
1679             cbMessageBox(_("Unable to stop the debug process!"), _("Error"), wxOK | wxICON_WARNING);
1680         else
1681         {
1682             if (!wxProcess::Exists(pid))
1683                 DebugLog(wxString::Format(_("GDB process (pid:%ld) doesn't exists"), pid), Logger::error);
1684 
1685             Log(F(_("Trying to interrupt process with pid: %ld; child pid: %ld gdb pid: %ld"),
1686                   pid, childPid, static_cast<long>(m_Pid)));
1687             wxKillError error;
1688             if (wxKill(pid, wxSIGINT, &error) != 0)
1689                 DebugLog(wxString::Format(_("Can't kill process (%ld) %d"), pid, (int)(error)));
1690         }
1691     #else
1692         // windows gdb can interrupt the running process too. yay!
1693         if (   (pid <=0)
1694             && (CreateToolhelp32SnapshotFunc!=NULL)
1695             && (Process32FirstFunc!=NULL)
1696             && (Process32NextFunc!=NULL) )
1697         {
1698             HANDLE snap = CreateToolhelp32SnapshotFunc(TH32CS_SNAPALL,0);
1699             if (snap!=INVALID_HANDLE_VALUE)
1700             {
1701                 PROCESSENTRY32 lppe;
1702                 lppe.dwSize = sizeof(PROCESSENTRY32);
1703                 BOOL ok = Process32FirstFunc(snap, &lppe);
1704                 while ( ok == TRUE)
1705                 {
1706                     if (static_cast<int>(lppe.th32ParentProcessID) == m_Pid) // Have my Child...
1707                     {
1708                         pid = lppe.th32ProcessID;
1709                         DebugLog(F(_("Found child: %ld"),  pid));
1710                     }
1711                     lppe.dwSize = sizeof(PROCESSENTRY32);
1712                     ok = Process32NextFunc(snap, &lppe);
1713                 }
1714                 CloseHandle(snap);
1715             }
1716             else
1717                 Log(_("No handle created. Trying to pause directly with cbd.exe..."), Logger::warning);
1718         }
1719 
1720         if (m_State.GetDriver()->UseDebugBreakProcess())
1721         {
1722             if (!DebugBreakProcessFunc)
1723                 Log(_("DebugBreakProcess is not supported, you need Windows XP or newer..."), Logger::error);
1724             else if (pid > 0)
1725             {
1726                 Log(F(_("Trying to interrupt process with pid: %ld; child pid: %ld gdb pid: %ld"),
1727                       pid, childPid, static_cast<long>(m_Pid)));
1728                 HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
1729                 if (proc)
1730                 {
1731                     DebugBreakProcessFunc(proc); // yay!
1732                     CloseHandle(proc);
1733                 }
1734                 else
1735                     Log(wxT("Interrupting debugger failed :("), Logger::error);
1736             }
1737         }
1738         else
1739         {
1740             if (m_Pid > 0)
1741             {
1742                 Log(_("Trying to interrupt the process by sending CTRL-C event to the console!"));
1743                 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) == 0)
1744                 {
1745                     Log(wxT("Interrupting debugger failed :("), Logger::error);
1746                     return;
1747                 }
1748             }
1749         }
1750     #endif
1751         // Notify debugger plugins for end of debug session
1752         PluginManager *plm = Manager::Get()->GetPluginManager();
1753         CodeBlocksEvent evt(cbEVT_DEBUGGER_PAUSED);
1754         plm->NotifyPlugins(evt);
1755     }
1756 }
1757 
Stop()1758 void DebuggerGDB::Stop()
1759 {
1760     // m_Process is PipedProcess I/O; m_Pid is debugger pid
1761     if (m_pProcess && m_Pid)
1762     {
1763         if (!IsStopped())
1764         {
1765             // TODO (obfuscated#): Check if this can be implemented on Windows
1766 #ifdef __WXGTK__
1767             int childPID=m_State.GetDriver()->GetChildPID();
1768             if (childPID == 0)
1769             {
1770                 DebugLog(_("Child pid is 0, so we will terminate GDB directly"));
1771                 wxKill(m_Pid, wxSIGTERM);
1772                 return;
1773             }
1774 #endif
1775             Break();
1776         }
1777         RunCommand(CMD_STOP);
1778     }
1779 }
1780 
ParseOutput(const wxString & output)1781 void DebuggerGDB::ParseOutput(const wxString& output)
1782 {
1783     if (!output.IsEmpty() && m_State.HasDriver())
1784     {
1785         m_State.GetDriver()->ParseOutput(output);
1786     }
1787 }
1788 
GetCurrentPosition(wxString & filename,int & line)1789 void DebuggerGDB::GetCurrentPosition(wxString &filename, int &line)
1790 {
1791     if (m_State.HasDriver())
1792     {
1793         const Cursor& cursor = m_State.GetDriver()->GetCursor();
1794         filename = cursor.file;
1795         line = cursor.line;
1796     }
1797     else
1798     {
1799         filename = wxEmptyString;
1800         line = -1;
1801     }
1802 }
1803 
1804 // TODO: should reimplement
OnAddSymbolFile(wxCommandEvent & WXUNUSED (event))1805 void DebuggerGDB::OnAddSymbolFile(wxCommandEvent& WXUNUSED(event))
1806 {
1807     wxString file = wxFileSelector(_("Choose file to read symbols from"),
1808                                     _T(""),
1809                                     _T(""),
1810                                     _T(""),
1811                                     _("Executables and libraries|*.exe;*.dll"),
1812                                     wxFD_OPEN | wxFD_FILE_MUST_EXIST | compatibility::wxHideReadonly);
1813     if (file.IsEmpty())
1814         return;
1815 //    Manager::Get()->GetLogManager()->Log(m_PageIndex, _("Adding symbol file: %s"), file.wx_str());
1816     ConvertToGDBDirectory(file);
1817 //    QueueCommand(new DbgCmd_AddSymbolFile(this, file));
1818 }
1819 
SetupToolsMenu(wxMenu & menu)1820 void DebuggerGDB::SetupToolsMenu(wxMenu &menu)
1821 {
1822     if (!GetActiveConfigEx().IsGDB())
1823         return;
1824     menu.Append(idMenuInfoFrame,   _("Current stack frame"), _("Displays info about the current (selected) stack frame"));
1825     menu.Append(idMenuInfoDLL,     _("Loaded libraries"), _("List dynamically loaded libraries (DLL/SO)"));
1826     menu.Append(idMenuInfoFiles,   _("Targets and files"), _("Displays info on the targets and files being debugged"));
1827     menu.Append(idMenuInfoFPU,     _("FPU status"), _("Displays the status of the floating point unit"));
1828     menu.Append(idMenuInfoSignals, _("Signal handling"), _("Displays how the debugger handles various signals"));
1829     menu.AppendSeparator();
1830 
1831     wxMenu *menuPrint = new wxMenu;
1832     menuPrint->AppendRadioItem(idMenuInfoPrintElementsUnlimited, _("Unlimited"),
1833                                _("The full arrays are printed (could lead to lock-ups if uninitialised data is printed)"));
1834     menuPrint->AppendRadioItem(idMenuInfoPrintElements20, _("20"));
1835     menuPrint->AppendRadioItem(idMenuInfoPrintElements50, _("50"));
1836     menuPrint->AppendRadioItem(idMenuInfoPrintElements100, _("100"));
1837     menuPrint->AppendRadioItem(idMenuInfoPrintElements200, _("200 (default)"));
1838     menu.AppendSubMenu(menuPrint, _("Print Elements"), _("Set limit on string chars or array elements to print"));
1839     menu.AppendCheckItem(idMenuInfoCatchThrow, _("Catch throw"),
1840                          _("If enabled the debugger will break when an exception is thronw"));
1841 }
1842 
OnUpdateTools(wxUpdateUIEvent & event)1843 void DebuggerGDB::OnUpdateTools(wxUpdateUIEvent &event)
1844 {
1845     bool checked = (event.GetId() == idMenuInfoPrintElementsUnlimited && m_printElements==0) ||
1846                    (event.GetId() == idMenuInfoPrintElements20 && m_printElements==20) ||
1847                    (event.GetId() == idMenuInfoPrintElements50 && m_printElements==50) ||
1848                    (event.GetId() == idMenuInfoPrintElements100 && m_printElements==100) ||
1849                    (event.GetId() == idMenuInfoPrintElements200 && m_printElements==200);
1850     event.Check(checked);
1851     event.Enable(IsRunning() && IsStopped());
1852 }
1853 
OnPrintElements(wxCommandEvent & event)1854 void DebuggerGDB::OnPrintElements(wxCommandEvent &event)
1855 {
1856     if (event.GetId() == idMenuInfoPrintElementsUnlimited)
1857         m_printElements = 0;
1858     else if (event.GetId() == idMenuInfoPrintElements20)
1859         m_printElements = 20;
1860     else if (event.GetId() == idMenuInfoPrintElements50)
1861         m_printElements = 50;
1862     else if (event.GetId() == idMenuInfoPrintElements100)
1863         m_printElements = 100;
1864     else if (event.GetId() == idMenuInfoPrintElements200)
1865         m_printElements = 200;
1866     else
1867         return;
1868 
1869     wxString cmd = wxString::Format(wxT("set print elements %d"), m_printElements);
1870     m_State.GetDriver()->QueueCommand(new DebuggerCmd(m_State.GetDriver(), cmd));
1871     RequestUpdate(Watches);
1872 }
1873 
OnUpdateCatchThrow(wxUpdateUIEvent & event)1874 void DebuggerGDB::OnUpdateCatchThrow(wxUpdateUIEvent &event)
1875 {
1876     DebuggerConfiguration &config = GetActiveConfigEx();
1877     event.Enable(config.IsGDB() && IsStopped());
1878     event.Check(config.GetFlag(DebuggerConfiguration::CatchExceptions));
1879 }
1880 
OnCatchThrow(wxCommandEvent & event)1881 void DebuggerGDB::OnCatchThrow(wxCommandEvent &event)
1882 {
1883     bool flag = event.IsChecked();
1884     GetActiveConfigEx().SetFlag(DebuggerConfiguration::CatchExceptions, flag);
1885     m_State.GetDriver()->EnableCatchingThrow(flag);
1886 }
1887 
OnInfoFrame(wxCommandEvent & WXUNUSED (event))1888 void DebuggerGDB::OnInfoFrame(wxCommandEvent& WXUNUSED(event))
1889 {
1890     if (m_State.HasDriver())
1891         m_State.GetDriver()->InfoFrame();
1892 }
1893 
OnInfoDLL(wxCommandEvent & WXUNUSED (event))1894 void DebuggerGDB::OnInfoDLL(wxCommandEvent& WXUNUSED(event))
1895 {
1896     if (m_State.HasDriver())
1897     {
1898         m_State.GetDriver()->InfoDLL();
1899     }
1900 }
1901 
OnInfoFiles(wxCommandEvent & WXUNUSED (event))1902 void DebuggerGDB::OnInfoFiles(wxCommandEvent& WXUNUSED(event))
1903 {
1904     if (m_State.HasDriver())
1905         m_State.GetDriver()->InfoFiles();
1906 }
1907 
OnInfoFPU(wxCommandEvent & WXUNUSED (event))1908 void DebuggerGDB::OnInfoFPU(wxCommandEvent& WXUNUSED(event))
1909 {
1910     if (m_State.HasDriver())
1911         m_State.GetDriver()->InfoFPU();
1912 }
1913 
OnInfoSignals(wxCommandEvent & WXUNUSED (event))1914 void DebuggerGDB::OnInfoSignals(wxCommandEvent& WXUNUSED(event))
1915 {
1916     if (m_State.HasDriver())
1917         m_State.GetDriver()->InfoSignals();
1918 }
1919 
OnGDBOutput(wxCommandEvent & event)1920 void DebuggerGDB::OnGDBOutput(wxCommandEvent& event)
1921 {
1922     wxString msg = event.GetString();
1923     if (!msg.IsEmpty())
1924         ParseOutput(msg);
1925 }
1926 
OnGDBError(wxCommandEvent & event)1927 void DebuggerGDB::OnGDBError(wxCommandEvent& event)
1928 {
1929     wxString msg = event.GetString();
1930     if (!msg.IsEmpty())
1931         ParseOutput(msg);
1932 }
1933 
OnGDBTerminated(wxCommandEvent & event)1934 void DebuggerGDB::OnGDBTerminated(wxCommandEvent& event)
1935 {
1936     m_PidToAttach = 0;
1937 
1938     m_TimerPollDebugger.Stop();
1939     m_LastExitCode = event.GetInt();
1940     //the process deletes itself
1941 //    m_pProcess = 0L;
1942 
1943     ClearActiveMarkFromAllEditors();
1944     m_State.StopDriver();
1945     Manager::Get()->GetDebuggerManager()->GetBreakpointDialog()->Reload();
1946     if (!Manager::IsAppShuttingDown())
1947     {
1948         Log(wxString::Format(_("Debugger finished with status %d"), m_LastExitCode));
1949 
1950         if (m_NoDebugInfo)
1951         {
1952             cbMessageBox(_("This project/target has no debugging info."
1953                            "Please change this in the project's build options, re-compile and retry..."),
1954                          _("Error"), wxICON_STOP);
1955         }
1956     }
1957 
1958     // Notify debugger plugins for end of debug session
1959     PluginManager *plm = Manager::Get()->GetPluginManager();
1960     CodeBlocksEvent evt(cbEVT_DEBUGGER_FINISHED);
1961     plm->NotifyPlugins(evt);
1962 
1963     // switch to the user-defined layout when finished debugging
1964     if (!Manager::IsAppShuttingDown())
1965         SwitchToPreviousLayout();
1966     KillConsole();
1967     MarkAsStopped();
1968 
1969     ///killerbot : run there the post shell commands ?
1970 }
1971 
KillConsole()1972 void DebuggerGDB::KillConsole()
1973 {
1974 #ifdef __WXMSW__
1975     if (m_bIsConsole)
1976     {
1977         // remove the CTRL_C handler
1978         SetConsoleCtrlHandler(HandlerRoutine, FALSE);
1979         FreeConsole();
1980         m_bIsConsole = false;
1981     }
1982 #else
1983     // kill any linux console
1984     if ( m_bIsConsole && (m_nConsolePid > 0) )
1985     {
1986         ::wxKill(m_nConsolePid);
1987         m_nConsolePid = 0;
1988         m_bIsConsole = false;
1989     }
1990 #endif
1991 }
1992 
CheckIfConsoleIsClosed()1993 void DebuggerGDB::CheckIfConsoleIsClosed()
1994 {
1995 #ifndef __WXMSW__
1996     // Detect if the console is closed by the user and if it is stop the session.
1997     if (m_stopDebuggerConsoleClosed && m_nConsolePid > 0 && wxKill(m_nConsolePid, wxSIGNONE) != 0)
1998     {
1999         AnnoyingDialog dialog(_("Terminal/Console closed"),
2000                               _("Detected that the Terminal/Console has been closed. "
2001                                 "Do you want to stop the debugging session?"),
2002                               wxART_QUESTION);
2003         if (dialog.ShowModal() == AnnoyingDialog::rtNO)
2004             m_stopDebuggerConsoleClosed = false;
2005         else
2006         {
2007             Stop();
2008             m_nConsolePid = 0;
2009         }
2010     }
2011 #endif
2012 }
2013 
ShowValueTooltip(int style)2014 bool DebuggerGDB::ShowValueTooltip(int style)
2015 {
2016     if (!m_pProcess || !IsStopped())
2017         return false;
2018 
2019     if (!m_State.HasDriver() || !m_State.GetDriver()->IsDebuggingStarted())
2020         return false;
2021 
2022     if (!GetActiveConfigEx().GetFlag(DebuggerConfiguration::EvalExpression))
2023         return false;
2024     if (style != wxSCI_C_DEFAULT && style != wxSCI_C_OPERATOR && style != wxSCI_C_IDENTIFIER &&
2025         style != wxSCI_C_WORD2 && style != wxSCI_C_GLOBALCLASS  && style != wxSCI_C_WXSMITH &&
2026         style != wxSCI_F_IDENTIFIER)
2027     {
2028         return false;
2029     }
2030     return true;
2031 }
2032 
OnValueTooltip(const wxString & token,const wxRect & evalRect)2033 void DebuggerGDB::OnValueTooltip(const wxString &token, const wxRect &evalRect)
2034 {
2035     m_State.GetDriver()->EvaluateSymbol(token, evalRect);
2036 }
2037 
CleanupWhenProjectClosed(cbProject * project)2038 void DebuggerGDB::CleanupWhenProjectClosed(cbProject *project)
2039 {
2040     // remove all breakpoints belonging to the closed project
2041     DeleteAllProjectBreakpoints(project);
2042     // FIXME (#obfuscated): Optimize this when multiple projects are closed
2043     //                      (during workspace close operation for exmaple).
2044     cbBreakpointsDlg *dlg = Manager::Get()->GetDebuggerManager()->GetBreakpointDialog();
2045     dlg->Reload();
2046 }
2047 
OnIdle(wxIdleEvent & event)2048 void DebuggerGDB::OnIdle(wxIdleEvent& event)
2049 {
2050     if (m_pProcess && ((PipedProcess*)m_pProcess)->HasInput())
2051         event.RequestMore();
2052     else
2053         event.Skip();
2054 }
2055 
OnTimer(cb_unused wxTimerEvent & event)2056 void DebuggerGDB::OnTimer(cb_unused wxTimerEvent& event)
2057 {
2058     // send any buffered (previous) output
2059     ParseOutput(wxEmptyString);
2060 
2061     CheckIfConsoleIsClosed();
2062 
2063     wxWakeUpIdle();
2064 }
2065 
OnShowFile(wxCommandEvent & event)2066 void DebuggerGDB::OnShowFile(wxCommandEvent& event)
2067 {
2068     SyncEditor(event.GetString(), event.GetInt(), false);
2069 }
2070 
DebuggeeContinued()2071 void DebuggerGDB::DebuggeeContinued()
2072 {
2073     m_TemporaryBreak = false;
2074 }
2075 
OnCursorChanged(wxCommandEvent & WXUNUSED (event))2076 void DebuggerGDB::OnCursorChanged(wxCommandEvent& WXUNUSED(event))
2077 {
2078     if (m_TemporaryBreak)
2079         return;
2080 
2081     if (m_State.HasDriver())
2082     {
2083         const Cursor& cursor = m_State.GetDriver()->GetCursor();
2084         // checking if driver is stopped is redundant because it would only
2085         // send us this event if it was stopped anyway
2086         if (/*m_State.GetDriver()->IsStopped() &&*/ cursor.changed)
2087         {
2088             bool autoSwitch = cbDebuggerCommonConfig::GetFlag(cbDebuggerCommonConfig::AutoSwitchFrame);
2089 
2090             MarkAllWatchesAsUnchanged();
2091 
2092             // if the cursor line is invalid and the auto switch is on,
2093             // we don't sync the editor, because there is no line to sync to
2094             // and also we are going to execute a backtrace command hoping to find a valid frame.
2095             if (!autoSwitch || cursor.line != -1)
2096                 SyncEditor(cursor.file, cursor.line);
2097 
2098             BringCBToFront();
2099             if (cursor.line != -1)
2100                 Log(wxString::Format(_("At %s:%ld"), cursor.file.wx_str(), cursor.line));
2101             else
2102                 Log(wxString::Format(_("In %s (%s)"), cursor.function.wx_str(), cursor.file.wx_str()));
2103 
2104             // update watches
2105             DebuggerManager *dbg_manager = Manager::Get()->GetDebuggerManager();
2106 
2107             if (IsWindowReallyShown(dbg_manager->GetWatchesDialog()->GetWindow()))
2108                 DoWatches();
2109 
2110             // update CPU registers
2111             if (dbg_manager->UpdateCPURegisters())
2112                 RunCommand(CMD_REGISTERS);
2113 
2114             // update callstack
2115             if (dbg_manager->UpdateBacktrace())
2116                 RunCommand(CMD_BACKTRACE);
2117             else
2118             {
2119                 if (cursor.line == -1 && autoSwitch)
2120                     RunCommand(CMD_BACKTRACE);
2121             }
2122 
2123             // update disassembly
2124             if (dbg_manager->UpdateDisassembly())
2125             {
2126                 uint64_t addr = cbDebuggerStringToAddress(cursor.address);
2127                 //if zero addr, don't attempt disassembly
2128                 if (addr && !dbg_manager->GetDisassemblyDialog()->SetActiveAddress(addr))
2129                     RunCommand(CMD_DISASSEMBLE);
2130             }
2131 
2132             // update memory examiner
2133             if (dbg_manager->UpdateExamineMemory())
2134                 RunCommand(CMD_MEMORYDUMP);
2135 
2136             // update running threads
2137             if (dbg_manager->UpdateThreads())
2138                 RunCommand(CMD_RUNNINGTHREADS);
2139 
2140             // Notify everybody that the debugger cursor has changed.
2141             // This might be used by some view windows to request the debugger plugin to update some
2142             // data.
2143             CodeBlocksEvent cursorChangeEvent(cbEVT_DEBUGGER_CURSOR_CHANGED);
2144             cursorChangeEvent.SetPlugin(this);
2145             Manager::Get()->ProcessEvent(cursorChangeEvent);
2146         }
2147     }
2148 }
2149 
AddWatch(const wxString & symbol,bool update)2150 cb::shared_ptr<cbWatch> DebuggerGDB::AddWatch(const wxString& symbol, bool update)
2151 {
2152     cb::shared_ptr<GDBWatch> watch(new GDBWatch(CleanStringValue(symbol)));
2153     m_watches.push_back(watch);
2154     m_mapWatchesToType[watch] = WatchType::Normal;
2155 
2156     if (m_pProcess && update)
2157         m_State.GetDriver()->UpdateWatch(m_watches.back());
2158 
2159     return watch;
2160 }
2161 
AddMemoryRange(uint64_t address,uint64_t size,const wxString & symbol,bool update)2162 cb::shared_ptr<cbWatch> DebuggerGDB::AddMemoryRange(uint64_t address, uint64_t size,
2163                                                     const wxString &symbol, bool update)
2164 {
2165     cb::shared_ptr<GDBMemoryRangeWatch> watch(new GDBMemoryRangeWatch(address, size, symbol));
2166     m_memoryRanges.push_back(watch);
2167     m_mapWatchesToType[watch] = WatchType::MemoryRange;
2168 
2169     if (m_pProcess && update)
2170         m_State.GetDriver()->UpdateMemoryRangeWatch(m_memoryRanges.back());
2171 
2172     return watch;
2173 }
2174 
AddWatchNoUpdate(const cb::shared_ptr<GDBWatch> & watch)2175 void DebuggerGDB::AddWatchNoUpdate(const cb::shared_ptr<GDBWatch> &watch)
2176 {
2177     m_watches.push_back(watch);
2178     m_mapWatchesToType[watch] = WatchType::Normal;
2179 }
2180 
DeleteWatch(cb::shared_ptr<cbWatch> watch)2181 void DebuggerGDB::DeleteWatch(cb::shared_ptr<cbWatch> watch)
2182 {
2183     MapWatchesToType::iterator itType = m_mapWatchesToType.find(watch);
2184     if (itType == m_mapWatchesToType.end())
2185         return;
2186 
2187     switch (itType->second)
2188     {
2189     case WatchType::Normal:
2190         {
2191             WatchesContainer::iterator it = std::find(m_watches.begin(), m_watches.end(), watch);
2192             if (it != m_watches.end())
2193             {
2194                 m_watches.erase(it);
2195                 return;
2196             }
2197         }
2198         break;
2199     case WatchType::MemoryRange:
2200         {
2201             MemoryRangeWatchesContainer::iterator it = std::find(m_memoryRanges.begin(),
2202                                                                  m_memoryRanges.end(), watch);
2203             if (it != m_memoryRanges.end())
2204             {
2205                 m_memoryRanges.erase(it);
2206                 return;
2207             }
2208             break;
2209         }
2210     }
2211 
2212 }
2213 
HasWatch(cb::shared_ptr<cbWatch> watch)2214 bool DebuggerGDB::HasWatch(cb::shared_ptr<cbWatch> watch)
2215 {
2216     if (watch == m_localsWatch || watch == m_funcArgsWatch)
2217         return true;
2218 
2219     return m_mapWatchesToType.find(watch) != m_mapWatchesToType.end();
2220 }
2221 
IsMemoryRangeWatch(const cb::shared_ptr<cbWatch> & watch)2222 bool DebuggerGDB::IsMemoryRangeWatch(const cb::shared_ptr<cbWatch> &watch)
2223 {
2224     MapWatchesToType::const_iterator it = m_mapWatchesToType.find(watch);
2225     if (it == m_mapWatchesToType.end())
2226         return false;
2227     else
2228         return it->second == WatchType::MemoryRange;
2229 }
2230 
ShowWatchProperties(cb::shared_ptr<cbWatch> watch)2231 void DebuggerGDB::ShowWatchProperties(cb::shared_ptr<cbWatch> watch)
2232 {
2233     // not supported for child nodes or memory ranges!
2234     if (watch->GetParent() || IsMemoryRangeWatch(watch))
2235         return;
2236 
2237     cb::shared_ptr<GDBWatch> real_watch = cb::static_pointer_cast<GDBWatch>(watch);
2238     EditWatchDlg dlg(real_watch, nullptr);
2239     if (dlg.ShowModal() == wxID_OK)
2240         DoWatches();
2241 }
2242 
SetWatchValue(cb::shared_ptr<cbWatch> watch,const wxString & value)2243 bool DebuggerGDB::SetWatchValue(cb::shared_ptr<cbWatch> watch, const wxString &value)
2244 {
2245     if (!m_State.HasDriver())
2246         return false;
2247 
2248     cb::shared_ptr<cbWatch> rootWatch = cbGetRootWatch(watch);
2249     MapWatchesToType::const_iterator itType = m_mapWatchesToType.find(rootWatch);
2250     if (itType == m_mapWatchesToType.end())
2251         return false;
2252 
2253     const WatchType type = itType->second;
2254     if (type == WatchType::MemoryRange)
2255     {
2256         cb::shared_ptr<GDBMemoryRangeWatch> temp_watch = std::static_pointer_cast<GDBMemoryRangeWatch>(watch);
2257         uint64_t addr = temp_watch->GetAddress();
2258 
2259         DebuggerDriver* driver = m_State.GetDriver();
2260         driver->SetMemoryRangeValue(addr, value);
2261     }
2262     else
2263     {
2264         wxString full_symbol;
2265         cb::shared_ptr<cbWatch> temp_watch = watch;
2266         if (g_DebugLanguage == dl_Cpp)
2267         {
2268             while (temp_watch)
2269             {
2270                 wxString symbol;
2271                 temp_watch->GetSymbol(symbol);
2272                 temp_watch = temp_watch->GetParent();
2273 
2274                 if (symbol.find(wxT('*')) != wxString::npos || symbol.find(wxT('&')) != wxString::npos)
2275                     symbol = wxT('(') + symbol + wxT(')');
2276 
2277                 if (full_symbol.empty())
2278                     full_symbol = symbol;
2279                 else
2280                     full_symbol = symbol + wxT('.') + full_symbol;
2281             }
2282         }
2283         else // Fortran language
2284         {
2285             while (temp_watch)
2286             {
2287                 wxString symbol;
2288                 temp_watch->GetSymbol(symbol);
2289                 temp_watch = temp_watch->GetParent();
2290 
2291                 if (full_symbol.empty())
2292                     full_symbol = symbol;
2293                 else
2294                 {
2295                     if (full_symbol.at(0) == '(' && symbol.at(0) == '(')
2296                     {
2297                         size_t sec = full_symbol.find(')');
2298                         if (sec != wxString::npos && symbol.at(symbol.size()-1) == ')')
2299                         {
2300                             full_symbol = full_symbol.substr(0,sec) + wxT(',') + symbol.substr(1,symbol.size()-2) +
2301                                           full_symbol.substr(sec);
2302                         }
2303                     }
2304                     else if (full_symbol.at(0) == '(')
2305                         full_symbol = symbol + full_symbol;
2306                     else
2307                         full_symbol = symbol + wxT('%') + full_symbol;
2308                 }
2309             }
2310         }
2311 
2312         DebuggerDriver* driver = m_State.GetDriver();
2313         driver->SetVarValue(full_symbol, value);
2314     }
2315 
2316     DoWatches();
2317     return true;
2318 }
2319 
ExpandWatch(cb_unused cb::shared_ptr<cbWatch> watch)2320 void DebuggerGDB::ExpandWatch(cb_unused cb::shared_ptr<cbWatch> watch) // TODO: shouldn't this do something?
2321 {
2322 }
2323 
CollapseWatch(cb_unused cb::shared_ptr<cbWatch> watch)2324 void DebuggerGDB::CollapseWatch(cb_unused cb::shared_ptr<cbWatch> watch)
2325 {
2326 }
2327 
UpdateWatch(cb::shared_ptr<cbWatch> watch)2328 void DebuggerGDB::UpdateWatch(cb::shared_ptr<cbWatch> watch)
2329 {
2330     DebuggerDriver *driver = m_State.GetDriver();
2331     if (driver == nullptr)
2332         return;
2333 
2334     if (watch == m_localsWatch)
2335         driver->UpdateWatchLocalsArgs(cb::static_pointer_cast<GDBWatch>(watch), true);
2336     else if (watch == m_funcArgsWatch)
2337         driver->UpdateWatchLocalsArgs(cb::static_pointer_cast<GDBWatch>(watch), false);
2338     else
2339     {
2340         MapWatchesToType::const_iterator itType = m_mapWatchesToType.find(watch);
2341         if (itType == m_mapWatchesToType.end())
2342             return;
2343         const WatchType type = itType->second;
2344         switch (type)
2345         {
2346         case WatchType::Normal:
2347             driver->UpdateWatch(cb::static_pointer_cast<GDBWatch>(watch));
2348             break;
2349         case WatchType::MemoryRange:
2350             driver->UpdateMemoryRangeWatch(cb::static_pointer_cast<GDBMemoryRangeWatch>(watch));
2351             break;
2352         }
2353     }
2354 }
2355 
UpdateWatches(const std::vector<cb::shared_ptr<cbWatch>> & watches)2356 void DebuggerGDB::UpdateWatches(const std::vector<cb::shared_ptr<cbWatch>> &watches)
2357 {
2358     if (!m_State.HasDriver())
2359         return;
2360 
2361     WatchesContainer normalWatches;
2362     MemoryRangeWatchesContainer memoryRanges;
2363 
2364     cb::shared_ptr<GDBWatch> localsToUpdate, funcArgsToUpdate;
2365 
2366     for (const cb::shared_ptr<cbWatch> &watch : watches)
2367     {
2368         if (watch == m_localsWatch)
2369         {
2370             localsToUpdate = m_localsWatch;
2371             continue;
2372         }
2373         if (watch == m_funcArgsWatch)
2374         {
2375             funcArgsToUpdate = m_funcArgsWatch;
2376             continue;
2377         }
2378 
2379         MapWatchesToType::const_iterator itType = m_mapWatchesToType.find(watch);
2380         if (itType == m_mapWatchesToType.end())
2381             continue;
2382 
2383         const WatchType type = itType->second;
2384         switch (type)
2385         {
2386         case WatchType::Normal:
2387             normalWatches.push_back(cb::static_pointer_cast<GDBWatch>(watch));
2388             break;
2389         case WatchType::MemoryRange:
2390             memoryRanges.push_back(cb::static_pointer_cast<GDBMemoryRangeWatch>(watch));
2391             break;
2392         }
2393     }
2394 
2395     if (!normalWatches.empty())
2396         m_State.GetDriver()->UpdateWatches(localsToUpdate, funcArgsToUpdate, normalWatches, true);
2397     if (!memoryRanges.empty())
2398         m_State.GetDriver()->UpdateMemoryRangeWatches(memoryRanges, true);
2399 }
2400 
MarkAllWatchesAsUnchanged()2401 void DebuggerGDB::MarkAllWatchesAsUnchanged()
2402 {
2403     if (m_localsWatch)
2404         m_localsWatch->MarkAsChangedRecursive(false);
2405     if (m_funcArgsWatch)
2406         m_funcArgsWatch->MarkAsChangedRecursive(false);
2407 
2408     for (WatchesContainer::iterator it = m_watches.begin(); it != m_watches.end(); ++it)
2409         (*it)->MarkAsChangedRecursive(false);
2410 }
2411 
OnWatchesContextMenu(wxMenu & menu,const cbWatch & watch,wxObject * property,int & disabledMenus)2412 void DebuggerGDB::OnWatchesContextMenu(wxMenu &menu, const cbWatch &watch, wxObject *property, int &disabledMenus)
2413 {
2414     wxString type, symbol;
2415     watch.GetType(type);
2416     watch.GetSymbol(symbol);
2417 
2418     if (IsPointerType(type))
2419     {
2420         menu.InsertSeparator(0);
2421         menu.Insert(0, idMenuWatchDereference, _("Dereference ") + symbol);
2422         m_watchToDereferenceSymbol = symbol;
2423         m_watchToDereferenceProperty = property;
2424     }
2425 
2426     if (watch.GetParent())
2427     {
2428         disabledMenus = WatchesDisabledMenuItems::Rename;
2429         disabledMenus |= WatchesDisabledMenuItems::Properties;
2430         disabledMenus |= WatchesDisabledMenuItems::Delete;
2431         disabledMenus |= WatchesDisabledMenuItems::AddDataBreak;
2432         disabledMenus |= WatchesDisabledMenuItems::ExamineMemory;
2433     }
2434 }
2435 
OnMenuWatchDereference(cb_unused wxCommandEvent & event)2436 void DebuggerGDB::OnMenuWatchDereference(cb_unused wxCommandEvent& event)
2437 {
2438     cbWatchesDlg *watches = Manager::Get()->GetDebuggerManager()->GetWatchesDialog();
2439     if (!watches)
2440         return;
2441 
2442     watches->RenameWatch(m_watchToDereferenceProperty, wxT("*") + m_watchToDereferenceSymbol);
2443     m_watchToDereferenceProperty = NULL;
2444     m_watchToDereferenceSymbol = wxEmptyString;
2445 }
2446 
AttachToProcess(const wxString & pid)2447 void DebuggerGDB::AttachToProcess(const wxString& pid)
2448 {
2449     if (!pid.IsEmpty())
2450     {
2451         pid.ToLong((long*)&m_PidToAttach);
2452         Debug(false);
2453     }
2454 }
2455 
DetachFromProcess()2456 void DebuggerGDB::DetachFromProcess()
2457 {
2458     m_State.GetDriver()->Detach();
2459     m_PidToAttach = 0;
2460     m_State.GetDriver()->Stop();
2461 }
2462 
IsAttachedToProcess() const2463 bool DebuggerGDB::IsAttachedToProcess() const
2464 {
2465     return m_PidToAttach != 0;
2466 }
2467 
CompilerFinished(bool compilerFailed,StartType startType)2468 bool DebuggerGDB::CompilerFinished(bool compilerFailed, StartType startType)
2469 {
2470     if (compilerFailed || startType == StartTypeUnknown)
2471         return false;
2472     if (DoDebug(startType == StartTypeStepInto) != 0)
2473         return false;
2474     return true;
2475 }
2476 
OnBuildTargetSelected(CodeBlocksEvent & event)2477 void DebuggerGDB::OnBuildTargetSelected(CodeBlocksEvent& event)
2478 {
2479     // verify that the project that sent it, is the one we 're debugging
2480     // and that a project is loaded
2481     if (m_pProject && event.GetProject() == m_pProject)
2482         m_ActiveBuildTarget = event.GetBuildTargetName();
2483 }
2484 
DetermineLanguage()2485 void DebuggerGDB::DetermineLanguage()
2486 {
2487     if (m_State.HasDriver())
2488         m_State.GetDriver()->DetermineLanguage();
2489 }
2490