callstack generation fixed
[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::setAllBreakPoints(Breakpoints& _bps)
176 {
177     // remove existing breakpoints
178     for (auto bp : breakpoints)
179     {
180         delete bp;
181     }
182     breakpoints.clear();
183
184     // set new breakpoints
185     breakpoints.swap(_bps);
186     sendUpdate();
187 }
188
189 Breakpoints::iterator DebuggerManager::findBreakPoint(Breakpoint* bp)
190 {
191     Breakpoints::iterator found = std::find_if(breakpoints.begin(), breakpoints.end(),
192     [&](Breakpoint* b) {
193         bool isMacro = b->getFunctioName() != "" &&
194                        b->getFunctioName() == bp->getFunctioName() &&
195                        b->getMacroLine() == bp->getMacroLine();
196
197         bool isFile  = b->getFileName() != "" &&
198                        b->getFileName() == bp->getFileName() &&
199                        b->getFileLine() == bp->getFileLine();
200
201         return (isMacro || isFile);
202     });
203
204     return found;
205 }
206
207 bool DebuggerManager::addBreakPoint(Breakpoint* bp)
208 {
209     //check if breakpoint does not exist
210     Breakpoints::iterator iter = findBreakPoint(bp);
211     if(iter == breakpoints.end())
212     {
213         breakpoints.push_back(bp);
214         sendUpdate();
215         return true;
216     }
217
218     return false;
219 }
220
221 bool DebuggerManager::updateBreakPoint(Breakpoint* bp)
222 {
223     Breakpoints::iterator iter = findBreakPoint(bp);
224     if(iter != breakpoints.end())
225     {
226         std::swap(*iter, bp);
227         delete bp;
228         return true;
229     }
230
231     return false;
232 }
233
234 bool DebuggerManager::removeBreakPoint(Breakpoint* bp)
235 {
236     Breakpoints::iterator iter = findBreakPoint(bp);
237     if(iter != breakpoints.end())
238     {
239         delete *iter;
240         breakpoints.erase(iter);
241         return true;
242     }
243
244     return false;
245 }
246
247 void DebuggerManager::removeBreakPoint(int _iBreakPoint)
248 {
249     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
250     {
251         Breakpoints::iterator it = breakpoints.begin() + _iBreakPoint;
252         delete *it;
253         breakpoints.erase(it);
254         sendUpdate();
255     }
256 }
257
258 void DebuggerManager::removeAllBreakPoints()
259 {
260     Breakpoints::iterator it = breakpoints.begin();
261     for (; it != breakpoints.end(); ++it)
262     {
263         delete *it;
264     }
265
266     breakpoints.clear();
267     sendUpdate();
268 }
269
270 void DebuggerManager::disableBreakPoint(int _iBreakPoint)
271 {
272     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
273     {
274         breakpoints[_iBreakPoint]->setDisable();
275         sendUpdate();
276     }
277 }
278
279 void DebuggerManager::disableAllBreakPoints()
280 {
281     for (const auto& it : breakpoints)
282     {
283         it->setDisable();
284     }
285
286     sendUpdate();
287 }
288
289 void DebuggerManager::enableBreakPoint(int _iBreakPoint)
290 {
291     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
292     {
293         breakpoints[_iBreakPoint]->setEnable();
294         sendUpdate();
295     }
296 }
297
298 void DebuggerManager::enableAllBreakPoints()
299 {
300     for (const auto& it : breakpoints)
301     {
302         it->setEnable();
303     }
304
305     sendUpdate();
306 }
307
308 bool DebuggerManager::isEnableBreakPoint(int _iBreakPoint)
309 {
310     if (_iBreakPoint >= 0 && _iBreakPoint <= (int)breakpoints.size())
311     {
312         return breakpoints[_iBreakPoint]->isEnable();
313     }
314
315     return false;
316 }
317
318 Breakpoint* DebuggerManager::getBreakPoint(int _iBreakPoint)
319 {
320     if (_iBreakPoint >= 0 && _iBreakPoint < (int)breakpoints.size())
321     {
322         return breakpoints[_iBreakPoint];
323     }
324
325     return NULL;
326 }
327
328 int DebuggerManager::getBreakPointCount()
329 {
330     return (int)breakpoints.size();
331 }
332
333 Breakpoints& DebuggerManager::getAllBreakPoint()
334 {
335     return breakpoints;
336 }
337
338 void DebuggerManager::generateCallStack()
339 {
340     clearCallStack();
341
342     std::wostringstream ostr;
343     ast::PrintVisitor pp(ostr, true, true, true);
344     getExp()->accept(pp);
345     char* tmp = wide_string_to_UTF8(ostr.str().data());
346     callstack.exp = tmp;
347     FREE(tmp);
348
349     //where
350     const std::vector<ConfigVariable::WhereEntry>& where = ConfigVariable::getWhere();
351     auto it_name = where.rbegin();
352
353     // first row
354     Stack cs;
355     StackRow row;
356     tmp = wide_string_to_UTF8(it_name->call->getName().data());
357     row.functionName = tmp;
358     FREE(tmp);
359
360     row.functionLine = -1;
361     if(it_name->call->getFirstLine())
362     {
363         row.functionLine = getExp()->getLocation().first_line - it_name->call->getFirstLine();
364     }
365
366     if(callstackAddFile(&row, *it_name->m_file_name))
367     {
368         row.fileLine = getExp()->getLocation().first_line;
369     }
370
371     row.scope = symbol::Context::getInstance()->getScopeLevel();
372
373     cs.push_back(row);
374     ++it_name;
375
376     // next rows
377     for (auto it_line = where.rbegin(); it_name != where.rend(); it_name++, it_line++)
378     {
379         StackRow row;
380         tmp = wide_string_to_UTF8(it_name->call->getName().data());
381         row.functionName = tmp;
382         FREE(tmp);
383         row.functionLine = it_line->m_line - 1;
384         if(it_name->m_file_name && callstackAddFile(&row, *it_name->m_file_name))
385         {
386             row.fileLine = it_line->m_line;
387             row.functionLine = -1;
388             if(it_name->call->getFirstLine())
389             {
390                 row.fileLine = it_name->call->getFirstLine() + it_line->m_line - 1;
391                 row.functionLine = it_line->m_line - 1;
392             }
393         }
394
395         row.scope = it_line->m_scope_lvl;
396         cs.push_back(row);
397     }
398
399     callstack.stack = cs;
400 }
401
402 bool DebuggerManager::callstackAddFile(StackRow* _row, const std::wstring& _fileName)
403 {
404     _row->hasFile = false;
405     if(_fileName.length())
406     {
407         std::string pstrFileName = scilab::UTF8::toUTF8(_fileName);
408         _row->hasFile = true;
409         // replace .bin by .sci
410         size_t pos = pstrFileName.rfind(".bin");
411         if(pos != std::string::npos)
412         {
413             pstrFileName.replace(pos, 4, ".sci");
414             // do not add the file in the callstack if the associeted .sci is not available
415             if (FileExist(pstrFileName.data()) == false)
416             {
417                 _row->hasFile = false;
418             }
419         }
420
421         if(_row->hasFile)
422         {
423             _row->fileName = pstrFileName;
424         }
425     }
426
427     return _row->hasFile;
428 }
429
430 void DebuggerManager::print(const std::string& variable)
431 {
432     //inform debuggers
433     sendPrint(variable);
434 }
435
436 void DebuggerManager::show(int bp)
437 {
438     //inform debuggers
439     sendShow(bp);
440 }
441
442 char* DebuggerManager::execute(const std::string& command)
443 {
444     char* error = checkCommand(command.data());
445     if(error)
446     {
447         return error;
448     }
449
450     // reset abort flag befor a new exection
451     resetAborted();
452
453     // inform debuggers
454     sendExecution();
455     // execute command and wait
456     StoreDebuggerCommand(command.data());
457     // send execution finished and update debugger informations
458     internal_execution_released();
459
460     return nullptr;
461 }
462
463 void DebuggerManager::resume() //resume execution
464 {
465     if (ConfigVariable::getPauseLevel() != 0)
466     {
467         //inform debuggers
468         sendResume();
469
470         ConfigVariable::DecreasePauseLevel();
471         // reset callstack
472         clearCallStack();
473
474         // send "SendRunMeSignal" to unlock execution then wait
475         ThreadManagement::WaitForDebuggerExecDoneSignal(true);
476
477         // send execution finished and update debugger informations
478         internal_execution_released();
479     }
480 }
481
482 void DebuggerManager::requestPause() //ask for pause
483 {
484     // pause on execution only if a command is running
485     if(interrupted == false) {
486         request_pause = true;
487     }
488 }
489
490 bool DebuggerManager::isPauseRequested() //pause execution
491 {
492     return request_pause;
493 }
494
495 void DebuggerManager::resetPauseRequest() //pause execution
496 {
497     request_pause = false;
498 }
499
500 void DebuggerManager::abort() //abort execution
501 {
502     //inform debuggers
503     sendAbort();
504
505     // this state is check by the debuggerVisitor to do abort in the main thread
506     setAborted();
507
508     // reset requested pause in case we abort before beeing in pause
509     resetPauseRequest();
510
511     // abort in a pause
512     if(isInterrupted())
513     {
514         if (ConfigVariable::getPauseLevel() != 0)
515         {
516             ConfigVariable::DecreasePauseLevel();
517         }
518
519         // reset lasterror information
520         ConfigVariable::clearLastError();
521         // reset error flag
522         ConfigVariable::resetError();
523         // reset callstack
524         clearCallStack();
525
526         ThreadManagement::WaitForDebuggerExecDoneSignal(true);
527
528         internal_execution_released();
529     }
530 }
531
532 void DebuggerManager::internal_execution_released()
533 {
534     // send execution finished
535     sendExecutionReleased();
536 }
537
538 void DebuggerManager::internal_stop()
539 {
540     interrupted = true;
541     generateCallStack();
542     // release the debugger thread
543     ThreadManagement::SendDebuggerExecDoneSignal();
544     // wait inside pause
545     pause();
546     //clean current seqexp
547     interrupted = false;
548 }
549
550 void DebuggerManager::stop(const ast::Exp* pExp, int index)
551 {
552     //send stop information to all debuggers
553     setExp(pExp);
554     sendStop(index);
555     // because stop is used only in the debuggervisitor the pause
556     // will be executed in the main thread (where is executed the command)
557     internal_stop();
558     clearExp();
559 }
560
561 void DebuggerManager::errorInFile(const std::wstring filename, const ast::Exp* pExp)
562 {
563     setExp(pExp);
564     sendErrorInFile(filename);
565     internal_stop();
566     clearExp();
567 }
568 void DebuggerManager::errorInScript(const std::wstring funcname, const ast::Exp* pExp)
569 {
570     setExp(pExp);
571     sendErrorInScript(funcname);
572     internal_stop();
573     clearExp();
574 }
575
576 }