debugger:
[scilab.git] / scilab / modules / core / sci_gateway / cpp / sci_debug.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #include "core_gw.hxx"
14 #include "function.hxx"
15 #include "string.hxx"
16 #include "printvisitor.hxx"
17 #include "execvisitor.hxx"
18 #include "debuggervisitor.hxx"
19 #include "configvariable.hxx"
20 #include "debugmanager.hxx"
21 #include "threadId.hxx"
22
23 extern "C"
24 {
25 #include "Scierror.h"
26 #include "sciprint.h"
27 #include "Thread_Wrapper.h"
28 }
29
30 typedef enum EnumCommand
31 {
32     AbortCommand,
33     BreakCommand,
34     ContinueCommand,
35     DisableCommand,
36     DeleteCommand,
37     EnableCommand,
38     HelpCommand,
39     HelpShortCommand,
40     ListCommand,
41     NextCommand,
42     QuitCommand,
43     ShowCommand,
44     StepInCommand,
45     StepOutCommand,
46     UnknowCommand,
47     WhereCommand
48 };
49
50 const char fname[] = "debug";
51
52 void print_help();
53 EnumCommand getCommand(const std::wstring& command);
54
55 types::Function::ReturnValue sci_debug(types::typed_list &in, int _iRetCount, types::typed_list &out)
56 {
57     if (in.size() == 0)
58     {
59         //debugger already active
60         if (ConfigVariable::getEnableDebug())
61         {
62             return types::Function::OK;
63         }
64
65         //debugger can be lauch only on console scope level
66         if (symbol::Context::getInstance()->getScopeLevel() != SCOPE_CONSOLE)
67         {
68             Scierror(999, _("%s: Debugger can be activated only at console scope level\n"), fname);
69             return types::Function::Error;
70         }
71
72         ConfigVariable::setEnableDebug(true);
73         ConfigVariable::setDefaultVisitor(new ast::DebuggerVisitor());
74         return types::Function::OK;
75     }
76
77     if (ConfigVariable::getEnableDebug() == false)
78     {
79         Scierror(999, _("%s: Debugger is not running. Call \"%s\" without parameter first.\n"), fname, fname);
80         return types::Function::Error;
81     }
82
83     int iRhs = (int)in.size();
84     for (int i = 0; i < iRhs; i++)
85     {
86         if (in[i]->isString() == false || ((types::String*)in[i])->isScalar() == false)
87         {
88             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), fname, i + 1);
89             return types::Function::Error;
90         }
91     }
92
93     debugger::DebuggerMagager* manager = debugger::DebuggerMagager::getInstance();
94
95     std::wstring command(((types::String*)in[0])->get(0));
96     switch (getCommand(command))
97     {
98         case AbortCommand:
99         {
100             if (iRhs > 1)
101             {
102                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "abort", 0);
103                 return types::Function::Error;
104             }
105
106             //abort
107             if (manager->isInterrupted())
108             {
109                 manager->abort();
110             }
111             else
112             {
113                 sciprint("debugger is not paused\n");
114             }
115
116             return types::Function::OK;
117         }
118         case BreakCommand:
119         {
120             if (iRhs < 2 || iRhs > 4)
121             {
122                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "breakpoint", 1, 3);
123                 return types::Function::Error;
124             }
125
126             //breakpoint
127             wchar_t* pwstFunctionName = NULL;
128             int iLine = -1;
129             wchar_t* pwstCondition = NULL;
130             debugger::Breakpoint* bp = NULL;
131             //function name
132             if (iRhs > 1)
133             {
134                 //do not check name
135                 //we can set breakpoint before function declaration
136                 //for embedded function for example
137                 pwstFunctionName = ((types::String*)in[1])->get(0);
138             }
139
140             if (iRhs > 2)
141             {
142                 wchar_t* pwstLineNumber = ((types::String*)in[2])->get(0);
143                 wchar_t* pwstEnd = NULL;
144                 iLine = wcstol(pwstLineNumber, &pwstEnd, 10);
145                 if (pwstEnd == NULL || *pwstEnd != 0)
146                 {
147                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "breakpoint", 2);
148                     return types::Function::Error;
149                 }
150             }
151
152             if (iRhs > 3)
153             {
154                 pwstCondition = ((types::String*)in[3])->get(0);
155                 bp = new debugger::Breakpoint(pwstFunctionName, iLine, pwstCondition);
156             }
157             else
158             {
159                 bp = new debugger::Breakpoint(pwstFunctionName, iLine);
160             }
161
162             manager->addBreakPoint(bp);
163             return types::Function::OK;
164         }
165         case ContinueCommand:
166         {
167             if (iRhs > 1)
168             {
169                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "continue", 0);
170                 return types::Function::Error;
171             }
172
173             //continue
174             if (manager->isInterrupted())
175             {
176                 manager->resume();
177             }
178             else
179             {
180                 sciprint("debugger is not paused\n");
181             }
182
183             return types::Function::OK;
184         }
185         case DisableCommand:
186         {
187             if (iRhs > 2)
188             {
189                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "disable", 0, 1);
190                 return types::Function::Error;
191             }
192
193             //disable
194             if (iRhs == 2)
195             {
196                 wchar_t* pEnd = NULL;
197                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
198                 if (pEnd == NULL || *pEnd != 0)
199                 {
200                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "disable", 1);
201                     return types::Function::Error;
202                 }
203
204                 if (manager->getBreakPoint(iBp) == NULL)
205                 {
206                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "disable", iBp);
207                     return types::Function::Error;
208                 }
209
210                 manager->disableBreakPoint(iBp);
211             }
212             else
213             {
214                 manager->disableAllBreakPoints();
215             }
216
217             return types::Function::OK;
218         }
219         case DeleteCommand :
220         {
221             if (iRhs > 2)
222             {
223                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "delete", 0, 1);
224                 return types::Function::Error;
225             }
226
227             //delete
228             if (iRhs == 2)
229             {
230                 wchar_t* pEnd = NULL;
231                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
232                 if (pEnd == NULL || *pEnd != 0)
233                 {
234                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "disable", 1);
235                     return types::Function::Error;
236                 }
237
238                 if (manager->getBreakPoint(iBp) == NULL)
239                 {
240                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "delete", iBp);
241                     return types::Function::Error;
242                 }
243
244                 manager->removeBreakPoint(iBp);
245             }
246             else
247             {
248                 manager->removeAllBreakPoints();
249             }
250
251             return types::Function::OK;
252         }
253         case EnableCommand:
254         {
255             if (iRhs > 2)
256             {
257                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "enable", 0, 1);
258                 return types::Function::Error;
259             }
260
261             //enable
262             if (iRhs == 2)
263             {
264                 wchar_t* pEnd = NULL;
265                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
266                 if (pEnd == NULL || *pEnd != 0)
267                 {
268                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "enable", 1);
269                     return types::Function::Error;
270                 }
271
272                 if (manager->getBreakPoint(iBp) == NULL)
273                 {
274                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "enable", iBp);
275                     return types::Function::Error;
276                 }
277
278                 manager->enableBreakPoint(iBp);
279             }
280             else
281             {
282                 manager->enableAllBreakPoints();
283             }
284
285             return types::Function::OK;
286         }
287         case HelpCommand:
288         {
289             if (iRhs > 1)
290             {
291                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "help", 0);
292                 return types::Function::Error;
293             }
294
295             if (ConfigVariable::getScilabMode() == SCILAB_NW || ConfigVariable::getScilabMode() == SCILAB_STD)
296             {
297                 StorePrioritaryCommand("help debug");
298                 return types::Function::OK;
299             }
300
301             //continue tp HelpShortCommand
302         }
303         case HelpShortCommand:
304         {
305             if (iRhs > 1)
306             {
307                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "help", 0);
308                 return types::Function::Error;
309             }
310
311             //help
312             print_help();
313             return types::Function::OK;
314         }
315         case ListCommand:
316         {
317             if (iRhs > 1)
318             {
319                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "list", 0);
320                 return types::Function::Error;
321             }
322
323             if (manager->isInterrupted())
324             {
325                 std::wostringstream ostr;
326                 ast::PrintVisitor pp(ostr, true, true, true);
327                 manager->getExp()->accept(pp);
328                 sciprint(_("%ls"), ostr.str().data());
329             }
330             else
331             {
332                 sciprint("debugger is not paused\n");
333             }
334             return types::Function::OK;
335         }
336         case StepInCommand:
337         {
338             if (iRhs > 1)
339             {
340                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "stepin", 0);
341                 return types::Function::Error;
342             }
343
344             if (manager->isInterrupted())
345             {
346                 manager->setStepIn();
347                 manager->resume();
348             }
349             return types::Function::OK;
350         }
351         case NextCommand:
352         {
353             if (iRhs > 1)
354             {
355                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "next", 0);
356                 return types::Function::Error;
357             }
358
359             if (manager->isInterrupted())
360             {
361                 manager->setStepNext();
362                 manager->resume();
363             }
364             else
365             {
366                 sciprint("debugger is not paused\n");
367             }
368             return types::Function::OK;
369         }
370         case StepOutCommand:
371         {
372             if (iRhs > 1)
373             {
374                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "stepout", 0);
375                 return types::Function::Error;
376             }
377
378             //need to level to go stepout
379             if (manager->isInterrupted())
380             {
381                 manager->setStepOut();
382                 manager->resume();
383             }
384             else
385             {
386                 sciprint("debugger is not paused\n");
387             }
388             return types::Function::OK;
389         }
390         case QuitCommand:
391         {
392             if (iRhs > 1)
393             {
394                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "quit", 0);
395                 return types::Function::Error;
396             }
397
398             //quit : disable debugger + abort + quit
399             ConfigVariable::setEnableDebug(false);
400             ConfigVariable::setDefaultVisitor(new ast::ExecVisitor());
401             manager->abort();
402             manager->sendQuit();
403             return types::Function::OK;
404         }
405         case ShowCommand:
406         {
407             if (iRhs > 2)
408             {
409                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "show", 0, 1);
410                 return types::Function::Error;
411             }
412
413             sciprint("% 3ls % 7ls %24ls % 5ls %ls\n\n", L"num", L"enable", L"function name", L"line", L"condition");
414
415             if (iRhs > 1)
416             {
417                 wchar_t* pEnd = NULL;
418                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
419                 if (pEnd == NULL || *pEnd != 0)
420                 {
421                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "disable", 1);
422                     return types::Function::Error;
423                 }
424
425                 debugger::Breakpoint* bp = manager->getBreakPoint(iBp);
426                 if (bp == NULL)
427                 {
428                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "showbreakpoint", iBp);
429                     return types::Function::Error;
430                 }
431
432                 if (bp->isMacro())
433                 {
434                     std::wstring condition = bp->getCondition();
435                     sciprint("% 3d % 7s %24ls % 5d %ls\n", iBp, bp->isEnable() ? "true" : "false", bp->getFunctioName().c_str(), bp->getMacroLine(),
436                              condition.size() < 30 ? condition.c_str() :
437                              (std::wstring(condition.begin(), condition.begin() + 27) + L"...").c_str());
438                 }
439             }
440             else
441             {
442                 debugger::Breakpoints bps = manager->getAllBreakPoint();
443                 debugger::Breakpoints::iterator it = bps.begin();
444                 for (int i = 0; it != bps.end(); ++it, ++i)
445                 {
446                     debugger::Breakpoint* bp = *it;
447                     if (bp->isMacro())
448                     {
449                         std::wstring condition = bp->getCondition();
450                         sciprint("% 3d % 7s %24ls % 5d %ls\n", i, bp->isEnable() ? "true" : "false", bp->getFunctioName().c_str(), bp->getMacroLine(),
451                                  condition.size() < 30 ? condition.c_str() :
452                                  (std::wstring(condition.begin(), condition.begin() + 27) + L"...").c_str());
453                     }
454                 }
455             }
456
457             return types::Function::OK;
458         }
459         case WhereCommand:
460         {
461             if (iRhs > 1)
462             {
463                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "where", 0);
464                 return types::Function::Error;
465             }
466
467             if (manager->isInterrupted() == false)
468             {
469                 sciprint("debugger is not paused\n");
470                 return types::Function::OK;
471             }
472
473             int curLine = (manager->getExp()->getLocation().first_line - ConfigVariable::getMacroFirstLines()) + 1;
474
475             //where
476             int i = 0;
477             sciprint("%s\n", _("callstack:"));
478
479             std::wostringstream ostr;
480             ast::PrintVisitor pp(ostr, true, true, true);
481             manager->getExp()->accept(pp);
482 #define BT_PRINT "#%-5d%ls (line %d)\n"
483             sciprint("#%-5d%ls\n", 0, ostr.str().data());
484
485             ConfigVariable::WhereVector where = ConfigVariable::getWhere();
486             auto it1 = where.rbegin();
487             auto it2 = ++where.rbegin();
488
489             sciprint(_(BT_PRINT), 1, it2->m_name.data(), curLine);
490             ++it1;
491             ++it2;
492             for (int j = 2; it2 != where.rend(); it1++, it2++, j++)
493             {
494                 sciprint(_(BT_PRINT), j, it2->m_name.data(), it1->m_line);
495             }
496
497             return types::Function::OK;
498         }
499
500         case UnknowCommand:
501         default :
502             break;
503     }
504
505     sciprint("Unknown command \"%ls\".\n\n", command.c_str());
506     sciprint("use 'h' for more information\n\n");
507     return types::Function::OK;
508 }
509
510 void print_help()
511 {
512     //a,b,c,d,h,i,n,o,q,s,w
513
514     sciprint(_("debug commands : \n"));
515     sciprint("  h                            : %s.\n", _("show this help"));
516     sciprint("  help                         : %s.\n", _("open debug documentation page"));
517     sciprint("\n");                          
518     sciprint("  (q)uit                       : %s.\n", _("stop debugging"));
519     sciprint("  (w)here or bt                : %s.\n", _("show callstack"));
520     sciprint("\n");                          
521     sciprint("  (e)xec cmd                   : %s.\n", _("execute cmd"));
522     sciprint("  (r)un cmd                    : %s.\n", _("execute cmd"));
523     sciprint("\n");                          
524     sciprint("  (d)isp var                   : %s.\n", _("display variable"));
525     sciprint("  (p)rint var                  : %s.\n", _("display variable"));
526     sciprint("\n");                          
527     sciprint("  (c)ontinue                   : %s.\n", _("continue execution"));
528     sciprint("  (a)bort                      : %s.\n", _("abort execution"));
529     sciprint("  step(n)ext or next           : %s.\n", _("continue to next statement"));
530     sciprint("  step(i)n or in               : %s.\n", _("step into function"));
531     sciprint("  step(o)ut or out             : %s.\n", _("step outside function"));
532     sciprint("\n");
533     sciprint("  (b)reakpoint or break\n     func [line [\"condition\"]] : %s.\n", _("add a breakpoint"));
534     sciprint("  (del)ete                     : %s.\n", _("delete all breakpoints"));
535     sciprint("  (del)ete n                   : %s.\n", _("delete a specific breakpoint"));
536     sciprint("  enable                       : %s.\n", _("enable all breakpoints"));
537     sciprint("  enable n                     : %s.\n", _("enable a specific breakpoint"));
538     sciprint("  disable                      : %s.\n", _("disable all breakpoints"));
539     sciprint("  disable n                    : %s.\n", _("disable a specific breakpoint"));
540     sciprint("  (s)how                       : %s.\n", _("show all breakpoints"));
541     sciprint("  (s)how n                     : %s.\n", _("show a specific breakpoint"));
542     sciprint("\n");
543     sciprint(_("  for more details, show help page.\n"));
544 }
545
546 EnumCommand getCommand(const std::wstring& command)
547 {
548     wchar_t c = command[0];
549
550     switch (c)
551     {
552         case L'a':
553         {
554             if (command.size() == 1 || command == L"abort")
555             {
556                 return AbortCommand;
557             }
558             break;
559         }
560         case 'b':
561         {
562             if (command.size() == 1 || command == L"break" || command == L"breakpoint")
563             {
564                 return BreakCommand;
565             }
566
567             if (command == L"bt")
568             {
569                 return WhereCommand;
570             }
571             break;
572         }
573         case L'c':
574         {
575             if (command.size() == 1 || command == L"continue")
576             {
577                 return ContinueCommand;
578             }
579             break;
580         }
581         case L'd':
582         {
583             if (command == L"disable")
584             {
585                 return DisableCommand;
586             }
587
588             if (command == L"del" || command == L"delete")
589             {
590                 return DeleteCommand;
591             }
592             break;
593         }
594         case L'e':
595         {
596             if (command == L"enable")
597             {
598                 return EnableCommand;
599             }
600             break;
601         }
602         case L'h':
603         {
604             if (command.size() == 1)
605             {
606                 return HelpShortCommand;
607             }
608
609             if (command == L"help")
610             {
611                 return HelpCommand;
612             }
613
614             break;
615         }
616         case L'l':
617         {
618             if (command.size() == 1 || command == L"list")
619             {
620                 return ListCommand;
621             }
622             break;
623         }
624         case L'i':
625         {
626             if (command.size() == 1 || command == L"in")
627             {
628                 return StepInCommand;
629             }
630             break;
631         }
632         case L'n':
633         {
634             if (command.size() == 1 || command == L"next")
635             {
636                 return NextCommand;
637             }
638             break;
639         }
640         case L'o':
641         {
642             if (command.size() == 1 || command == L"out")
643             {
644                 return StepOutCommand;
645             }
646             break;
647         }
648         case L'q':
649         {
650             if (command.size() == 1 || command == L"quit")
651             {
652                 return QuitCommand;
653             }
654             break;
655         }
656         case L's':
657         {
658             if (command.size() == 1 || command == L"show")
659             {
660                 return ShowCommand;
661             }
662             if (command == L"stepnext")
663             {
664                 return NextCommand;
665             }
666             if (command == L"stepin")
667             {
668                 return StepInCommand;
669             }
670             if (command == L"stepout")
671             {
672                 return StepOutCommand;
673             }
674             break;
675         }
676         case L'w':
677         {
678             if (command.size() == 1 || command == L"where")
679             {
680                 return WhereCommand;
681             }
682             break;
683         }
684     }
685
686     return UnknowCommand;
687 }