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