core: on error, a crash could happen
[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::setWatches(Watches _w)
302 {
303     watches.clear();
304     watches = _w;
305 }
306
307 void DebuggerManager::removeWatches()
308 {
309     watches.clear();
310 }
311
312 void DebuggerManager::updateWatches(int _iScopeLvl)
313 {
314     symbol::Context* pCtx = symbol::Context::getInstance();
315
316     if(_iScopeLvl < 0)
317     {
318         // get current scope lvl
319         _iScopeLvl = pCtx->getScopeLevel();
320     }
321
322     for(auto& w : watches)
323     {
324         types::InternalType* pIT = pCtx->getAtLevel(symbol::Symbol(scilab::UTF8::toWide(w.first)), _iScopeLvl);
325         if(pIT)
326         {
327             std::wostringstream os;
328             pIT->toString(os);
329             w.second = scilab::UTF8::toUTF8(os.str());
330         }
331         else
332         {
333             w.second.clear();
334         }
335     }
336 }
337
338 Watches& DebuggerManager::getWatches()
339 {
340     return watches;
341 }
342
343
344
345 void DebuggerManager::generateCallStack()
346 {
347     clearCallStack();
348
349     std::wostringstream ostr;
350     ast::PrintVisitor pp(ostr, true, true, true);
351     getExp()->accept(pp);
352     char* tmp = wide_string_to_UTF8(ostr.str().data());
353     callstack.exp = tmp;
354     FREE(tmp);
355
356     //where
357     const std::vector<ConfigVariable::WhereEntry>& where = ConfigVariable::getWhere();
358     auto it_name = where.rbegin();
359
360     // first row
361     Stack cs;
362     StackRow row;
363     tmp = wide_string_to_UTF8(it_name->call->getName().data());
364     row.functionName = tmp;
365     FREE(tmp);
366
367     row.functionLine = -1;
368     if(it_name->call->getFirstLine())
369     {
370         row.functionLine = getExp()->getLocation().first_line - it_name->call->getFirstLine();
371     }
372
373     if(callstackAddFile(&row, *it_name->m_file_name))
374     {
375         row.fileLine = getExp()->getLocation().first_line;
376     }
377
378     row.scope = symbol::Context::getInstance()->getScopeLevel();
379
380     cs.push_back(row);
381     ++it_name;
382
383     // next rows
384     for (auto it_line = where.rbegin(); it_name != where.rend(); it_name++, it_line++)
385     {
386         StackRow row;
387         tmp = wide_string_to_UTF8(it_name->call->getName().data());
388         row.functionName = tmp;
389         FREE(tmp);
390         row.functionLine = it_line->m_line - 1;
391         if(callstackAddFile(&row, *it_name->m_file_name))
392         {
393             row.fileLine = it_line->m_line;
394             row.functionLine = -1;
395             if(it_name->call->getFirstLine())
396             {
397                 row.fileLine = it_name->call->getFirstLine() + it_line->m_line - 1;
398                 row.functionLine = it_line->m_line - 1;
399             }
400         }
401
402         row.scope = it_line->m_scope_lvl;
403         cs.push_back(row);
404     }
405
406     callstack.stack = cs;
407 }
408
409 bool DebuggerManager::callstackAddFile(StackRow* _row, const std::wstring& _fileName)
410 {
411     _row->hasFile = false;
412     if(_fileName.length())
413     {
414         std::string pstrFileName = scilab::UTF8::toUTF8(_fileName);
415         _row->hasFile = true;
416         // replace .bin by .sci
417         size_t pos = pstrFileName.rfind(".bin");
418         if(pos != std::string::npos)
419         {
420             pstrFileName.replace(pos, 4, ".sci");
421             // do not add the file in the callstack if the associeted .sci is not available
422             if (FileExist(pstrFileName.data()) == false)
423             {
424                 _row->hasFile = false;
425             }
426         }
427
428         if(_row->hasFile)
429         {
430             _row->fileName = pstrFileName;
431         }
432     }
433
434     return _row->hasFile;
435 }
436
437 void DebuggerManager::print(const std::string& variable)
438 {
439     //inform debuggers
440     sendPrint(variable);
441 }
442
443 void DebuggerManager::show(int bp)
444 {
445     //inform debuggers
446     sendShow(bp);
447 }
448
449 char* DebuggerManager::execute(const std::string& command)
450 {
451     char* error = checkCommand(command.data());
452     if(error)
453     {
454         return error;
455     }
456
457     //inform debuggers
458     sendExecution();
459     // execute command and wait
460     StoreDebuggerCommand(command.data());
461     // send execution finished and update debugger informations
462     internal_execution_released();
463
464     return nullptr;
465 }
466
467 void DebuggerManager::resume() //resume execution
468 {
469     if (ConfigVariable::getPauseLevel() != 0)
470     {
471         //inform debuggers
472         sendResume();
473
474         ConfigVariable::DecreasePauseLevel();
475         // reset callstack
476         clearCallStack();
477
478         // send "SendRunMeSignal" to unlock execution then wait
479         ThreadManagement::WaitForDebuggerExecDoneSignal(true);
480
481         // send execution finished and update debugger informations
482         internal_execution_released();
483     }
484 }
485
486 void DebuggerManager::abort() //abort execution
487 {
488     if (ConfigVariable::getPauseLevel() != 0)
489     {
490         //inform debuggers
491         sendAbort();
492
493         // this state is check by the debuggerVisitor to do abort in the main thread
494         setAborted();
495         ConfigVariable::DecreasePauseLevel();
496         // reset lasterror
497         ConfigVariable::clearLastError();
498         // reset callstack
499         clearCallStack();
500
501         ThreadManagement::WaitForDebuggerExecDoneSignal(true);
502
503         internal_execution_released();
504     }
505 }
506
507 void DebuggerManager::internal_execution_released()
508 {
509     // update watches at each execution released
510     updateWatches();
511     // send execution finished
512     sendExecutionReleased();
513 }
514
515 void DebuggerManager::internal_stop()
516 {
517     interrupted = true;
518     generateCallStack();
519     updateWatches();
520     pause();
521     //clean current seqexp
522     interrupted = false;
523 }
524
525 void DebuggerManager::stop(const ast::Exp* pExp, int index)
526 {
527     //send stop information to all debuggers
528     setExp(pExp);
529     sendStop(index);
530     // because stop is used only in the debuggervisitor the pause
531     // will be executed in the main thread (where is executed the command)
532     internal_stop();
533     clearExp();
534 }
535
536 void DebuggerManager::errorInFile(const std::wstring filename, const ast::Exp* pExp)
537 {
538     setExp(pExp);
539     sendErrorInFile(filename);
540     internal_stop();
541     clearExp();
542 }
543 void DebuggerManager::errorInScript(const std::wstring funcname, const ast::Exp* pExp)
544 {
545     setExp(pExp);
546     sendErrorInScript(funcname);
547     internal_stop();
548     clearExp();
549 }
550
551 }