1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  *
5  * $Revision: 11770 $
6  * $Id: debuggermanager.cpp 11770 2019-07-04 22:15:32Z fuscated $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/sdk/debuggermanager.cpp $
8  */
9 
10 #include "sdk_precomp.h"
11 #ifndef CB_PRECOMP
12     #include <wx/artprov.h>
13     #include <wx/bmpbuttn.h>
14     #include <wx/combobox.h>
15     #include <wx/filedlg.h>
16     #include <wx/frame.h>
17     #include <wx/menu.h>
18     #include <wx/settings.h>
19     #include <wx/sizer.h>
20     #include <wx/stattext.h>
21     #include <wx/regex.h>
22 
23     #include "cbeditor.h"
24     #include "cbexception.h"
25     #include "cbplugin.h"
26     #include "cbproject.h"
27     #include "compilerfactory.h"
28     #include "configmanager.h"
29     #include "editormanager.h"
30     #include "logmanager.h"
31     #include "projectmanager.h"
32 #endif
33 
34 #include <algorithm>
35 #include <sstream>
36 #include <wx/toolbar.h>
37 
38 #include "debuggermanager.h"
39 
40 #include "annoyingdialog.h"
41 #include "cbdebugger_interfaces.h"
42 #include "loggers.h"
43 #include "manager.h"
44 
cbWatch()45 cbWatch::cbWatch() :
46     m_changed(true),
47     m_removed(false),
48     m_expanded(false),
49     m_autoUpdate(true)
50 {
51 }
52 
~cbWatch()53 cbWatch::~cbWatch()
54 {
55     m_children.clear();
56 }
57 
AddChild(cb::shared_ptr<cbWatch> parent,cb::shared_ptr<cbWatch> watch)58 void cbWatch::AddChild(cb::shared_ptr<cbWatch> parent, cb::shared_ptr<cbWatch> watch)
59 {
60     watch->m_parent = parent;
61     parent->m_children.push_back(watch);
62 }
63 
RemoveChild(int index)64 void cbWatch::RemoveChild(int index)
65 {
66     std::vector<cb::shared_ptr<cbWatch> >::iterator it = m_children.begin();
67     std::advance(it, index);
68     m_children.erase(it);
69 }
70 
TestIfMarkedForRemoval(cb::shared_ptr<cbWatch> watch)71 inline bool TestIfMarkedForRemoval(cb::shared_ptr<cbWatch> watch)
72 {
73     if(watch->IsRemoved())
74         return true;
75     else
76     {
77         watch->RemoveMarkedChildren();
78         return false;
79     }
80 }
81 
RemoveMarkedChildren()82 bool cbWatch::RemoveMarkedChildren()
83 {
84     size_t start_size = m_children.size();
85     std::vector<cb::shared_ptr<cbWatch> >::iterator new_last;
86     new_last = std::remove_if(m_children.begin(), m_children.end(), &TestIfMarkedForRemoval);
87     m_children.erase(new_last, m_children.end());
88 
89     return start_size != m_children.size();
90 
91 }
RemoveChildren()92 void cbWatch::RemoveChildren()
93 {
94     m_children.clear();
95 }
96 
GetChildCount() const97 int cbWatch::GetChildCount() const
98 {
99     return m_children.size();
100 }
101 
GetChild(int index)102 cb::shared_ptr<cbWatch> cbWatch::GetChild(int index)
103 {
104     std::vector<cb::shared_ptr<cbWatch> >::iterator it = m_children.begin();
105     std::advance(it, index);
106     return *it;
107 }
108 
GetChild(int index) const109 cb::shared_ptr<const cbWatch> cbWatch::GetChild(int index) const
110 {
111     std::vector<cb::shared_ptr<cbWatch> >::const_iterator it = m_children.begin();
112     std::advance(it, index);
113     return *it;
114 }
115 
FindChild(const wxString & symbol)116 cb::shared_ptr<cbWatch> cbWatch::FindChild(const wxString& symbol)
117 {
118     for (std::vector<cb::shared_ptr<cbWatch> >::iterator it = m_children.begin(); it != m_children.end(); ++it)
119     {
120         wxString s;
121         (*it)->GetSymbol(s);
122         if(s == symbol)
123             return *it;
124     }
125     return cb::shared_ptr<cbWatch>();
126 }
127 
FindChildIndex(const wxString & symbol) const128 int cbWatch::FindChildIndex(const wxString& symbol) const
129 {
130     int index = 0;
131     for (std::vector<cb::shared_ptr<cbWatch> >::const_iterator it = m_children.begin();
132          it != m_children.end();
133          ++it, ++index)
134     {
135         wxString s;
136         (*it)->GetSymbol(s);
137         if(s == symbol)
138             return index;
139     }
140     return -1;
141 }
142 
GetParent() const143 cb::shared_ptr<const cbWatch> cbWatch::GetParent() const
144 {
145     return m_parent.lock();
146 }
147 
GetParent()148 cb::shared_ptr<cbWatch> cbWatch::GetParent()
149 {
150     return m_parent.lock();
151 }
152 
IsRemoved() const153 bool cbWatch::IsRemoved() const
154 {
155     return m_removed;
156 }
157 
IsChanged() const158 bool cbWatch::IsChanged() const
159 {
160     return m_changed;
161 }
162 
MarkAsRemoved(bool flag)163 void cbWatch::MarkAsRemoved(bool flag)
164 {
165     m_removed = flag;
166 }
167 
MarkChildsAsRemoved()168 void cbWatch::MarkChildsAsRemoved()
169 {
170     for(std::vector<cb::shared_ptr<cbWatch> >::iterator it = m_children.begin(); it != m_children.end(); ++it)
171         (*it)->MarkAsRemoved(true);
172 }
MarkAsChanged(bool flag)173 void cbWatch::MarkAsChanged(bool flag)
174 {
175     m_changed = flag;
176 }
177 
MarkAsChangedRecursive(bool flag)178 void cbWatch::MarkAsChangedRecursive(bool flag)
179 {
180     m_changed = flag;
181     for(std::vector<cb::shared_ptr<cbWatch> >::iterator it = m_children.begin(); it != m_children.end(); ++it)
182         (*it)->MarkAsChangedRecursive(flag);
183 }
184 
IsExpanded() const185 bool cbWatch::IsExpanded() const
186 {
187     return m_expanded;
188 }
189 
Expand(bool expand)190 void cbWatch::Expand(bool expand)
191 {
192     m_expanded = expand;
193 }
194 
IsAutoUpdateEnabled() const195 bool cbWatch::IsAutoUpdateEnabled() const
196 {
197     return m_autoUpdate;
198 }
199 
AutoUpdate(bool enabled)200 void cbWatch::AutoUpdate(bool enabled)
201 {
202     m_autoUpdate = enabled;
203 }
204 
MakeSymbolToAddress() const205 wxString cbWatch::MakeSymbolToAddress() const
206 {
207     wxString symbol;
208     GetSymbol(symbol);
209     return symbol;
210 }
211 
IsPointerType() const212 bool cbWatch::IsPointerType() const
213 {
214     return false;
215 }
216 
cbGetRootWatch(cb::shared_ptr<cbWatch> watch)217 cb::shared_ptr<cbWatch> DLLIMPORT cbGetRootWatch(cb::shared_ptr<cbWatch> watch)
218 {
219     cb::shared_ptr<cbWatch> root = watch;
220     while (root)
221     {
222         cb::shared_ptr<cbWatch> parent = root->GetParent();
223         if (!parent)
224             break;
225         root = parent;
226     }
227     return root;
228 }
229 
cbStackFrame()230 cbStackFrame::cbStackFrame() :
231     m_valid(false)
232 {
233 }
234 
SetNumber(int number)235 void cbStackFrame::SetNumber(int number)
236 {
237     m_number = number;
238 }
239 
SetAddress(uint64_t address)240 void cbStackFrame::SetAddress(uint64_t address)
241 {
242     m_address = address;
243 }
244 
SetSymbol(const wxString & symbol)245 void cbStackFrame::SetSymbol(const wxString& symbol)
246 {
247     m_symbol = symbol;
248 }
249 
SetFile(const wxString & filename,const wxString & line)250 void cbStackFrame::SetFile(const wxString& filename, const wxString &line)
251 {
252     m_file = filename;
253     m_line = line;
254 }
255 
MakeValid(bool flag)256 void cbStackFrame::MakeValid(bool flag)
257 {
258     m_valid = flag;
259 }
260 
GetNumber() const261 int cbStackFrame::GetNumber() const
262 {
263     return m_number;
264 }
265 
GetAddress() const266 uint64_t cbStackFrame::GetAddress() const
267 {
268     return m_address;
269 }
270 
GetAddressAsString() const271 wxString cbStackFrame::GetAddressAsString() const
272 {
273     if(m_address!=0)
274         return cbDebuggerAddressToString(m_address);
275     else
276         return wxEmptyString;
277 }
278 
GetSymbol() const279 const wxString& cbStackFrame::GetSymbol() const
280 {
281     return m_symbol;
282 }
283 
GetFilename() const284 const wxString& cbStackFrame::GetFilename() const
285 {
286     return m_file;
287 }
288 
GetLine() const289 const wxString& cbStackFrame::GetLine() const
290 {
291     return m_line;
292 }
293 
IsValid() const294 bool cbStackFrame::IsValid() const
295 {
296     return m_valid;
297 }
298 
cbThread()299 cbThread::cbThread()
300 {
301 }
302 
cbThread(bool active,int number,const wxString & info)303 cbThread::cbThread(bool active, int number, const wxString& info)
304 {
305     m_active = active;
306     m_number = number;
307     m_info = info;
308 }
309 
IsActive() const310 bool cbThread::IsActive() const
311 {
312     return m_active;
313 }
314 
GetNumber() const315 int cbThread::GetNumber() const
316 {
317     return m_number;
318 }
319 
GetInfo() const320 const wxString& cbThread::GetInfo() const
321 {
322     return m_info;
323 }
324 
cbDebuggerConfiguration(const ConfigManagerWrapper & config)325 cbDebuggerConfiguration::cbDebuggerConfiguration(const ConfigManagerWrapper &config) :
326     m_config(config),
327     m_menuId(wxID_ANY)
328 {
329 }
330 
cbDebuggerConfiguration(const cbDebuggerConfiguration & o)331 cbDebuggerConfiguration::cbDebuggerConfiguration(const cbDebuggerConfiguration &o) :
332     m_config(o.m_config),
333     m_name(o.m_name)
334 {
335 }
336 
SetName(const wxString & name)337 void cbDebuggerConfiguration::SetName(const wxString &name)
338 {
339     m_name = name;
340 }
GetName() const341 const wxString& cbDebuggerConfiguration::GetName() const
342 {
343     return m_name;
344 }
345 
GetConfig() const346 const ConfigManagerWrapper& cbDebuggerConfiguration::GetConfig() const
347 {
348     return m_config;
349 }
350 
SetConfig(const ConfigManagerWrapper & config)351 void cbDebuggerConfiguration::SetConfig(const ConfigManagerWrapper &config)
352 {
353     m_config = config;
354 }
355 
SetMenuId(long id)356 void cbDebuggerConfiguration::SetMenuId(long id)
357 {
358     m_menuId = id;
359 }
360 
GetMenuId() const361 long cbDebuggerConfiguration::GetMenuId() const
362 {
363     return m_menuId;
364 }
365 
GetFlag(Flags flag)366 bool cbDebuggerCommonConfig::GetFlag(Flags flag)
367 {
368     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
369     switch (flag)
370     {
371         case AutoBuild:
372             return c->ReadBool(wxT("/common/auto_build"), true);
373         case AutoSwitchFrame:
374             return c->ReadBool(wxT("/common/auto_switch_frame"), true);
375         case ShowDebuggersLog:
376             return c->ReadBool(wxT("/common/debug_log"), false);
377         case JumpOnDoubleClick:
378             return c->ReadBool(wxT("/common/jump_on_double_click"), false);
379         case RequireCtrlForTooltips:
380             return c->ReadBool(wxT("/common/require_ctrl_for_tooltips"), false);
381         case ShowTemporaryBreakpoints:
382             return c->ReadBool(wxT("/common/show_temporary_breakpoints"), false);
383         default:
384             return false;
385     }
386 }
387 
SetFlag(Flags flag,bool value)388 void cbDebuggerCommonConfig::SetFlag(Flags flag, bool value)
389 {
390     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
391     switch (flag)
392     {
393         case AutoBuild:
394             c->Write(wxT("/common/auto_build"), value);
395             break;
396         case AutoSwitchFrame:
397             c->Write(wxT("/common/auto_switch_frame"), value);
398             break;
399         case ShowDebuggersLog:
400             c->Write(wxT("/common/debug_log"), value);
401             break;
402         case JumpOnDoubleClick:
403             c->Write(wxT("/common/jump_on_double_click"), value);
404             break;
405         case RequireCtrlForTooltips:
406             c->Write(wxT("/common/require_ctrl_for_tooltips"), value);
407             break;
408         case ShowTemporaryBreakpoints:
409             c->Write(wxT("/common/show_temporary_breakpoints"), value);
410         default:
411             ;
412     }
413 }
414 
GetValueTooltipFont()415 wxString cbDebuggerCommonConfig::GetValueTooltipFont()
416 {
417     wxFont system = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
418     system.SetPointSize(std::max(system.GetPointSize() - 3, 7));
419     wxString defaultFont = system.GetNativeFontInfo()->ToString();
420 
421     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
422     wxString configFont = c->Read(wxT("/common/tooltip_font"));
423 
424     return configFont.empty() ? defaultFont : configFont;
425 }
426 
SetValueTooltipFont(const wxString & font)427 void cbDebuggerCommonConfig::SetValueTooltipFont(const wxString &font)
428 {
429     const wxString &oldFont = GetValueTooltipFont();
430 
431     if (font != oldFont && !font.empty())
432     {
433         ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
434         c->Write(wxT("/common/tooltip_font"), font);
435     }
436 }
437 
GetPerspective()438 cbDebuggerCommonConfig::Perspective cbDebuggerCommonConfig::GetPerspective()
439 {
440     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
441     int v = c->ReadInt(wxT("/common/perspective"), static_cast<int>(OnePerDebuggerConfig));
442     if (v < OnlyOne || v > OnePerDebuggerConfig)
443         return OnePerDebuggerConfig;
444     return static_cast<Perspective>(v);
445 }
446 
SetPerspective(int perspective)447 void cbDebuggerCommonConfig::SetPerspective(int perspective)
448 {
449     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
450     if (perspective < OnlyOne || perspective > OnePerDebuggerConfig)
451         perspective = OnePerDebuggerConfig;
452     c->Write(wxT("/common/perspective"), perspective);
453 }
454 
cbDetectDebuggerExecutable(const wxString & exeName)455 wxString cbDetectDebuggerExecutable(const wxString &exeName)
456 {
457     wxString exeExt(platform::windows ? wxT(".exe") : wxEmptyString);
458     wxString exePath = cbFindFileInPATH(exeName);
459     wxChar sep = wxFileName::GetPathSeparator();
460 
461     if (exePath.empty())
462     {
463         if (!platform::windows)
464             exePath = wxT("/usr/bin/") + exeName + exeExt;
465         else
466         {
467             const wxString &cbInstallFolder = ConfigManager::GetExecutableFolder();
468             if (wxFileExists(cbInstallFolder + sep + wxT("MINGW") + sep + wxT("bin") + sep + exeName + exeExt))
469                 exePath = cbInstallFolder + sep + wxT("MINGW") + sep + wxT("bin");
470             else
471             {
472                 exePath = wxT("C:\\MinGW\\bin");
473                 if (!wxDirExists(exePath))
474                     exePath = wxT("C:\\MinGW32\\bin");
475             }
476         }
477     }
478     if (!wxDirExists(exePath))
479         return wxEmptyString;
480     return exePath + wxFileName::GetPathSeparator() + exeName + exeExt;
481 }
482 
cbDebuggerStringToAddress(const wxString & address)483 uint64_t cbDebuggerStringToAddress(const wxString &address)
484 {
485     if (address.empty())
486         return 0;
487     std::istringstream s(address.utf8_str().data());
488     uint64_t result;
489     s >> std::hex >> result;
490     return (s.fail() ? 0 : result);
491 }
492 
cbDebuggerAddressToString(uint64_t address)493 wxString cbDebuggerAddressToString(uint64_t address)
494 {
495     std::stringstream s;
496     s << "0x" << std::hex << address;
497     return wxString(s.str().c_str(), wxConvUTF8);
498 }
499 
500 class DebugTextCtrlLogger : public TextCtrlLogger
501 {
502 public:
DebugTextCtrlLogger(bool fixedPitchFont,bool debugLog)503     DebugTextCtrlLogger(bool fixedPitchFont, bool debugLog) :
504         TextCtrlLogger(fixedPitchFont),
505         m_panel(nullptr),
506         m_debugLog(debugLog)
507     {
508     }
509 
CreateTextCtrl(wxWindow * parent)510     wxWindow* CreateTextCtrl(wxWindow *parent)
511     {
512         return TextCtrlLogger::CreateControl(parent);
513     }
514 
515     wxWindow* CreateControl(wxWindow* parent) override;
516 
517 private:
518     wxPanel *m_panel;
519     bool    m_debugLog;
520 };
521 
522 class DebugLogPanel : public wxPanel
523 {
524 public:
DebugLogPanel(wxWindow * parent,DebugTextCtrlLogger * text_control_logger,bool debug_log)525     DebugLogPanel(wxWindow *parent, DebugTextCtrlLogger *text_control_logger, bool debug_log) :
526         wxPanel(parent),
527         m_text_control_logger(text_control_logger),
528         m_debug_log(debug_log)
529     {
530         int idDebug_LogEntryControl = wxNewId();
531         int idDebug_ExecuteButton = wxNewId();
532         int idDebug_ClearButton = wxNewId();
533         int idDebug_LoadButton = wxNewId();
534 
535         wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
536         wxBoxSizer *control_sizer = new wxBoxSizer(wxHORIZONTAL);
537 
538         wxWindow *text_control = text_control_logger->CreateTextCtrl(this);
539         sizer->Add(text_control, wxEXPAND, wxEXPAND | wxALL , 0);
540         sizer->Add(control_sizer, 0, wxEXPAND | wxALL, 0);
541 
542         wxStaticText *label = new wxStaticText(this, wxID_ANY, _T("Command:"),
543                                                wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE);
544 
545         m_command_entry = new wxComboBox(this, idDebug_LogEntryControl, wxEmptyString,
546                                          wxDefaultPosition, wxDefaultSize, 0, nullptr,
547                                          wxCB_DROPDOWN | wxTE_PROCESS_ENTER);
548 
549         wxBitmap execute_bitmap = wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_EXECUTABLE_FILE")),
550                                                            wxART_BUTTON);
551         wxBitmap clear_bitmap = wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_DELETE")),wxART_BUTTON);
552         wxBitmap file_open_bitmap =wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_FILE_OPEN")),
553                                                             wxART_BUTTON);
554 
555         wxBitmapButton *button_execute;
556         button_execute = new wxBitmapButton(this, idDebug_ExecuteButton, execute_bitmap, wxDefaultPosition,
557                                             wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator,
558                                             _T("idDebug_ExecuteButton"));
559         button_execute->SetToolTip(_("Execute current command"));
560 
561         wxBitmapButton *button_load = new wxBitmapButton(this, idDebug_LoadButton, file_open_bitmap, wxDefaultPosition,
562                                                          wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator,
563                                                          _T("idDebug_LoadButton"));
564         button_load->SetDefault();
565         button_load->SetToolTip(_("Load from file"));
566 
567         wxBitmapButton *button_clear = new wxBitmapButton(this, idDebug_ClearButton, clear_bitmap, wxDefaultPosition,
568                                                           wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator,
569                                                           _T("idDebug_ClearButton"));
570         button_clear->SetDefault();
571         button_clear->SetToolTip(_("Clear output window"));
572 
573         control_sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 2);
574         control_sizer->Add(m_command_entry, wxEXPAND, wxEXPAND | wxALL, 2);
575         control_sizer->Add(button_execute, 0, wxEXPAND | wxALL, 0);
576         control_sizer->Add(button_load, 0, wxALL|wxALIGN_CENTER_VERTICAL, 0);
577         control_sizer->Add(button_clear, 0, wxALL|wxALIGN_CENTER_VERTICAL, 0);
578 
579         SetSizer(sizer);
580 
581         Connect(idDebug_LogEntryControl,
582                 wxEVT_COMMAND_TEXT_ENTER,
583                 wxObjectEventFunction(&DebugLogPanel::OnEntryCommand));
584         Connect(idDebug_ExecuteButton,
585                 wxEVT_COMMAND_BUTTON_CLICKED,
586                 wxObjectEventFunction(&DebugLogPanel::OnEntryCommand));
587         Connect(idDebug_ClearButton,
588                 wxEVT_COMMAND_BUTTON_CLICKED,
589                 wxObjectEventFunction(&DebugLogPanel::OnClearLog));
590         Connect(idDebug_LoadButton,
591                 wxEVT_COMMAND_BUTTON_CLICKED,
592                 wxObjectEventFunction(&DebugLogPanel::OnLoadFile));
593 
594         // UpdateUI events
595         Connect(idDebug_ExecuteButton,
596                 wxEVT_UPDATE_UI,
597                 wxObjectEventFunction(&DebugLogPanel::OnUpdateUI));
598         Connect(idDebug_LoadButton,
599                 wxEVT_UPDATE_UI,
600                 wxObjectEventFunction(&DebugLogPanel::OnUpdateUI));
601         Connect(idDebug_LogEntryControl,
602                 wxEVT_UPDATE_UI,
603                 wxObjectEventFunction(&DebugLogPanel::OnUpdateUI));
604     }
605 
OnEntryCommand(cb_unused wxCommandEvent & event)606     void OnEntryCommand(cb_unused wxCommandEvent& event)
607     {
608         assert(m_command_entry);
609         wxString cmd = m_command_entry->GetValue();
610         cmd.Trim(false);
611         cmd.Trim(true);
612 
613         if (cmd.IsEmpty())
614             return;
615         cbDebuggerPlugin *plugin = Manager::Get()->GetDebuggerManager()->GetActiveDebugger();
616         if (plugin)
617         {
618             plugin->SendCommand(cmd, m_debug_log);
619 
620             // If it already exists in the list, remove it and add it as the first element of the wxComboBox list
621             int index = m_command_entry->FindString(cmd);
622             if (index != wxNOT_FOUND)
623                 m_command_entry->Delete(index);
624             m_command_entry->Insert(cmd, 0);
625 
626             m_command_entry->SetValue(wxEmptyString);
627         }
628     }
629 
OnClearLog(cb_unused wxCommandEvent & event)630     void OnClearLog(cb_unused wxCommandEvent& event)
631     {
632         assert(m_command_entry);
633         assert(m_text_control_logger);
634         m_text_control_logger->Clear();
635         m_command_entry->SetFocus();
636     }
637 
OnLoadFile(cb_unused wxCommandEvent & event)638     void OnLoadFile(cb_unused wxCommandEvent& event)
639     {
640         cbDebuggerPlugin *plugin = Manager::Get()->GetDebuggerManager()->GetActiveDebugger();
641         if (!plugin)
642             return;
643 
644         ConfigManager* manager = Manager::Get()->GetConfigManager(_T("app"));
645         wxString path = manager->Read(_T("/file_dialogs/file_run_dbg_script/directory"), wxEmptyString);
646 
647         wxFileDialog dialog(this, _("Load script"), path, wxEmptyString,
648                             _T("Debugger script files (*.gdb)|*.gdb"), wxFD_OPEN | compatibility::wxHideReadonly);
649 
650         if (dialog.ShowModal() == wxID_OK)
651         {
652             manager->Write(_T("/file_dialogs/file_run_dbg_script/directory"), dialog.GetDirectory());
653 
654             plugin->SendCommand(_T("source ") + dialog.GetPath(), m_debug_log);
655         }
656     }
657 
OnUpdateUI(wxUpdateUIEvent & event)658     void OnUpdateUI(wxUpdateUIEvent &event)
659     {
660         cbDebuggerPlugin *plugin = Manager::Get()->GetDebuggerManager()->GetActiveDebugger();
661         event.Enable(plugin && plugin->IsRunning() && plugin->IsStopped());
662     }
663 private:
664     DebugTextCtrlLogger *m_text_control_logger;
665     wxComboBox  *m_command_entry;
666     bool m_debug_log;
667 };
668 
CreateControl(wxWindow * parent)669 wxWindow* DebugTextCtrlLogger::CreateControl(wxWindow* parent)
670 {
671     if(!m_panel)
672         m_panel = new DebugLogPanel(parent, this, m_debugLog);
673 
674     return m_panel;
675 }
676 
677 template<> DebuggerManager* Mgr<DebuggerManager>::instance = nullptr;
678 template<> bool  Mgr<DebuggerManager>::isShutdown = false;
679 
ReadActiveDebuggerConfig(wxString & name,int & configIndex)680 inline void ReadActiveDebuggerConfig(wxString &name, int &configIndex)
681 {
682     ConfigManager &config = *Manager::Get()->GetConfigManager(_T("debugger_common"));
683     name = config.Read(wxT("active_debugger"), wxEmptyString);
684     if (name.empty())
685         configIndex = -1;
686     else
687         configIndex = std::max(0, config.ReadInt(wxT("active_debugger_config"), 0));
688 }
689 
WriteActiveDebuggerConfig(const wxString & name,int configIndex)690 inline void WriteActiveDebuggerConfig(const wxString &name, int configIndex)
691 {
692     ConfigManager &configMgr = *Manager::Get()->GetConfigManager(_T("debugger_common"));
693     configMgr.Write(wxT("active_debugger"), name);
694     configMgr.Write(wxT("active_debugger_config"), configIndex);
695 }
696 
GetConfiguration(int index)697 cbDebuggerConfiguration* DebuggerManager::PluginData::GetConfiguration(int index)
698 {
699     if (m_configurations.empty())
700         cbAssert(false);
701     if (index >= static_cast<int>(m_configurations.size()))
702         return nullptr;
703     else
704         return m_configurations[index];
705 }
706 
DebuggerManager()707 DebuggerManager::DebuggerManager() :
708     m_interfaceFactory(nullptr),
709     m_activeDebugger(nullptr),
710     m_menuHandler(nullptr),
711     m_backtraceDialog(nullptr),
712     m_breakPointsDialog(nullptr),
713     m_cpuRegistersDialog(nullptr),
714     m_disassemblyDialog(nullptr),
715     m_examineMemoryDialog(nullptr),
716     m_threadsDialog(nullptr),
717     m_watchesDialog(nullptr),
718     m_logger(nullptr),
719     m_loggerIndex(-1),
720     m_isDisassemblyMixedMode(false),
721     m_useTargetsDefault(false)
722 {
723     typedef cbEventFunctor<DebuggerManager, CodeBlocksEvent> Event;
724     Manager::Get()->RegisterEventSink(cbEVT_PROJECT_ACTIVATE,        new Event(this, &DebuggerManager::OnProjectActivated));
725     // connect with cbEVT_PROJECT_OPEN, too (see here: http://forums.codeblocks.org/index.php/topic,17260.msg118431.html#msg118431)
726     Manager::Get()->RegisterEventSink(cbEVT_PROJECT_OPEN,            new Event(this, &DebuggerManager::OnProjectActivated));
727     Manager::Get()->RegisterEventSink(cbEVT_BUILDTARGET_SELECTED,    new Event(this, &DebuggerManager::OnTargetSelected));
728     Manager::Get()->RegisterEventSink(cbEVT_SETTINGS_CHANGED,        new Event(this, &DebuggerManager::OnSettingsChanged));
729     Manager::Get()->RegisterEventSink(cbEVT_PLUGIN_LOADING_COMPLETE, new Event(this, &DebuggerManager::OnPluginLoadingComplete));
730 
731     wxString activeDebuggerName;
732     int activeConfig;
733     ReadActiveDebuggerConfig(activeDebuggerName, activeConfig);
734     if (activeDebuggerName.empty() && activeConfig == -1)
735         m_useTargetsDefault = true;
736 
737     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
738     m_isDisassemblyMixedMode = c->ReadBool(wxT("/common/disassembly/mixed_mode"), false);
739 
740 }
741 
~DebuggerManager()742 DebuggerManager::~DebuggerManager()
743 {
744     for (RegisteredPlugins::iterator it = m_registered.begin(); it != m_registered.end(); ++it)
745         it->second.ClearConfigurations();
746 
747     Manager::Get()->RemoveAllEventSinksFor(this);
748     delete m_interfaceFactory;
749 }
750 
RegisterDebugger(cbDebuggerPlugin * plugin)751 bool DebuggerManager::RegisterDebugger(cbDebuggerPlugin *plugin)
752 {
753     RegisteredPlugins::iterator it = m_registered.find(plugin);
754     if (it != m_registered.end())
755         return false;
756     const wxString &guiName=plugin->GetGUIName();
757     const wxString &settingsName=plugin->GetSettingsName();
758 
759     wxRegEx regExSettingsName(wxT("^[a-z_][a-z0-9_]+$"));
760     if (!regExSettingsName.Matches(settingsName))
761     {
762         wxString s;
763         s = wxString::Format(_("The settings name for the debugger plugin \"%s\" - \"%s\" contains invalid characters"),
764                              guiName.c_str(), settingsName.c_str());
765         Manager::Get()->GetLogManager()->LogError(s);
766         return false;
767     }
768 
769     int normalIndex = -1;
770     GetLogger(normalIndex);
771     plugin->SetupLog(normalIndex);
772 
773     PluginData data;
774 
775     m_registered[plugin] = data;
776     it = m_registered.find(plugin);
777     ProcessSettings(it);
778 
779     // There should be at least one configuration for every plugin.
780     // If this is not the case, something is wrong and should be fixed.
781     cbAssert(!it->second.GetConfigurations().empty());
782 
783     wxString activeDebuggerName;
784     int activeConfig;
785     ReadActiveDebuggerConfig(activeDebuggerName, activeConfig);
786 
787     if (activeDebuggerName == settingsName)
788     {
789         if (activeConfig > static_cast<int>(it->second.GetConfigurations().size()))
790             activeConfig = 0;
791 
792         m_activeDebugger = plugin;
793         m_activeDebugger->SetActiveConfig(activeConfig);
794 
795         m_menuHandler->SetActiveDebugger(m_activeDebugger);
796     }
797 
798     CreateWindows();
799     m_menuHandler->RebuildMenus();
800 
801     return true;
802 }
803 
UnregisterDebugger(cbDebuggerPlugin * plugin)804 bool DebuggerManager::UnregisterDebugger(cbDebuggerPlugin *plugin)
805 {
806     RegisteredPlugins::iterator it = m_registered.find(plugin);
807     if(it == m_registered.end())
808         return false;
809 
810     it->second.ClearConfigurations();
811     m_registered.erase(it);
812     if (plugin == m_activeDebugger)
813     {
814         if (m_registered.empty())
815             m_activeDebugger = nullptr;
816         else
817             m_activeDebugger = m_registered.begin()->first;
818         m_menuHandler->SetActiveDebugger(m_activeDebugger);
819     }
820     if (!Manager::IsAppShuttingDown())
821     {
822         m_menuHandler->RebuildMenus();
823         RefreshUI();
824     }
825 
826     if (m_registered.empty())
827     {
828         DestoryWindows();
829 
830         if (Manager::Get()->GetLogManager())
831             Manager::Get()->GetDebuggerManager()->HideLogger();
832     }
833 
834     return true;
835 }
836 
ProcessSettings(RegisteredPlugins::iterator it)837 void DebuggerManager::ProcessSettings(RegisteredPlugins::iterator it)
838 {
839     cbDebuggerPlugin *plugin = it->first;
840     PluginData &data = it->second;
841     ConfigManager *config = Manager::Get()->GetConfigManager(wxT("debugger_common"));
842     wxString path = wxT("/sets/") + plugin->GetSettingsName();
843     wxArrayString configs = config->EnumerateSubPaths(path);
844     configs.Sort();
845 
846     if (configs.empty())
847     {
848         config->Write(path + wxT("/conf1/name"), wxString(wxT("Default")));
849         configs = config->EnumerateSubPaths(path);
850         configs.Sort();
851     }
852 
853     data.ClearConfigurations();
854     data.m_lastConfigID = -1;
855 
856     for (size_t jj = 0; jj < configs.Count(); ++jj)
857     {
858         wxString configPath = path + wxT("/") + configs[jj];
859         wxString name = config->Read(configPath + wxT("/name"));
860 
861         cbDebuggerConfiguration *pluginConfig;
862         pluginConfig = plugin->LoadConfig(ConfigManagerWrapper(wxT("debugger_common"), configPath + wxT("/values")));
863         if (pluginConfig)
864         {
865             pluginConfig->SetName(name);
866             data.GetConfigurations().push_back(pluginConfig);
867         }
868     }
869 }
870 
NewConfig(cbDebuggerPlugin * plugin,cb_unused const wxString & name)871 ConfigManagerWrapper DebuggerManager::NewConfig(cbDebuggerPlugin *plugin, cb_unused const wxString& name)
872 {
873     RegisteredPlugins::iterator it = m_registered.find(plugin);
874     if (it == m_registered.end())
875         return ConfigManagerWrapper();
876 
877     wxString path = wxT("/sets/") + it->first->GetSettingsName();
878 
879     if (it->second.m_lastConfigID == -1)
880     {
881         ConfigManager *config = Manager::Get()->GetConfigManager(wxT("debugger_common"));
882         wxArrayString configs = config->EnumerateSubPaths(path);
883         for (size_t ii = 0; ii < configs.GetCount(); ++ii)
884         {
885             long id;
886             if (configs[ii].Remove(0, 4).ToLong(&id))
887                 it->second.m_lastConfigID = std::max<long>(it->second.m_lastConfigID, id);
888         }
889     }
890 
891     path << wxT("/conf") << ++it->second.m_lastConfigID;
892 
893     return ConfigManagerWrapper(wxT("debugger_common"), path +  wxT("/values"));
894 }
895 
RebuildAllConfigs()896 void DebuggerManager::RebuildAllConfigs()
897 {
898     for (RegisteredPlugins::iterator it = m_registered.begin(); it != m_registered.end(); ++it)
899         ProcessSettings(it);
900     m_menuHandler->RebuildMenus();
901 }
902 
GetMenu()903 wxMenu* DebuggerManager::GetMenu()
904 {
905     wxMenuBar *menuBar = Manager::Get()->GetAppFrame()->GetMenuBar();
906     cbAssert(menuBar);
907     wxMenu *menu = NULL;
908 
909     int menu_pos = menuBar->FindMenu(_("&Debug"));
910 
911     if(menu_pos != wxNOT_FOUND)
912         menu = menuBar->GetMenu(menu_pos);
913 
914     if (!menu)
915     {
916         menu = Manager::Get()->LoadMenu(_T("debugger_menu"),true);
917 
918         // ok, now, where do we insert?
919         // three possibilities here:
920         // a) locate "Compile" menu and insert after it
921         // b) locate "Project" menu and insert after it
922         // c) if not found (?), insert at pos 5
923         int finalPos = 5;
924         int projcompMenuPos = menuBar->FindMenu(_("&Build"));
925         if (projcompMenuPos == wxNOT_FOUND)
926             projcompMenuPos = menuBar->FindMenu(_("&Compile"));
927 
928         if (projcompMenuPos != wxNOT_FOUND)
929             finalPos = projcompMenuPos + 1;
930         else
931         {
932             projcompMenuPos = menuBar->FindMenu(_("&Project"));
933             if (projcompMenuPos != wxNOT_FOUND)
934                 finalPos = projcompMenuPos + 1;
935         }
936         menuBar->Insert(finalPos, menu, _("&Debug"));
937 
938         m_menuHandler->RebuildMenus();
939     }
940     return menu;
941 }
942 
HasMenu() const943 bool DebuggerManager::HasMenu() const
944 {
945     wxMenuBar *menuBar = Manager::Get()->GetAppFrame()->GetMenuBar();
946     cbAssert(menuBar);
947     int menu_pos = menuBar->FindMenu(_("&Debug"));
948     return menu_pos != wxNOT_FOUND;
949 }
950 
BuildContextMenu(wxMenu & menu,const wxString & word_at_caret,bool is_running)951 void DebuggerManager::BuildContextMenu(wxMenu &menu, const wxString& word_at_caret, bool is_running)
952 {
953     m_menuHandler->BuildContextMenu(menu, word_at_caret, is_running);
954 }
955 
GetLogger(int & index)956 TextCtrlLogger* DebuggerManager::GetLogger(int &index)
957 {
958     LogManager* msgMan = Manager::Get()->GetLogManager();
959 
960     if (!m_logger)
961     {
962         m_logger = new DebugTextCtrlLogger(true, false);
963         m_loggerIndex = msgMan->SetLog(m_logger);
964         LogSlot &slot = msgMan->Slot(m_loggerIndex);
965         slot.title = _("Debugger");
966         // set log image
967         const int uiSize = Manager::Get()->GetImageSize(Manager::UIComponent::InfoPaneNotebooks);
968         const int uiScaleFactor = Manager::Get()->GetUIScaleFactor(Manager::UIComponent::InfoPaneNotebooks);
969         const wxString prefix = ConfigManager::GetDataFolder()
970                               + wxString::Format(_T("/resources.zip#zip:/images/infopane/%dx%d/"),
971                                                  uiSize, uiSize);
972         wxBitmap* bmp = new wxBitmap(cbLoadBitmapScaled(prefix + _T("misc.png"), wxBITMAP_TYPE_PNG,
973                                                         uiScaleFactor));
974         slot.icon = bmp;
975 
976         CodeBlocksLogEvent evtAdd(cbEVT_ADD_LOG_WINDOW, m_logger, slot.title, slot.icon);
977         Manager::Get()->ProcessEvent(evtAdd);
978     }
979 
980     index = m_loggerIndex;
981     return m_logger;
982 }
983 
GetLogger()984 TextCtrlLogger* DebuggerManager::GetLogger()
985 {
986     int index;
987     return GetLogger(index);
988 }
989 
HideLogger()990 void DebuggerManager::HideLogger()
991 {
992     LogManager *logManager = Manager::Get()->GetLogManager();
993     if (logManager)
994     {
995         // TODO: This is wrong. We need some automatic way for this to happen!!!
996         LogSlot &slot = logManager->Slot(m_loggerIndex);
997         delete slot.icon;
998         slot.icon = nullptr;
999     }
1000 
1001     CodeBlocksLogEvent evt(cbEVT_REMOVE_LOG_WINDOW, m_logger);
1002     Manager::Get()->ProcessEvent(evt);
1003     m_logger = nullptr;
1004     m_loggerIndex = -1;
1005 }
1006 
SetInterfaceFactory(cbDebugInterfaceFactory * factory)1007 void DebuggerManager::SetInterfaceFactory(cbDebugInterfaceFactory *factory)
1008 {
1009     cbAssert(!m_interfaceFactory);
1010     m_interfaceFactory = factory;
1011 
1012     CreateWindows();
1013 
1014     m_backtraceDialog->EnableWindow(false);
1015     m_cpuRegistersDialog->EnableWindow(false);
1016     m_disassemblyDialog->EnableWindow(false);
1017     m_examineMemoryDialog->EnableWindow(false);
1018     m_threadsDialog->EnableWindow(false);
1019 }
1020 
CreateWindows()1021 void DebuggerManager::CreateWindows()
1022 {
1023     if (!m_backtraceDialog)
1024         m_backtraceDialog = m_interfaceFactory->CreateBacktrace();
1025     if (!m_breakPointsDialog)
1026         m_breakPointsDialog = m_interfaceFactory->CreateBreapoints();
1027     if (!m_cpuRegistersDialog)
1028         m_cpuRegistersDialog = m_interfaceFactory->CreateCPURegisters();
1029     if (!m_disassemblyDialog)
1030         m_disassemblyDialog = m_interfaceFactory->CreateDisassembly();
1031     if (!m_examineMemoryDialog)
1032         m_examineMemoryDialog = m_interfaceFactory->CreateMemory();
1033     if (!m_threadsDialog)
1034         m_threadsDialog = m_interfaceFactory->CreateThreads();
1035     if (!m_watchesDialog)
1036         m_watchesDialog = m_interfaceFactory->CreateWatches();
1037 }
1038 
DestoryWindows()1039 void DebuggerManager::DestoryWindows()
1040 {
1041     m_interfaceFactory->DeleteBacktrace(m_backtraceDialog);
1042     m_backtraceDialog = nullptr;
1043 
1044     m_interfaceFactory->DeleteBreakpoints(m_breakPointsDialog);
1045     m_breakPointsDialog = nullptr;
1046 
1047     m_interfaceFactory->DeleteCPURegisters(m_cpuRegistersDialog);
1048     m_cpuRegistersDialog = nullptr;
1049 
1050     m_interfaceFactory->DeleteDisassembly(m_disassemblyDialog);
1051     m_disassemblyDialog = nullptr;
1052 
1053     m_interfaceFactory->DeleteMemory(m_examineMemoryDialog);
1054     m_examineMemoryDialog = nullptr;
1055 
1056     m_interfaceFactory->DeleteThreads(m_threadsDialog);
1057     m_threadsDialog = nullptr;
1058 
1059     m_interfaceFactory->DeleteWatches(m_watchesDialog);
1060     m_watchesDialog = nullptr;
1061 }
1062 
GetInterfaceFactory()1063 cbDebugInterfaceFactory* DebuggerManager::GetInterfaceFactory()
1064 {
1065     return m_interfaceFactory;
1066 }
1067 
SetMenuHandler(cbDebuggerMenuHandler * handler)1068 void DebuggerManager::SetMenuHandler(cbDebuggerMenuHandler *handler)
1069 {
1070     m_menuHandler = handler;
1071 }
1072 
GetMenuHandler()1073 cbDebuggerMenuHandler* DebuggerManager::GetMenuHandler()
1074 {
1075     return m_menuHandler;
1076 }
1077 
GetBacktraceDialog()1078 cbBacktraceDlg* DebuggerManager::GetBacktraceDialog()
1079 {
1080     return m_backtraceDialog;
1081 }
1082 
GetBreakpointDialog()1083 cbBreakpointsDlg* DebuggerManager::GetBreakpointDialog()
1084 {
1085     return m_breakPointsDialog;
1086 }
1087 
GetCPURegistersDialog()1088 cbCPURegistersDlg* DebuggerManager::GetCPURegistersDialog()
1089 {
1090     return m_cpuRegistersDialog;
1091 }
1092 
GetDisassemblyDialog()1093 cbDisassemblyDlg* DebuggerManager::GetDisassemblyDialog()
1094 {
1095     return m_disassemblyDialog;
1096 }
1097 
GetExamineMemoryDialog()1098 cbExamineMemoryDlg* DebuggerManager::GetExamineMemoryDialog()
1099 {
1100     return m_examineMemoryDialog;
1101 }
1102 
GetThreadsDialog()1103 cbThreadsDlg* DebuggerManager::GetThreadsDialog()
1104 {
1105     return m_threadsDialog;
1106 }
1107 
GetWatchesDialog()1108 cbWatchesDlg* DebuggerManager::GetWatchesDialog()
1109 {
1110     return m_watchesDialog;
1111 }
1112 
ShowBacktraceDialog()1113 bool DebuggerManager::ShowBacktraceDialog()
1114 {
1115     cbBacktraceDlg *dialog = GetBacktraceDialog();
1116 
1117     if (!IsWindowReallyShown(dialog->GetWindow()))
1118     {
1119         // show the backtrace window
1120         CodeBlocksDockEvent evt(cbEVT_SHOW_DOCK_WINDOW);
1121         evt.pWindow = dialog->GetWindow();
1122         Manager::Get()->ProcessEvent(evt);
1123         return true;
1124     }
1125     else
1126         return false;
1127 }
1128 
UpdateBacktrace()1129 bool DebuggerManager::UpdateBacktrace()
1130 {
1131     return m_backtraceDialog && IsWindowReallyShown(m_backtraceDialog->GetWindow());
1132 }
1133 
UpdateCPURegisters()1134 bool DebuggerManager::UpdateCPURegisters()
1135 {
1136     return m_cpuRegistersDialog && IsWindowReallyShown(m_cpuRegistersDialog->GetWindow());
1137 }
1138 
UpdateDisassembly()1139 bool DebuggerManager::UpdateDisassembly()
1140 {
1141     return m_disassemblyDialog && IsWindowReallyShown(m_disassemblyDialog->GetWindow());
1142 }
1143 
UpdateExamineMemory()1144 bool DebuggerManager::UpdateExamineMemory()
1145 {
1146     return m_examineMemoryDialog && IsWindowReallyShown(m_examineMemoryDialog->GetWindow());
1147 }
1148 
UpdateThreads()1149 bool DebuggerManager::UpdateThreads()
1150 {
1151     return m_threadsDialog && IsWindowReallyShown(m_threadsDialog->GetWindow());
1152 }
1153 
GetDebuggerHavingWatch(cb::shared_ptr<cbWatch> watch)1154 cbDebuggerPlugin* DebuggerManager::GetDebuggerHavingWatch(cb::shared_ptr<cbWatch> watch)
1155 {
1156     watch = cbGetRootWatch(watch);
1157     for (RegisteredPlugins::iterator it = m_registered.begin(); it != m_registered.end(); ++it)
1158     {
1159         if (it->first->HasWatch(watch))
1160             return it->first;
1161     }
1162     return NULL;
1163 }
1164 
ShowValueTooltip(const cb::shared_ptr<cbWatch> & watch,const wxRect & rect)1165 bool DebuggerManager::ShowValueTooltip(const cb::shared_ptr<cbWatch> &watch, const wxRect &rect)
1166 {
1167     return m_interfaceFactory->ShowValueTooltip(watch, rect);
1168 }
1169 
GetAllDebuggers() const1170 DebuggerManager::RegisteredPlugins const & DebuggerManager::GetAllDebuggers() const
1171 {
1172     return m_registered;
1173 }
GetAllDebuggers()1174 DebuggerManager::RegisteredPlugins & DebuggerManager::GetAllDebuggers()
1175 {
1176     return m_registered;
1177 }
GetActiveDebugger()1178 cbDebuggerPlugin* DebuggerManager::GetActiveDebugger()
1179 {
1180     return m_activeDebugger;
1181 }
1182 
RefreshBreakpoints(cb_unused const cbDebuggerPlugin * plugin)1183 inline void RefreshBreakpoints(cb_unused const cbDebuggerPlugin* plugin)
1184 {
1185     EditorManager *editorManager = Manager::Get()->GetEditorManager();
1186     int count = editorManager->GetEditorsCount();
1187     for (int ii = 0; ii < count; ++ii)
1188     {
1189         EditorBase *editor = editorManager->GetEditor(ii);
1190         if (editor->IsBuiltinEditor())
1191             static_cast<cbEditor*>(editor)->RefreshBreakpointMarkers();
1192     }
1193 }
1194 
SetActiveDebugger(cbDebuggerPlugin * activeDebugger,ConfigurationVector::const_iterator config)1195 void DebuggerManager::SetActiveDebugger(cbDebuggerPlugin* activeDebugger, ConfigurationVector::const_iterator config)
1196 {
1197     RegisteredPlugins::const_iterator it = m_registered.find(activeDebugger);
1198     cbAssert(it != m_registered.end());
1199 
1200     m_useTargetsDefault = false;
1201     m_activeDebugger = activeDebugger;
1202     int index = std::distance(it->second.GetConfigurations().begin(), config);
1203     m_activeDebugger->SetActiveConfig(index);
1204 
1205     WriteActiveDebuggerConfig(it->first->GetSettingsName(), index);
1206     RefreshUI();
1207 }
1208 
RefreshUI()1209 void DebuggerManager::RefreshUI()
1210 {
1211     m_menuHandler->SetActiveDebugger(m_activeDebugger);
1212     m_menuHandler->RebuildMenus();
1213     RefreshBreakpoints(m_activeDebugger);
1214 
1215     if (m_activeDebugger)
1216     {
1217         if (m_backtraceDialog)
1218             m_backtraceDialog->EnableWindow(m_activeDebugger->SupportsFeature(cbDebuggerFeature::Callstack));
1219         if (m_cpuRegistersDialog)
1220             m_cpuRegistersDialog->EnableWindow(m_activeDebugger->SupportsFeature(cbDebuggerFeature::CPURegisters));
1221         if (m_disassemblyDialog)
1222             m_disassemblyDialog->EnableWindow(m_activeDebugger->SupportsFeature(cbDebuggerFeature::Disassembly));
1223         if (m_examineMemoryDialog)
1224             m_examineMemoryDialog->EnableWindow(m_activeDebugger->SupportsFeature(cbDebuggerFeature::ExamineMemory));
1225         if (m_threadsDialog)
1226             m_threadsDialog->EnableWindow(m_activeDebugger->SupportsFeature(cbDebuggerFeature::Threads));
1227     }
1228     if (m_watchesDialog)
1229         m_watchesDialog->RefreshUI();
1230     if (m_breakPointsDialog)
1231         m_breakPointsDialog->Reload();
1232 }
1233 
IsActiveDebuggerTargetsDefault() const1234 bool DebuggerManager::IsActiveDebuggerTargetsDefault() const
1235 {
1236     return m_activeDebugger && m_useTargetsDefault;
1237 }
1238 
SetTargetsDefaultAsActiveDebugger()1239 void DebuggerManager::SetTargetsDefaultAsActiveDebugger()
1240 {
1241     m_activeDebugger = nullptr;
1242     m_menuHandler->SetActiveDebugger(nullptr);
1243     FindTargetsDebugger();
1244 }
1245 
FindTargetsDebugger()1246 void DebuggerManager::FindTargetsDebugger()
1247 {
1248     if (Manager::Get()->GetProjectManager()->IsLoadingOrClosing())
1249         return;
1250 
1251     m_activeDebugger = nullptr;
1252     m_menuHandler->SetActiveDebugger(nullptr);
1253 
1254     if (m_registered.empty())
1255     {
1256         m_menuHandler->MarkActiveTargetAsValid(false);
1257         return;
1258     }
1259 
1260     ProjectManager* projectMgr = Manager::Get()->GetProjectManager();
1261     LogManager* log = Manager::Get()->GetLogManager();
1262     cbProject* project = projectMgr->GetActiveProject();
1263     ProjectBuildTarget *target = nullptr;
1264     if (project)
1265     {
1266         const wxString &targetName = project->GetActiveBuildTarget();
1267         if (project->BuildTargetValid(targetName))
1268             target = project->GetBuildTarget(targetName);
1269     }
1270 
1271 
1272     Compiler *compiler = nullptr;
1273     if (!target)
1274     {
1275         if (project)
1276             compiler = CompilerFactory::GetCompiler(project->GetCompilerID());
1277         if (!compiler)
1278             compiler = CompilerFactory::GetDefaultCompiler();
1279         if (!compiler)
1280         {
1281             log->LogError(_("Can't get the compiler for the active target, nor the project, nor the default one!"));
1282             m_menuHandler->MarkActiveTargetAsValid(false);
1283             return;
1284         }
1285     }
1286     else
1287     {
1288         compiler = CompilerFactory::GetCompiler(target->GetCompilerID());
1289         if (!compiler)
1290         {
1291             log->LogError(wxString::Format(_("Current target '%s' doesn't have valid compiler!"),
1292                                            target->GetTitle().c_str()));
1293             m_menuHandler->MarkActiveTargetAsValid(false);
1294             return;
1295         }
1296     }
1297     wxString dbgString = compiler->GetPrograms().DBGconfig;
1298     wxString::size_type pos = dbgString.find(wxT(':'));
1299 
1300     wxString name, config;
1301     if (pos != wxString::npos)
1302     {
1303         name = dbgString.substr(0, pos);
1304         config = dbgString.substr(pos + 1, dbgString.length() - pos - 1);
1305     }
1306 
1307     if (name.empty() || config.empty())
1308     {
1309         if (compiler->GetID() != wxT("null"))
1310         {
1311             log->LogError(wxString::Format(_("Current compiler '%s' doesn't have correctly defined debugger!"),
1312                                            compiler->GetName().c_str()));
1313         }
1314         m_menuHandler->MarkActiveTargetAsValid(false);
1315         return;
1316     }
1317 
1318     for (RegisteredPlugins::iterator it = m_registered.begin(); it != m_registered.end(); ++it)
1319     {
1320         PluginData &data = it->second;
1321         if (it->first->GetSettingsName() == name)
1322         {
1323             ConfigurationVector &configs = data.GetConfigurations();
1324             int index = 0;
1325             for (ConfigurationVector::iterator itConf = configs.begin(); itConf != configs.end(); ++itConf, ++index)
1326             {
1327                 if ((*itConf)->GetName() == config)
1328                 {
1329                     m_activeDebugger = it->first;
1330                     m_activeDebugger->SetActiveConfig(index);
1331                     m_useTargetsDefault = true;
1332 
1333                     WriteActiveDebuggerConfig(wxEmptyString, -1);
1334                     RefreshUI();
1335                     m_menuHandler->MarkActiveTargetAsValid(true);
1336                     return;
1337                 }
1338             }
1339         }
1340     }
1341 
1342     wxString targetTitle(target ? target->GetTitle() : wxT("<nullptr>"));
1343     log->LogError(wxString::Format(_("Can't find the debugger config: '%s:%s' for the current target '%s'!"),
1344                                    name.c_str(), config.c_str(),
1345                                    targetTitle.c_str()));
1346     m_menuHandler->MarkActiveTargetAsValid(false);
1347 }
1348 
IsDisassemblyMixedMode()1349 bool DebuggerManager::IsDisassemblyMixedMode()
1350 {
1351     return m_isDisassemblyMixedMode;
1352 }
1353 
SetDisassemblyMixedMode(bool mixed)1354 void DebuggerManager::SetDisassemblyMixedMode(bool mixed)
1355 {
1356     m_isDisassemblyMixedMode = mixed;
1357     ConfigManager *c = Manager::Get()->GetConfigManager(wxT("debugger_common"));
1358     c->Write(wxT("/common/disassembly/mixed_mode"), m_isDisassemblyMixedMode);
1359 }
1360 
OnProjectActivated(cb_unused CodeBlocksEvent & event)1361 void DebuggerManager::OnProjectActivated(cb_unused CodeBlocksEvent& event)
1362 {
1363     if (m_useTargetsDefault)
1364         FindTargetsDebugger();
1365 }
1366 
OnTargetSelected(cb_unused CodeBlocksEvent & event)1367 void DebuggerManager::OnTargetSelected(cb_unused CodeBlocksEvent& event)
1368 {
1369     if (m_useTargetsDefault)
1370         FindTargetsDebugger();
1371 }
1372 
OnSettingsChanged(CodeBlocksEvent & event)1373 void DebuggerManager::OnSettingsChanged(CodeBlocksEvent& event)
1374 {
1375     if (event.GetInt() == cbSettingsType::Compiler || event.GetInt() == cbSettingsType::Debugger)
1376     {
1377         if (m_useTargetsDefault)
1378             FindTargetsDebugger();
1379     }
1380 }
1381 
OnPluginLoadingComplete(cb_unused CodeBlocksEvent & event)1382 void DebuggerManager::OnPluginLoadingComplete(cb_unused CodeBlocksEvent& event)
1383 {
1384     RefreshUI();
1385     if (!m_activeDebugger)
1386     {
1387         m_useTargetsDefault = true;
1388         FindTargetsDebugger();
1389     }
1390 }
1391