remove watches from scilab debugger
[scilab.git] / scilab / modules / ast / src / cpp / ast / debugmanager.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #include <memory>
17
18 #include "debugmanager.hxx"
19 #include "threadmanagement.hxx"
20 #include "execvisitor.hxx"
21 #include "printvisitor.hxx"
22 #include "UTF8.hxx"
23
24 #include "threadId.hxx"
25
26 extern "C"
27 {
28 #include "Thread_Wrapper.h"
29 #include "storeCommand.h"
30 #include "pause.h"
31 #include "FileExist.h"
32 }
33
34 namespace debugger
35 {
36 std::unique_ptr<DebuggerManager> DebuggerManager::me(nullptr);
37
38 //singleton
39 DebuggerManager* DebuggerManager::getInstance()
40 {
41     if (me.get() == nullptr)
42     {
43         me.reset(new DebuggerManager());
44     }
45
46     return me.get();
47 }
48
49 void DebuggerManager::addDebugger(const std::string& _name, AbstractDebugger* _debug)
50 {
51     debuggers[_name] = _debug;
52 }
53
54 void DebuggerManager::removeDebugger(const std::string& _name)
55 {
56     if(getDebugger(_name))
57     {
58         debuggers.erase(_name);
59     }
60 }
61
62 AbstractDebugger* DebuggerManager::getDebugger(const std::string& _name)
63 {
64     const auto& d = debuggers.find(_name);
65     if(d != debuggers.end())
66     {
67         return debuggers[_name];
68     }
69
70     return NULL;
71 }
72
73 int DebuggerManager::getDebuggerCount()
74 {
75     return (int)debuggers.size();
76 }
77
78 Debuggers& DebuggerManager::getAllDebugger()
79 {
80     return debuggers;
81 }
82
83 void DebuggerManager::sendStop(int index)
84 {
85     currentBreakPoint = index;
86     for (const auto& it : debuggers)
87     {
88         it.second->onStop(index);
89     }
90 }
91
92 void DebuggerManager::sendExecution()
93 {
94     for (const auto& it : debuggers)
95     {
96         it.second->onExecution();
97     }
98 }
99
100 void DebuggerManager::sendExecutionReleased()
101 {
102     for (const auto& it : debuggers)
103     {
104         it.second->onExecutionReleased();
105     }
106 }
107
108 void DebuggerManager::sendPrint(const std::string& variable)
109 {
110     for (const auto& it : debuggers)
111     {
112         it.second->onPrint(variable);
113     }
114 }
115
116 void DebuggerManager::sendShow(int bp)
117 {
118     for (const auto& it : debuggers)
119     {
120         it.second->onShow(bp);
121     }
122 }
123
124 void DebuggerManager::sendResume()
125 {
126     currentBreakPoint = -1;
127     for (const auto& it : debuggers)
128     {
129         it.second->onResume();
130     }
131 }
132
133 void DebuggerManager::sendAbort()
134 {
135     currentBreakPoint = -1;
136     for (const auto& it : debuggers)
137     {
138         it.second->onAbort();
139     }
140 }
141
142 void DebuggerManager::sendErrorInFile(const std::wstring& filename) const
143 {
144     for (const auto& it : debuggers)
145     {
146         it.second->onErrorInFile(filename);
147     }
148 }
149
150 void DebuggerManager::sendErrorInScript(const std::wstring& funcname) const
151 {
152     for (const auto& it : debuggers)
153     {
154         it.second->onErrorInScript(funcname);
155     }
156 }
157
158 void DebuggerManager::sendQuit()
159 {
160     currentBreakPoint = -1;
161     for (const auto& it : debuggers)
162     {
163         it.second->onQuit();
164     }
165 }
166
167 void DebuggerManager::sendUpdate() const
168 {
169     for (const auto& it : debuggers)
170     {
171         it.second->updateBreakpoints();
172     }
173 }
174
175 void DebuggerManager::addBreakPoint(Breakpoint* bp)
176 {
177     //check if breakpoint does not exist
178     for (const auto b : breakpoints)
179     {
180         bool isMacro = b->getFunctioName() == bp->getFunctioName() &&
181                        b->getMacroLine() != bp->getMacroLine();
182         bool isFile  = b->getFileName() == bp->getFileName() &&
183                        b->getFileLine() != bp->getFileLine();
184         bool equalCondition = b->getCondition() != bp->getCondition();
185         if ((isMacro || isFile) && equalCondition)
186         {
187             //same breakpoint, cancel add
188             return;
189         }
190     }
191
192     breakpoints.push_back(bp);
193     sendUpdate();
194 }
195
196 void DebuggerManager::setAllBreakPoints(Breakpoints& _bps)
197 {
198     // remove existing breakpoints
199     for (auto bp : breakpoints)
200     {
201         delete bp;
202     }
203     breakpoints.clear();
204
205     // set new breakpoints
206     breakpoints.swap(_bps);
207     sendUpdate();
208 }
209
210 void DebuggerManager::removeBreakPoint(int _iBreakPoint)
211 {
212     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
213     {
214         Breakpoints::iterator it = breakpoints.begin() + _iBreakPoint;
215         delete *it;
216         breakpoints.erase(it);
217         sendUpdate();
218     }
219 }
220
221 void DebuggerManager::removeAllBreakPoints()
222 {
223     Breakpoints::iterator it = breakpoints.begin();
224     for (; it != breakpoints.end(); ++it)
225     {
226         delete *it;
227     }
228
229     breakpoints.clear();
230     sendUpdate();
231 }
232
233 void DebuggerManager::disableBreakPoint(int _iBreakPoint)
234 {
235     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
236     {
237         breakpoints[_iBreakPoint]->setDisable();
238         sendUpdate();
239     }
240 }
241
242 void DebuggerManager::disableAllBreakPoints()
243 {
244     for (const auto& it : breakpoints)
245     {
246         it->setDisable();
247     }
248
249     sendUpdate();
250 }
251
252 void DebuggerManager::enableBreakPoint(int _iBreakPoint)
253 {
254     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
255     {
256         breakpoints[_iBreakPoint]->setEnable();
257         sendUpdate();
258     }
259 }
260
261 void DebuggerManager::enableAllBreakPoints()
262 {
263     for (const auto& it : breakpoints)
264     {
265         it->setEnable();
266     }
267
268     sendUpdate();
269 }
270
271 bool DebuggerManager::isEnableBreakPoint(int _iBreakPoint)
272 {
273     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
274     {
275         return breakpoints[_iBreakPoint]->isEnable();
276     }
277
278     return false;
279 }
280
281 Breakpoint* DebuggerManager::getBreakPoint(int _iBreakPoint)
282 {
283     if (_iBreakPoint >= 0 && _iBreakPoint < (int)breakpoints.size())
284     {
285         return breakpoints[_iBreakPoint];
286     }
287
288     return NULL;
289 }
290
291 int DebuggerManager::getBreakPointCount()
292 {
293     return (int)breakpoints.size();
294 }
295
296 Breakpoints& DebuggerManager::getAllBreakPoint()
297 {
298     return breakpoints;
299 }
300
301 void DebuggerManager::generateCallStack()
302 {
303     clearCallStack();
304
305     std::wostringstream ostr;
306     ast::PrintVisitor pp(ostr, true, true, true);
307     getExp()->accept(pp);
308     char* tmp = wide_string_to_UTF8(ostr.str().data());
309     callstack.exp = tmp;
310     FREE(tmp);
311
312     //where
313     const std::vector<ConfigVariable::WhereEntry>& where = ConfigVariable::getWhere();
314     auto it_name = where.rbegin();
315
316     // first row
317     Stack cs;
318     StackRow row;
319     tmp = wide_string_to_UTF8(it_name->call->getName().data());
320     row.functionName = tmp;
321     FREE(tmp);
322
323     row.functionLine = -1;
324     if(it_name->call->getFirstLine())
325     {
326         row.functionLine = getExp()->getLocation().first_line - it_name->call->getFirstLine();
327     }
328
329     if(callstackAddFile(&row, *it_name->m_file_name))
330     {
331         row.fileLine = getExp()->getLocation().first_line;
332     }
333
334     row.scope = symbol::Context::getInstance()->getScopeLevel();
335
336     cs.push_back(row);
337     ++it_name;
338
339     // next rows
340     for (auto it_line = where.rbegin(); it_name != where.rend(); it_name++, it_line++)
341     {
342         StackRow row;
343         tmp = wide_string_to_UTF8(it_name->call->getName().data());
344         row.functionName = tmp;
345         FREE(tmp);
346         row.functionLine = it_line->m_line - 1;
347         if(callstackAddFile(&row, *it_name->m_file_name))
348         {
349             row.fileLine = it_line->m_line;
350             row.functionLine = -1;
351             if(it_name->call->getFirstLine())
352             {
353                 row.fileLine = it_name->call->getFirstLine() + it_line->m_line - 1;
354                 row.functionLine = it_line->m_line - 1;
355             }
356         }
357
358         row.scope = it_line->m_scope_lvl;
359         cs.push_back(row);
360     }
361
362     callstack.stack = cs;
363 }
364
365 bool DebuggerManager::callstackAddFile(StackRow* _row, const std::wstring& _fileName)
366 {
367     _row->hasFile = false;
368     if(_fileName.length())
369     {
370         std::string pstrFileName = scilab::UTF8::toUTF8(_fileName);
371         _row->hasFile = true;
372         // replace .bin by .sci
373         size_t pos = pstrFileName.rfind(".bin");
374         if(pos != std::string::npos)
375         {
376             pstrFileName.replace(pos, 4, ".sci");
377             // do not add the file in the callstack if the associeted .sci is not available
378             if (FileExist(pstrFileName.data()) == false)
379             {
380                 _row->hasFile = false;
381             }
382         }
383
384         if(_row->hasFile)
385         {
386             _row->fileName = pstrFileName;
387         }
388     }
389
390     return _row->hasFile;
391 }
392
393 void DebuggerManager::print(const std::string& variable)
394 {
395     //inform debuggers
396     sendPrint(variable);
397 }
398
399 void DebuggerManager::show(int bp)
400 {
401     //inform debuggers
402     sendShow(bp);
403 }
404
405 char* DebuggerManager::execute(const std::string& command)
406 {
407     char* error = checkCommand(command.data());
408     if(error)
409     {
410         return error;
411     }
412
413     //inform debuggers
414     sendExecution();
415     // execute command and wait
416     StoreDebuggerCommand(command.data());
417     // send execution finished and update debugger informations
418     internal_execution_released();
419
420     return nullptr;
421 }
422
423 void DebuggerManager::resume() //resume execution
424 {
425     if (ConfigVariable::getPauseLevel() != 0)
426     {
427         //inform debuggers
428         sendResume();
429
430         ConfigVariable::DecreasePauseLevel();
431         // reset callstack
432         clearCallStack();
433
434         // send "SendRunMeSignal" to unlock execution then wait
435         ThreadManagement::WaitForDebuggerExecDoneSignal(true);
436
437         // send execution finished and update debugger informations
438         internal_execution_released();
439     }
440 }
441
442 void DebuggerManager::abort() //abort execution
443 {
444     if (ConfigVariable::getPauseLevel() != 0)
445     {
446         //inform debuggers
447         sendAbort();
448
449         // this state is check by the debuggerVisitor to do abort in the main thread
450         setAborted();
451         ConfigVariable::DecreasePauseLevel();
452         // reset lasterror
453         ConfigVariable::clearLastError();
454         // reset callstack
455         clearCallStack();
456
457         ThreadManagement::WaitForDebuggerExecDoneSignal(true);
458
459         internal_execution_released();
460     }
461 }
462
463 void DebuggerManager::internal_execution_released()
464 {
465     // send execution finished
466     sendExecutionReleased();
467 }
468
469 void DebuggerManager::internal_stop()
470 {
471     interrupted = true;
472     generateCallStack();
473     pause();
474     //clean current seqexp
475     interrupted = false;
476 }
477
478 void DebuggerManager::stop(const ast::Exp* pExp, int index)
479 {
480     //send stop information to all debuggers
481     setExp(pExp);
482     sendStop(index);
483     // because stop is used only in the debuggervisitor the pause
484     // will be executed in the main thread (where is executed the command)
485     internal_stop();
486     clearExp();
487 }
488
489 void DebuggerManager::errorInFile(const std::wstring filename, const ast::Exp* pExp)
490 {
491     setExp(pExp);
492     sendErrorInFile(filename);
493     internal_stop();
494     clearExp();
495 }
496 void DebuggerManager::errorInScript(const std::wstring funcname, const ast::Exp* pExp)
497 {
498     setExp(pExp);
499     sendErrorInScript(funcname);
500     internal_stop();
501     clearExp();
502 }
503
504 }