jsish
Debugging
Not logged in

Jsi comes with two script debuggers, command-line and GUI.

But before resorting to the debugger it's usually a good idea to enable strict mode, and make use of logging.

Strict Mode

Strict checking is enabled by adding the "use strict" directive to the top of the file:

"use strict";
function foo (a:number, b:string='ok'):number {}

Among other things, this will generate an error when a function:

This directive should go on the first line (or second if there is a #!). You should avoid adding it inside individual functions.


Debugger GUI

Although Jsi's comes with a command-line debugger (described below) a web-browser based GUI is also available using WebSockets, eg:

jsish -D tests/simple.js

See tests/simple.js.

The DebugUI shares the same commands as the command-line debugger, but adds full-screen GUI features such as source navigation and double-click to set breakpoints.


Debugger

Jsi comes with a built-in gdb-like command-line debugger, that is invoked with -d:

jsish -d simple.jsi

The debugger will stop automatically when a debugger; statement is encountered, or anytime an error or warning occurs (eg. during "strict mode").

Commands

The usual debugger commands are supported:

CommandArgumentDescription
break file:line|funcBreak execution at a named function, line or file
continueContinue execution
deleteidDelete one or all breakpoints
disable idDisable one or all breakpoints
downcountMove down one or more stack levels
enableidEnable one or all breakpoints
evalexpressionEvaluate expression in program context
finishRun till return of current function
helpstringDisplay command usage
infobreakpoints|variablesShow status info
listproc|line countList file lines
nextSingle-step over function calls
print namePrint value of variable
quitQuit debugging current program and exit
stepSingle-step into function calls
tbreak Set a temporary breakpoint that is disabled when hit
upcountMove up one or more stack levels
where Display current location
xeval expressionDoes eval in debugger context

Debugging

Here is a sample session on ../tests/simple.js:

jsish -d /tmp/simple.js
#1:/tmp/simple.js:16  foo(); 
#1==> s   
CMD: step
#2:/tmp/simple.js:12    var x = 88; <in function foo()>
#2==> 
#2:/tmp/simple.js:13    foo1(); <in function foo()>
#2==> 
#3:/tmp/simple.js:7    var x = 99; <in function foo1()>
#3==> c
CMD: continue
#4:/tmp/simple.js:3    debugger; <in function foo2()>
#4==> up
CMD: up
#3:/tmp/simple.js:8    foo2(); <in function foo1()>
#3==> p x
CMD: print
RESULT= "99"
#3==> up
CMD: up
#2:/tmp/simple.js:13    foo1(); <in function foo()>
#2==> p x
CMD: print
RESULT= "88"
#2==> 

Note that just like gdb, an empty commands repeats the previous command.

Listing

Source file lines can be displayed with the list command:

jsish -d /tmp/simple.js
#1:/tmp/simple.js:16  foo(); 
#1==> c
CMD: continue
#4:/tmp/simple.js:3    debugger; <in function foo2()>
#2==> l 1 20
CMD: list
FILE: /tmp/simple.js:1
1    : // Simple test script for the debugger.
2    : function foo2() {
3    :   debugger;
4    : }
5    : 
6    : function foo1() {
7    :   var x = 99;
8    :   foo2();
9    : }
10   : 
11   : function foo() {
12   :   var x = 88;

Optional arguments are: startLine|func numLines file

With no arguments the default is to list 10 lines starting from the current line in the current file.

Print

The print command can be used to display the value of variables:

jsish -d /tmp/simple.js
#1:/tmp/simple.js:16  foo(); 
#1==> s
CMD: step
#2:/tmp/simple.js:12    var x = 88; <in function foo()>
#2==> s
CMD: step
#2:/tmp/simple.js:13    foo1(); <in function foo()>
#2==> p x
CMD: print
RESULT= "88"

Eval

The eval command can be used to evaluate expresssions or modify values:

jsish -d /tmp/simple.js
#1:/tmp/simple.js:16  foo(); 
#1==> c
CMD: continue
#4:/tmp/simple.js:3    debugger; <in function foo2()>
#4==> up
CMD: up
#3:/tmp/simple.js:8    foo2(); <in function foo1()>
#3==> p x
CMD: print
RESULT= "99"
#3==> ev x=9
CMD: eval
RESULT= 9
#3==> p x
CMD: print
RESULT= "9"

Breakpoints

Breakpoints can be set, cleared and queried as in the following example:

jsish -d /tmp/simple.js
#1:/tmp/simple.js:16  foo(); 
#1==> s
CMD: step
#2:/tmp/simple.js:12    var x = 88; <in function foo()>
#2==> b
CMD: break
breakpoint #1 set: /tmp/simple.js:12
#2==> b foo
CMD: break
breakpoint #2 set: foo
#2==> c
CMD: continue
Stopped at breakpoint #2
#2:/tmp/simple.js:13    foo1(); <in function foo()>
#2==> info
CMD: info
#1    : enabled=true, hits=0, file=/tmp/simple.js:12
#2    : enabled=true, hits=1, func=foo
#2==> dis 1
CMD: disable
#2==> info
CMD: info
#1    : enabled=false, hits=0, file=/tmp/simple.js:12
#2    : enabled=true,  hits=1, func=foo

Note that the debugger will stop whenever a debugger statement is encountered.

Where

The where command outputs a stack backtrace:

jsish -d /tmp/simple.js
#1:/tmp/simple.js:16  foo(); 
#1==> c
CMD: continue
#4:/tmp/simple.js:3    debugger; <in function foo2()>
#4==> wh
CMD: where
{ fileName:"/tmp/simple.js", funcName:"foo2", level:4, line:3 }
{ fileName:"/tmp/simple.js", funcName:"foo1", level:3, line:8 }
{ fileName:"/tmp/simple.js", funcName:"foo", level:2, line:13 }
{ fileName:"/tmp/simple.js", funcName:"", level:1, line:16 }
#4==> up 2
CMD: up
#2:/tmp/simple.js:13    foo1(); <in function foo()>
#2==> wh
CMD: where
{ fileName:"/tmp/simple.js", funcName:"foo", level:2, line:13 }
{ fileName:"/tmp/simple.js", funcName:"", level:1, line:16 }
#2==>

Implementation

The debugger runs the target script in a sub-interpreter.

The source: ../lib/Jsi_Debug.jsi

Source for the GUI: ../lib/Jsi_DebugUI/Jsi_DebugUI.jsi

Caveat: Jsi bends the memory management rules of Sub-interps a bit to make debugging mode work seamlessly, a side-effect of which is that a small amount of memory may leak during the debug session.