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