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