Websites Navigation: Airbit | Shop | m-shell.net
Languages: EN | DE

Module debug: Runtime Debugging

This module allows to create a debuggable process and provides access to its data and code.

The typical sequence of calls is:

  1. Open a script for debugging with debug.open, producing a debuggable process.
  2. Compile and load the code of the process via debug.compile.
  3. If compilation was successful, information about the code units (modules, classes, functions) can be obtained via debug.ccount, debug.cindex, debug.cinfo.
  4. Likewise, information about the variables (module variables, class member variables, function parameters and local variables) can be obtained via debug.vcount, debug.vindex, debug.vinfo.
  5. Set or clear breakpoints as desired with debug.breakp.
  6. Execute the process with debug.go, either stepwise, or until a breakpoint is hit, or until it is paused asynchronously with debug.pause.
  7. Check the process state, and check for runtime errors with debug.state.
  8. Examine the current position in code with debug.fcount and debug.pos.
  9. Examine the variable values and types with debug.vglobal and debug.vlocal.
  10. Close the process via debug.close.

Module, Class, Function and Variable Indices

All information about the debuggable process is accessed via indices:
  • A module index mod denotes a module. mod=0 is always the main module (script module).
  • A class index cls denotes a class within a module. cls=0 refers to the functions and variables of the module itself.
  • A function index func denotes a function of a module or a class:

    clsDenoted function
    0Function in module mod.
    >0Function in class cls of module mod.
  • A variable index var denotes a variable of a module, class or function:

    clsfuncDenoted variable
    0<0Global variable of module mod.
    0>=0Local variable or parameter of function func of module mod.
    >0<0Member variable of class cls of module mod.
    >0>=0Local variable or parameter of function func of class cls of module mod.
A negative index stands for "Unknown" or "not applicable". See also the function descriptions below.

All functions of module debug throw ExcIndexOutOfRange if the item with a given index does not exist.

Code Positions and Frames

Code positions always refer to a character position in the corresponding source file (which may be different from the character's byte position). New lines always count as one character, regardless of their actual representation in the file.

In short, a code position rather corresponds to a document position in a text editor or viewer than to a file position.

When execution of the debuggable process is paused, the current code position is within a series of nested function calls. Each function call corresponds to a frame. frame=0 always refers to the topmost frame, i.e. the currently executing function. frame=1 refers to the caller of the currently executing function, and so on. The number of frames can be obtained with debug.fcount. debug.fcount(process)-1 therefore always refers to the frame of the main code.

Example

Assume the following (not particulary useful) script SampleScript:

use ui
const DEFAULTMUL=20
class C
  p
  function init(p=..DEFAULTMUL)
    this.p=p
  end
  function mul(n)
    return n*p
  end
end
function fact(n)
  if n>1 then
    res=n*fact(n-1)
  else
    res=1
  end;
  return res
end
c:C=C(13)
n=ui.query("n","Debuggable",10)
print "n=" + n
print "fact=" + c.mul(fact(n))
print "fact2=" + c.mul("a")

Load this script with the runtime debug module:

// open and compile the script
d=debug.open("SampleScript")
debug.compile(d)
// list information about the modules
for i=0 to debug.ccount(d)-1 do
  print debug.cinfo(d,i)
end
→ [C:\documents\mShell\SampleScript.m,-1,0,-1,-1,,1]
[,-1,1,-1,-1,ui,1]
// get information about fact() (module 0, "class" 0)
fact=debug.cinfo(d,0,0,debug.cindex(d,"fact",0,0));
print fact
→ [C:\documents\mShell\SampleScript.m,155,0,0,40,fact,0]

Now run it, demonstrating breakpoints and single stepping:

// set a breakpoint at the start of fact()
debug.breakp(d,fact["mod"],fact["pos"])
// run the script, hitting the breakpoint three times
for i=1 to 3 do
  debug.go(d); debug.wait(d)
end
// list the call frames and the values of n in fact()
n=debug.vindex
  (d,"n",fact["mod"],fact["cls"],fact["func"]);
for i=0 to debug.fcount(d)-1 do
  print debug.pos(d,i);
  if debug.pos(d,i)["func"]=fact["func"] then
    print "n=",debug.vlocal(d,n,i)
  end
end
→ [C:\documents\mShell\SampleScript.m,155,0,0,40]
n= [8,Number]
[C:\documents\mShell\SampleScript.m,168,0,0,40]
n= [9,Number]
[C:\documents\mShell\SampleScript.m,168,0,0,40]
n= [10,Number]
[C:\documents\mShell\SampleScr
// single step from here
debug.go(d,debug.step); debug.wait(d);
print debug.pos(d)
[C:\documents\mShell\SampleScript.m,168,0,0,40]
// get the index of global variable c
c=debug.vindex(d,"c",0);
// print its value and type
print debug.vglobal(d,0,c)
→ [.C(p=13),Instance,0,1]
// print the value and type of c.p
C=debug.cindex(d,"C",0);
p=debug.vindex(d,"p",0,C);
print debug.vglobal(d,0,c,[p])
→ [13,Number]

Demonstrate how exceptions can be handled ("post-mortem debugging"):

// remove the breakpoint and run to termination
debug.breakp(d,fact["mod"],fact["pos"],false);
debug.go(d); debug.wait(d)
// find that an exception was thrown
print debug.state(d)
→ ExcStringNotNumber: Operand is a string,not a number
// list the call stack
for i=0 to debug.fcount(d)-1 do
  print debug.pos(d,i)
end
→ [C:\documents\mShell\SampleScript.m,119,0,2,1]
[C:\documents\mShell\SampleScript.m,313,0,0,0]
// variables are still accessible, so
// get the value of n in C.mul
mul=debug.cindex(d,"mul",0,C);
n=debug.vindex(d,"n",0,C,mul);
print debug.vlocal(d,n)
→ [a,String]

debug.breakp

• function breakp(process,mod,pos,enabled=true) → Number

Enables (if enabled=true) or disables (if enabled=false) the breakpoint in module mod at code position pos in the debuggable process. Execution will pause if an enabled breakpoint is reached.

Returns the real position where the breakpoint was enabled or disabled (breakpoints can only be set at the beginning of statements).

Throws ErrNotFound if the code position does not exist. Throws ErrInUse if process is executing.

debug.close

• function close(process) → null

Closes the debuggable process. Its state changes to debug.died.

debug.ccount

• function ccount(process,mod=-1,cls=-1) → Number

Returns the number of code units (or the maximum index + 1):

modclsCount returned
<0Number of modules.
>=0<0Number of classes in module mod.
>=00Number of functions in module mod.
>=0>0Number of functions in class cls in module mod.

debug.cindex

• function cindex(process,name,mod=-1,cls=-1) → Number

Returns the index of a code unit with name name:

modclsIndex returned
<0Index of module.
>=0<0Index of class in module mod.
>=00Index of function in module mod.
>=0>0Index of function in class cls in module mod.

debug.cinfo

• function cinfo(process,mod,cls=-1,func=-1) → Array

Returns information about a code unit:

clsfuncInformation returned
<0About module mod.
>0<0About class cls in module mod.
0>=0About function func in module mod.
>0>=0About function func in class cls in module mod.

The information is returned as an array with the following fields:

KeyMeaningType
fileSource file pathString
posPosition in source fileNumber
modModule indexNumber
clsClass indexNumber
funcFunction indexNumber
nameName (e.g. function name)String
flagsFlag bits (see below)Number
superModModule index of base class (only if class)Number
superClsClass index of base class (only if class)Number

flags is a combination of the following values:

• const isnative = 1 A function or variable defined in a native module.

• const isinherited = 2 An inherited function (not overwritten).

• const isconst = 4 A const variable.

debug.compile

• function compile(process) → null|Array

Compile the debuggable process. Returns null if successful, an array with the following fields if an error occured:

KeyMeaningType
msgError messageString
fileSource file path with errorString
posPosition in source fileNumber

Throws ErrInUse if process is not stopped.

debug.fcount

• function fcount(process) → Number

Return the number of frames (nested function calls) of the debuggable process.

Throws ErrNotReady if process has not been started. Throws ErrInUse if process is executing.

debug.go

• function go(process,mode=debug.run,arg="") → null

Continues execution the debuggable process (or starts it), either until a breakpoint is hit, or the condition implied by mode occurs. If the process is started, arg is passed to it as a parameter.

mode determines the condition when execution pauses:

• const run = 0 Execute until a breakpoint is hit, an exception occurs, or the process terminates normally.

• const stepinto = 1 Execute the next statement, stepping into function calls.

• const step = 2 Execute the next statement, behaving like debug.run within functions called from this frame.

• const stepout = 3 Execute until the current function returns, otherwise behaving like debug.run.

Throws ErrInUse if process is not compiled or paused.

debug.open

• function open(name) → Native Object

Opens the script with name name to debug it, creates a new debuggable process, and returns it. The script is not yet compiled or loaded.

Throws ErrNotFound if the script does not exist.

debug.pause

• function pause(process) → null

Pauses the debuggable process, as if a breakpoint has been hit.

debug.pos

• function pos(process,frame=0) → Array

Get the current position of execution for the frame with index frame. The position is returned as an array with the following fields:

KeyMeaningType
fileSource file pathString
posPosition in source fileNumber
modModule indexNumber
clsClass indexNumber
funcFunction indexNumber

Throws ErrNotReady if process has not been started. Throws ErrInUse if process is executing.

debug.state

• function state(process) → Number|String

Get the state the debuggable process is in.

If a string is returned, execution terminated with an exception, and the return value is the expression thrown (normally the error message).

If a number is returned, the debuggable is in one of the following states:

• const opened = 0 The process has been opened with debug.open.

• const compiled = 1 The process has been compiled successfully with debug.compile.

• const running = 2 The process is running and executing code.

• const waiting = 3 The process is running and waiting from some asynchronous external event (input, timeout, message arriving).

• const paused = 4 The process is not running (a breakpoint was hit, or an execution step was completed). It can be continued with debug.go.

• const ended = 5 The process terminated, either normally or with an exception. Variables can still be examined.

• const died = 6 The process has been closed and was removed.

debug.vcount

• function vcount(process,mod,cls=0,func=-1) → Number

Returns the number of variables (or the maximum variable index + 1):

clsfuncCount returned
0<0Number of global variables in module mod.
0>=0Number of local variables and parameters in function func in module mod.
>0<0Number of member variables in class cls in module mod.
>0>=0Number of local variables and parameters in function func in class cls in module mod.

debug.vglobal

• function vglobal(process,mod,var,follow=[]) → Array

Returns value and type of the global variable var in module mod of the debuggable process. If the value is an array or a class instance, its elements or member variables are derefenced in order by the element indices or member variable indices in follow.

The array returned has the following elements:

IndexMeaningType
0Value of variableNumber or String
1Type of variableString
2If Array, the number of elementsNumber
2If Instance, the module index of its classNumber
3If Instance, the class index of its classNumber

Note that non-numeric values are always returned as strings, since data from the debugged process cannot be accessed directly from the debugging process.

The possible types are Number, String, Array, Native, Boolean, null, Instance, Function, InstanceFunction.

Throws ErrNotReady if process has not been started. Throws ErrInUse if process is executing.

debug.vindex

• function vindex(process,name,mod,cls=0,func=-1) → Number

Returns the index of a variable with name name:

clsfuncIndex returned
0<0Index of global variable in module mod.
0>=0Index of local variable or parameter in function func in module mod.
>0<0Index of member variable in class cls in module mod.
>0>=0Index of local variable or parameter in function func in class cls in module mod.

debug.vinfo

• function vinfo(process,mod,cls,func,var) → Array

Returns information about a variable with index var:

clsfuncInformation returned
0<0About global variable in module mod.
0>=0About local variable or parameter in function func in module mod.
>0<0About member variable in class cls in module mod.
>0>=0About local variable or parameter in function func in class cls in module mod.

The information is returned as an array with the same fields as those returned by debug.cinfo:

KeyMeaningType
fileSource file pathString
pos-1Number
modModule indexNumber
clsClass indexNumber
funcFunction indexNumber
nameName of variableString
flagsFlag bitsNumber

debug.vlocal

• function vlocal(process,var,frame=0,follow=[]) → Array

Returns value and type of the local variable with index var in the function at frame frame of debuggable process. If the value is an array or a class instance, its elements or member variables are derefenced in order by the element indices or member variable indices in follow.

See debug.vglobal for information about the array returned.

Throws ErrNotReady if process has not been started. Throws ErrInUse if process is executing.

debug.wait

• function wait(process,timeout=-1) → Number|String

Waits until the debuggable process pauses or terminates, and returns its new state, like debug.state.

If timeout>=0 and timeout milliseconds have passed without the script pausing, the current state is returned.


© 2004-2011 airbit AG, CH-8008 Zürich
Document AB-M-TOO-887
mShell Home  > Documentation  > Manuals