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