Debugging With UDB

Version 1.4

Ziad Al-Sharif
July , 2008
Unicon Technical Report #10







Abstract


This report is the primary user documentation for the UDB source level debugger for Icon and Unicon. UDB is written in Unicon and uses the execution monitoring facilities. It combines a traditional debugging interface with many novel features. UDB is still under active development; this report is preliminary but reflects the current implementation in the Unicon language distribution.







http://unicon.sourceforge.net/utr/utr10.html

Department of Computer Science
University of Idaho
Moscow, ID 83843





Contents

  1. About UDB
  2. Getting In and Out of UDB
    1. Invoking UDB
    2. Quitting UDB
  3. The Console
    1. Command syntax
    2. Getting help
  4. Running Programs Under UDB
    1. Loading your program
    2. Starting your program
    3. Your program's input and output
  5. Stopping and Continuing
    1. Setting break points
    2. Setting watch points
    3. Deleting break points
    4. Stepping and continuing
  6. Examining the Stack
    1. Information about a frame
    2. Selecting a frame
    3. Back tracing
  7. Examining Data
    1. Getting a peek at the value of a variable
    2. Changing the value of a variable
  8. Examining Source Files
    1. Printing source lines
    2. Found and missing source files
  9. Tracing
    1. Tracing a variable
    2. Tracing an execution behavior
      1. Tracing procedure activities
      2. Tracing built-in function activities
      3. Tracing built-in operation activities
      4. Tracing string scanning activities
  10. Extensible Debugging
    1. Internal monitors (Library of Monitors)
      1. Enabling a library monitor
      2. Disabling a library monitor
      3. Analyze information in the internal monitor
      4. Print information from the internal monitor
      5. Information about library monitors
    2. External monitors (Stand-alone Monitoring Tools)
      1. Loading externals
      2. Enabling externals
      3. Disabling externals
      4. Information about externals
    3. Migration form externals to internals
      1. Simple monitors
      2. Complex monitors
  11. Future Work
  12. References

1. About UDB
UDB is a source-level debugger built on top of a monitoring framework called the Alamo framework [1]. Alamo stands for A Lightweight Architecture for MOnitoring; it is built into Unicon's virtual machine [2]. The main goal of UDB is to allow you to see what is going on inside your program during its execution or to see what your program was doing when it crashed. You can use UDB to debug programs written in Icon [3] and Unicon [2].

UDB features the classical debugging techniques found in a conventional debugger such as GDB [4]. At the same time, it has a rich set of advanced debugging techniques; one of those advanced techniques is an extensive execution behavior tracer. UDB also utilize some automatic debugging techniques to catch some predefined set of elusive bugs.

In UDB, you can run your program. If it is ever stopped, you will be able to examine what has happened, and you may change things to fix the problem or you may specify anything that might affect its behavior. Furthermore, you can use UDB's tracing facilities to comprehend different behavioral aspects of the execution, you can trace the entire execution or just any portion of it that starts and ends on specified condition. The automated techniques for catching some predefined situation, where it is possibly a bug, is huge advancement toward automating the debugging process.


2. Getting In and Out of UDB
Once UDB is started, it provides a console as an interface between you and the debugging session until you exit it.
 

2.1. Invoking UDB
To invoke UDB, run the program udb in one of the following formats:

udb
Starts a UDB session without any loaded program, then if you want to load or reload a program into udb after udb is already started, the command "load" must be used.

udb program
Starts a UDB session and loads the executable named "program" at the same time.

udb program arguments
Starts a UDB session and loads the executable named "program" into the udb session, that executable "program" can make use of the argument list "arguments" as parameters to that program.
 

2.2. Quitting UDB
To exit UDB type the command quit at any point during the debugging session.

quit
q
Exits UDB, if there is any program is running, a question will show up asking about your permission to quit UDB, if you are sure to exit, jut type "y", otherwise type "n" to ignore the quit command.
 

3. The Console
UDB console provides an interface between you and the udb session. You can repeat any UDB command by pressing just ENTER. You can also use the UP/DOWN keys to get UDB to find you a command from the list of the current session command history .
 

3.1. Command syntax
UDB commands can be formed in a single line of input. A command usually starts with a command name, then followed by zero or more arguments. Arguments are based on the command itself, each command has different set of possible arguments. A blank line as input to UDB means to repeat the previous command.
 

3.2. Getting help
You can always ask UDB itself for information on its commands, using the command help.

help
h

Prints a list of all possible commands in the current debugging situation, the list includes a brief description of each command.

help command
h command

Prints a complete description of the command "command" and its possible arguments.
 

4. Running Programs Under UDB
When you run a program under UDB, no recompilation of the program is needed. You just load your program under UDB as follows:
 

4.1. Loading your program
You may load your program when you start UDB. If you did not, from within UDB you can load/reload your program, at any time, using one of the following ways:

load program
Loads the executable program named "program" into the UDB session.

load program arguments
Loads the executable program named "program" into the UDB session and passes the argument list "arguments" into that loaded program.
 

4.2. Starting your program
Use the run command to start your program under UDB. You may specify the argument list, if any. If you already pre-specified the argument list when you loaded the program, then you do not have to re-specify it, unless you want to re-define it or to run the program with different arguments.

run
r

Runs the loaded program under UDB. It can be used also to re-run the program at any time during the UDB session.

run arguments
r arguments

Runs the loaded program with the argument list "arguments", if the program is running or was running previously, then it will re-run the program with this new argument list "arguments".
 

4.3. Your program's input and output (Not implemented yet)
By default, UDB switches the terminal to its own terminal modes to interact with you. The program you run under UDB does its input and output to the same terminal that UDB is using. In the current implementation, UDB supports no way to redirect your program's input and/or output using the shell redirection with the run command.
 

5. Stopping and Continuing
One of the main goals of a source-level debugger is that you can stop your program before it terminates. While your program is running under UDB, it may stop if it reaches a break point, a watch point, or a new line after the UDB's step or next commands. Stopping the program in the middle of the execution allows you to investigate any trouble and find its actual cause. You may use any of the UDB commands to examine and/or change the state of your program, or even set and/or remove break points or watch points before you continue the execution.
 

5.1. Setting break points
Break points are places where you like the program to stop its execution so you can investigate.

break
b

Prints out all of the break points that were set previously.

break linenum
b linenum

Checks if there is a code in that line number "linenum", if yes then it sets a break point in that line, if no source code, then it prints out an error message.

break filename linenum
b filename linenum

Sets a break point on the line number "linenum" in that specified filename "filename".

break procedure
b procedure

Searches in the source code for that procedure named "procedure". If there is one, it sets a break point on the line number of the procedure entrance, otherwise, it prints out an error message.
 

5.2. Setting watch points
Watch points enable you to stop the execution whenever some expression is evaluated or a variable changes its value.

watch
Prints a list of all the predefined set of watched expressions and/or variables

watch variable
If the program is loaded but it is not running yet, the semantic of this command assumes that the variable "variable" is one of the global variables, else if the program is already running and it is been stopped for a legitimate reason, then the semantic of this command assumes that the variable "variable" is a local variable in the current procedure or current stack frame. In both cases, UDB will break at every line that the variable "variable" is evaluated and changed its value.

watch variable procedure
Breaks at every line that the local variable "variable" in the specific procedure "procedure" is evaluated and changed its value. The semantic of this command assumes that the variable "variable" is local to that procedure named "procedure" regardless if the program is running or not.
 

5.3. Deleting break points
The delete command deletes an individual break point by specifying its line number or its procedure name.

delete linenum
Deletes the break point that is already on that line number "linenum"

delete procedure
Deletes the break point that is already on that procedure named "procedure"
 

5.4. Stepping and continuing
Stepping using the command "step" means executing just one line of your program source code. Stepping using the command "next" means continue to the next source line in the current stack frame; "next" is similar to "step" but without going inside any procedures or function calls that appear within the source code. In "next", execution stops when control reaches a different line of source code at the original stack level that the control was in when you gave the "next" command. Continuing using the "continue" command means resuming program execution until your program completes normally or reaches another break point or watch point.

step
s

Steps one source line in the execution of the program

step count
s count

Steps a number of lines, in the source program, that are equal to "count". The default value of "count" is one.

next
n

Steps one source line in the source program. If that source line has any procedure or function call, the control will not step anywhere inside that call, and the called procedure or function will be evaluated without showing any stepping inside.

next count
n count
Steps a number of source lines that is equal to "count". Stepping each line without showing any control detail for any procedure or function call that may occur in that source line. Each source line will be evaluated as one line without showing any steps of control inside any call from that line.

continue
cont
c

Resumes the program's execution at its normal speed until it terminates or reaches a break point or a watch point.
 

6. Examining the Stack
When a program performs a procedure call, information about the call is generated and saved in the execution stack in a block called the procedure frame. Each frame includes the level, the arguments, and the local variables of the called procedure. The procedure frame is saved on the stack until the procedure is returned. However, when the program is stopped, you may need to know where and/or how it got there; UDB commands help you do that.

By default, when the program stops, UDB points implicitly to the current procedure frame, which is the last frame on the execution stack. However, you can explicitly jump to any frame by making the current frame whichever frame number you are interested in. This is important because there is some UDB commands refer implicitly to the current selected frame. In particular, whenever you ask UDB for the value of a variable, the variable is supposed to be found in the current selected frame.
 

6.1. Information about a frame
You can obtain information, about the current state of the execution stack and its frames, using one of the following commands:

frame
f

Prints a brief description of the current selected stack frame plus a list of the global variables, local variables, and the formal parameters. When it is used without any argument, this command does not change the current selected frame.

frame n (not implemented yet)
f n

Prints a brief description of the frame number "n". By default the current farm is fame number 0, which is the innermost, the oldest frame on the the stack has the biggest frame number, which is the frame for main. This command does change the current selected frame by making it pointing at the frame number "n".

level
Prints out the number of levels (number of frames) that are in the execution stack.
 

6.2. Selecting a frame
You can select a frame from the current execution stack using one of the following commands:

up
Moves the current frame pointer one frame up in the execution stack. Assuming the stack is growing downward, if the current frame pointer points at the very oldest frame in the stack, then there is no more frames to go up in the stack.

up n
Moves the current frame pointer "n" number of frames up in the execution stack. The default value of "n" is one.

down
Moves the current frame pointer one frame down on the execution stack. Assuming the stack is growing downward, if the current frame pointer points at the very top frame in the stack, then there is no more frames to go down in the stack.

down n
Moves the current frame pointer "n" number of frames down in the execution stack. The default value of "n" is one.
 

6.3. Back tracing
Back tracing allows you to investigate the entire execution stack. It is commonly used after a runtime error. Another synonym for this command is "where"

backtrace
bt

Prints out information about every procedure frame in the current execution stack.

backtrace n (Not implemented yet)
bt n

Prints out information about the "n" innermost procedure frames from the current frame pointer.

backtrace -n (Not implemented yet)
bt -n

Prints out information about the "n" outermost procedure frames from the current frame pointer.
 

7. Examining Data
The print command is used to either get a peek at one of the variables or change the value of a variable.

7.1. Getting a peek at the value of a variable
Usually, the print command is used. It assumes that the variable is in the current stack frame. The printed value of the variable is different based on the variable type, if  the type of the variable is an Atomic Type, then the printed value is its current actual value. However, if the variable's type is a Structured Type, then the printed value is an image or ximage of that variable. Hence, the print command can be used to print an element or field of a structure such as list, table, or record, when the variable is a string, then you can print the whole string or just a substring.

To print an element of a list, you just refer to that element in the source code, for example:
print L[2] prints out the value of the element L[2]
print L[2][10] prints out the value of the element L[2][10]
print L[i][j] prints out the value of the element L[i][j] after evaluating both of i and j, note that i and j must be valid variables in the current context.

To print an element of a table, it is very similar to the list subscription with the extension that tables are not restricted to the integer keys.

To print a string value or a substring, you just refer to that element in the source code, for example:
print S prints the value of S
print S[5] prints the character in the position 5 in the string S
print S[2:8] prints all the characters between the position 2 and 8 of the string S

To print any field of a record, you just refer to that field using the dot operator, for example
print r.f prints out the value of the field f of that record r

Here is a detailed description of the print command:

print
p

Prints a snapshot of all of the global and local variables of the current active procedure that you are stepping in, it also includes the formal parameters of that procedure.

print variable
p variable

Prints out the value of the variable "variable". The passed variable named "variable" is assumed to be local to the current procedure frame that you are stepping in, if not it will be searched within the global variables.

print variable n
p variable n

Prints out the value of variable "variable" in the stack frame number n. Frame 0 is the innermost frame, frame 1 is the direct parent of the innermost frame, frame n is the frame number n away from the current frame, which is referred to the procedure main.

print -G
p -G

Prints a snapshot of all of the global variables and their values at that current program state.

print -L
p -L

Prints a snapshot of all of the variables and their values that are local to that current procedure frame that you are stepping in.

print -P
p -P

Prints a snapshot of all of the parameters and their values that are passed to the current procedure frame that you are stepping in.

print keyword
p keyword

Prints out the value or an image of any valid Unicon keyword "keyword"
 

7.2. Changing the value of a variable
The same print command that is used to get a peek at a variable, it can be used also to change the value of a variable. In order to change a variable value in your program from within UDB, the assignment operator ":="  or "=" must be used.

print variable := value
p variable := value

It evaluates the right hand side of the assignment "value" and assigns the result to the variable "variable" in the left hand side of the assign operator. The "value" can be a literal value or any other valid variable in the current program context. The variable "variable" is assumed to be in the current active procedure frame, otherwise it will be looked up in the global variables. The variable "variable" can be a simple variable, an element of a structured variable, or any other valid Unicon variable. If the variable "variable" is an element of a structure such as:

A list:
You can assign a an element of a list by referring to that element in the source code, for example:
print L[2]:=3 assigns L[2] with the integer literal 3
print L[5]:=b assigns L[5] with the value of the variable b
print L[i][j]:=10 assigns the element L[i][j] with the integer literal 10, both i & j must be valid variables in the current context.

A table:
Assigning to an element of a table is similar to assigning to an element of  a list, the only the difference is that a table key is not limited to the integer keys.

A string:
You can assign to a string variable or to a substring, for example: if S is variable that holds a string value then it is valid to say:
print S := "abcdefg"  or
print S[1]
:= "A" or
print S[2:6]
:= "ab"

A record:
You can assign any record field using the dot operator, for example:
print r.f := 10 assigns the field member f of the record r the integer literal 10

A valid Unicon keyword:
print &keyword := value
p &keyword := value
It changes the keyword value into the new assigned value.
Not: this type of assignment to a keyword depends on the keyword itself, in Unicon not all the keywords are variables that you can assign to.
 

8. Examining Source Files
UDB knows about the source code and what files are involved in building the executable. At the load time, UDB tries to open all of the related source files including the library files, it builds a list of what source files are available and what are not. It reads such information from the icode of the executable itself. UDB can print parts of your program's source, when your program reaches a break point or a watch point, UDB spontaneously prints to the line where it stopped, likewise, when you back trace or select a stack frame, UDB prints information about the file and the line where the execution in that frame has stopped. In general, you can print any part of a source file or query about what files are successfully opened and what are not.

8.1. Printing source lines
The command "list" allows you to print lines from the source code. The default number of lines are ten, and the default source file is the current source file that the program is stopped in. If the program is not running yet, the current file is the file that has the procedure main( ) in it.

list linenum
l linenum

Prints out ten lines centered around the line number "linenum"

list procedure
l procedure

Prints out ten lines centered around the header of the procedure "procedure"

list
l

Prints out ten lines from the current source file centered around the current line. Another list command will print out the next ten lines in the source file.

list -
l -

Print out the previous ten lines.
 

8.2. Found and missing source files
The src command allows you to check what source files are found and what are missing for any reason

src -f
Prints a list of all the file names that are found and opened by udb, those are the source files that can be navigated with the list command.

src -m
Prints a list of all the file names that are missing and not opened by udb. Even though those files are missing, udb is still able to work, the only degradation in the features is that you can not navigate the source code in the missing file.

src
Prints all of the file names that are used to build the executable, that include all used files from libraries, packages, and the user files. It separates the found files from the missing ones.
 

9. Tracing
No one can ignore the benefits from pausing the execution and investigating the state of the program, but it is not always enough or even a valid choice. You may be interested in understanding the behavior of the execution over a period of time, or may be the program depends on some real-time behavior, where stopping the execution might cause the program to change its behavior. UDB provides tracing facilities that allow you to depict the state and/or the behavior of the program without pausing the execution. However, tracing the execution can generate huge amount of data in a very short period of time, just remember to be selective about what to trace and to trace small pieces of the program instead of tracing the whole program. UDB's tracing facilities are divided into two main categories.
 

9.1. Tracing a variable
UDB allows you to trace one or more variables during the execution of the program. The tracer can be enabled and/or disabled at any point of the program's execution. It traces every value that the traced variable ever had combined with information about the file name, the line number, and the procedure name. You do not have to wait until the execution is complete in order to query about the traced information, you can investigate the traced information at any point of the execution.

trace variable
If this command is applied while the program is stopped for any reason, the tracer considers that variable "variable" as local variable in the current procedure, otherwise the tracer assumes that the variable "variable" is global and traces it during the rest of the execution. It sets a trace point on that variable "variable" to trace every value assigned to it combined with information consists of the file name, the line number, and the procedure name where that value is assigned.

trace variable procedure
This exactly same as "trace variable" command but the tracer here does not have to guess the scope of the traced variable "variable" since the procedure is provided in the command. It sets a trace point on that variable "variable" to trace every value assigned to it combined with information consists of the file name, the line number, and the procedure name where that value is assigned.

enable -trace variable
If this command is applied while the program is stopped for any reason, the tracer considers that variable "variable" as local variable in current procedure, otherwise the tracer assumes that the variable "variable" is global and traces it during the rest of the execution. Enables the tracer on that variable "variable", if that was at any break point during the program execution; the tracer will assume the variable "variable" is local to the current procedure that the break point is on, otherwise it will assume the "variable" is a global variable and trace it in the whole program.

enable -trace variable procedure
This exactly same as "enable trace variable" command but the tracer here does not have to guess the scope of the traced variable since the procedure is provided in the command. It enables the tracer on that local variable "variable" in the provided procedure "procedure". This command can be applied at any point of the program execution.

disable -trace variable
If this command is applied while the program is stopped for any reason, the tracer considers that variable "variable" as local variable in current procedure, otherwise the tracer assumes that the variable "variable" is global and traces it during the rest of the execution. Disables the tracer on that variable "variable", if that was at any break point during the program execution; the tracer will assume the variable "variable" is local to the current procedure that the break point is on, otherwise it will assume the "variable" is a global variable and stops the trace in the whole program.

disable -trace variable procedure
This exactly same as "disable trace variable" command but the tracer here does not have to guess the scope of the traced variable since the procedure is provided in the command. It disables the tracer on that local variable "variable" in the provided procedure "procedure". This command can be applied at any point of the program execution. This exactly same as "disable trace variable" command but the tracer here does not have to guess the scope of the traced variable since the procedure is provided in the command.

info -trace variable
If this command is applied while the program is stopped for any reason, the tracer considers that variable "variable" as local variable in current procedure, otherwise the tracer assumes that the variable "variable" is global and traces it during the rest of the execution. It prints out a list of all the traced information about the variable "variable". The information consist of an image of every value assigned to that variable "variable" combined with the file names, the line numbers, and the procedure names.

info -trace variable procedure
It prints out a list of all the traced information about the variable "variable". The information consist of an image of every value assigned to that variable "variable" combined with the file names, the line numbers, and the procedure names.
 

9.2. Tracing an execution behavior
Dynamic tracing is an important feature to understand the execution of a running program; it provides the user with information about what really happens during the execution. That is what drove an operating system such as Solaris to build DTrace [6] in order to help its developers understand the behavior of their program. DTrace is used to observe, debug and tune system behavior. It is built into the operating system, and complements other forms of application behavior tracing. UDB's tracing approach resembles a more detailed version of GDB's tracing facility, which means that the user can trace and debug in the same session, and the trace output can be customized based on the user interest. It allows you to trace some of the execution behaviors such as procedure calls, operator failures, and so many other features.
 

9.2.1 Tracing procedure activities
Tracing procedures is useful when the user wants to learn about the behavior, the sequence, and/or the values of the passed parameters at each procedure activities such as call, return, suspend, fail, and resume. The traced procedures can overcome the limitations of the execution stack. The execution stack provides you with information about those live procedures in that current execution state, however, tracing procedures can provide you with information not only about those live procedures but also about those procedures that maybe returned just before pausing the execution. Furthermore, investigating the execution stack does not tell whether that live procedure in the stack is suspended or just called another procedure. Traced procedures can assist the stack investigation with detailed information.

trace -proc
Traces all of the procedure activities such as call, return, fail, suspend, and resume. Traced information composed of the file name, the line number, the stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

trace -proc procedure
Traces only the activities of the procedure named "procedure", the traced activities are the procedure call, return, fail, suspend, and resume. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot their values at that specific activity.

trace -pcall
trace -preturn
trace -pfail

trace -psuspend
trace -presume
Traces only one activity for all of the procedures such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

trace -pcall procedure
trace -preturn procedure
trace -pfail procedure

trace -psuspend procedure
trace -presume procedure
Traces only the procedure named "procedure" and only one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

enable -trace -proc
Enables the tracer at all of the procedure activities such as call, return, fail, suspend, and resume. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

enable -trace -proc procedure
Enables the tracer only for the activities of the procedure named "procedure", the traced activities are the procedure calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and and a snapshot of their values at that specific activity.

enable -trace -pcall
enable -trace -preturn
enable -trace -pfail

enable -trace -psuspend
enable -trace -presume
Enables the tracer only with one activity for all of the procedures such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the filename, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot their values at that specific activity.

enable -trace -pcall procedure
enable -trace -preturn procedure
enable -trace -pfail procedure

enable -trace -psuspend procedure
enable -trace -presume procedure
Enables the tracer only for the procedure named "procedure" and only with one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and and a snapshot of their values at that specific activity.

disable -trace -proc
Disables the tracer at all of the procedure activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

disable trace -proc procedure
Disables the tracer only for the activities of the procedure named "procedure", the traced activities are the procedure call, return, suspend, fail, and resume. Traced information composed of the filename, line number, execution stack level, procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

disable -trace -pcall
disable -trace -preturn
disable -trace -pfail

disable -trace -psuspend
disable -trace -presume
Disables the tracer only with one activity for all of the procedures such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

disable -trace -pcall procedure
disable -trace -preturn procedure
disable -trace -pfail procedure

disable -trace -psuspend procedure
disable trace -presume procedure
Disables the tracer only for the procedure named "procedure" and only with one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

info -trace -proc
Prints out the traced information for all of procedures and all of their activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

info -trace -proc procedure
Prints out only the traced information of the procedure named "procedure", the traced activities are the procedure calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

info -trace -pcall
info -trace -preturn
info -trace -pfail

info -trace -psuspend
info -trace -presume
Prints out the traced information for only one activity for all of the procedures such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot of their values at that specific activity.

info -trace -pcall procedure
info -trace -preturn procedure
info -trace -pfail procedure

info -trace -psuspend procedure
info -trace -presume procedure
Prints out the traced information only for the procedure named "procedure" and only one traced activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, the procedure name, and the formal parameters names and a snapshot their values at that specific activity.
 

9.2.2. Tracing built-in function activities
UDB's tracing facilities goes places other tracers might not be able to trace, one of those places is the built-in functions which are supported by the Unicon's runtime system. Built-in functions provide a tremendous support for the Unicon programmer who uses them all the time. Tracing built-in function's activities gives the user a fine level of details about the execution behavior of the subject program. Those built-in functions activities, such as calls, returns, fails, suspends, and resumes, can be crucial to the behavior of the running program and understanding their behavior can be crucial to understanding the behavior of the running program.

trace -func
Traces all of the built-in functions activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

trace -func function
Traces only the activities of the function named "function", the traced activities are the function calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

trace -fcall
trace -freturn
trace -ffail

trace -fsuspend
trace -fresume
Traces only one activity for all of the built-in functions such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

trace -fcall function
trace -freturn function
trace -ffail function

trace -fsuspend function
trace -fresume function
Traces only the built-in function named "function" and only one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

enable -trace -func
Enables the tracer at all of the built-in functions activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

enable -trace -func function
Enables the tracer only for the activities of the built-in function named "function", the traced activities are the function calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

enable -trace -fcall
enable -trace -freturn
enable -trace -ffail

enable -trace -fsuspend
enable -trace -fresume
Enables the tracer only with one activity for all of the built-in functions activities such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

enable -trace -fcall function
enable -trace -freturn function
enable -trace -ffail function

enable -trace -fsuspend function
enable -trace -fresume function
Enables the tracer only for the built-in function named "function", the traced activity is all of the calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

disable -trace -func
Disables the tracer at all of the built-in functions activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

disable -trace -func function
Disables the tracer only for the activities of the built-in function named "function", the traced activities are the function calls, returns, suspends, fails, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

disable -trace -fcall
disable -trace -freturn
disable -trace -ffail

disable -trace -fsuspend
disable -trace -fresume
Disables the tracer only with one activity for all of the built-in functions such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

disable -trace -fcall function
disable -trace -freturn function
disable -trace -ffail function

disable -trace -fsuspend function
disable -trace -fresume function
Disables the tracer only for the built-in function named "function" and only with one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

info -trace -func
Prints out the traced information for all of built-in functions and all of their activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

info -trace -func function
Prints out only the traced information of the built-in function named "function" and all of its activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

info -trace -fcall
info -trace -freturn
info -trace -ffail

info -trace -fsuspend
info -trace -fresume
Prints out the traced information for only one activity for all of the built-in functions such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

info -trace -fcall function
info -trace -freturn function
info -trace -ffail function

info -trace -fsuspend function
info -trace -fresume function
Prints out the traced information only for the function  named "function" and only one traced activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.
 

9.2.3. Tracing built-in operation activities
UDB's tracing facilities goes places other tracers might not be able to trace, beside the built-in functions, it allows tracing the built-in operations which are supported by the Unicon's runtime system, they in the Unicon programmer all the time, and they have the semantic of the Unicon such as calls, returns, fails, suspends, and resumes. The semantic of those built-in operations gives the ability to trace them a significant importance by providing the user with another fine level of details about the behavior of the subject program.

trace -Oper
Traces all of the built-in operations activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

trace -Oper Operation
Traces only the activities of the built-in operation named "Operation", the traced activities are the operation calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and operation name.

trace -Ocall
trace -Oreturn
trace -Ofail

trace -Osuspend
trace -Oresume
Traces only one activity for all of the built-in operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

trace -Ocall Operation
trace -Oreturn Operation
trace -Ofail
Operation
trace -Osuspend Operation
trace -Oresume Operation
Traces only the built-in operation named "Operation" and only one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

enable -trace -Oper
Enables the tracer at all of the built-in operations activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

enable -trace -Oper Operation
Enables the tracer only for the activities of the built-in operation named "Operation", the traced activities are the operation calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

enable -trace -Ocall
enable -trace -Oreturn
enable -trace -Ofail

enable -trace -Osuspend
enable -trace -Oresume
Enables the tracer only with one activity for all of the built-in operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, ad operation name.

enable -trace -Ocall Operation
enable -trace -Oreturn Operation
enable -trace -Ofail
Operation
enable -trace -Osuspend Operation
enable -trace -Oresume Operation
Enables the tracer only for the built-in operation named "Operation" and only with one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

disable -trace -Oper
Disables the tracer at all of the built-in operations activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

disable -trace -Oper Operation
Disables the tracer only for the activities of the built-in operation named "Operation", the traced activities are the operation's calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

disable -trace -Ocall
disable -trace -Oreturn
disable -trace -Ofail

disable -trace -Osuspend
disable -trace -Oresume
Disables the tracer only with one activity for all of the built-in operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

disable -trace -Ocall Operation
disable -trace -Oreturn Operation
disable -trace -Ofail
Operation
disable -trace -Osuspend Operation
disable -trace -Oresume Operation
Disables the tracer only for the built-in operation named "Operation" and only with one activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

info -trace -Oper
Prints out the traced information for all of built-in operations and all of their activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

info -trace -Oper Operation
Prints out only the traced information of the built-in operation named "Operation", the traced activities are the operation calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

info -trace -Ocall
info -trace -Oreturn
info -trace -Ofail

info -trace -Osuspend
info -trace -Oresume
Prints out the traced information for only one activity for all of the built-in operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.

info -trace -Ocall Operation
info -trace -Oreturn Operation
info -trace -Ofail
Operation
info -trace -Osuspend Operation
info -trace -Oresume Operation
Prints out the traced information only for the built-in operation  named "Operation" and only one traced activity such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the operation name.
 

9.3.4. Tracing string scanning activities
UDB's tracing supports the string scanning activities. In a language such as Unicon invest heavily in the string scanning operations, it is very important to provide the user with the ability to trace them and give the user to investigate the state and the activities used during the string scanning.

trace -Scan
Traces all of the string scanning activities such as started new scan, suspend scan, failed scan, resumed scan, and returned scan . Traced information composed of the file name, the line number, the execution stack level, and the function name.

trace -Snew
trace -Sreturn
trace -Sfail

trace -Ssuspend
trace -Sresume
Traces only one activity for all of the string scanning operations such as a new scan, returned scan, failed scan, suspend scan, and resumed scan respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

enable -trace -Scan
Enables the tracer at all of the string scanning operations and activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

enable -trace -Snew
enable -trace -Sreturn
enable -trace -Sfail

enable -trace -Ssuspend
enable -trace -Sresume
Enables the tracer only with one activity for all of the string scanning operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.

disable trace -Scan
Disables the tracer at all of the string scanning operations and their activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

disable -trace -Snew
disable -trace -Sreturn
disable -trace -Sfail

disable -trace -Ssuspend
disable -trace -Sresume
Disables the tracer only with one activity for all of the string scanning operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the name.

info -trace -Scan
Prints out the traced information for all of the string scanning operations and all of their activities such as calls, returns, fails, suspends, and resumes. Traced information composed of the file name, the line number, the execution stack level, and the function name.

info -trace -Snew
info -trace -Sreturn
info -trace -Sfail

info -trace -Ssuspend
info -trace -Sresume
Prints out the traced information for only one activity for all of the string scanning operations such as calls, returns, fails, suspends, and resumes respectively. Traced information composed of the file name, the line number, the execution stack level, and the function name.
 

10. Extensible Debugging
UDB provides an open debugging architecture that is capable of being cooperative with external debugging tools. GDB style of debugging is not always good enough, the nature of the bug or the debugging situation may need some help from external or internal tools that would provide information beyond what a break point debugger is capable of. Fortunately, UDB has an open architecture that permits external or internal event-based monitoring tools to be loaded and enabled/disabled during the debugging session. Such tools might vary in its goals. some may trace specific event while others may dedicate to capture a specific execution behavior that might be hard or impossible to be captured using the break points, watch points, and stepping/continuing strategies.

10.1 Internal monitors
UDB has a library of different monitors, which serve different behaviors such as memory allocations, garbage collections, failed loops, failed subscripts, variable profiles, dead variables, loops time, procedure times, etc. Internal monitors are disabled by default, in order to be used, the user has to enable them explicitly. 

10.1.1 Enabling internal monitor

enable -internal monitor
Enables the internal monitor named "monitor", the command is valid from any point during the debugging session.

10.1.2 Disabling internal monitor

disable -internal monitor
Disables the internal monitor named "monitor", the command is valid from any point during the debugging session. The only condition is that the disabled monitor must be enabled previously.

10.1.3 Analyze information in the internal monitor

analyze -internal monitor
Analyzes the information collected by the internal monitor named "monitor", this command is valid after enabling the internal monitor from any point during the debugging session. However, some internal monitors may not have this facility; for such monitors, this command will fail silently.

10.1.4 Print information from the internal monitor

print -internal monitor
Prints the information collected and analyzed by the internal monitor named "monitor", the command is valid after enabling the internal monitor from any point during the debugging session. However, some internal monitors may not have this facility; for such monitors, this command will fail silently.

10.1.5 Information about internal monitors

info -internal monitor
Provides the current state of the internal monitor named "monitor", whether is is disabled or enabled. The command is valid from any point during the debugging session.

info -internal
Provides the current state of all internal monitors that are available in the system and whether each one is enabled or disabled. The command is valid from any point during the debugging session.

10.2 External monitors
UDB's extensible architecture opens the door for compatible stand-alone monitors to be loaded and used on the fly during the debugging session. Any Alamo-based stand-alone event-driven monitor can be loaded under UDB's control. Loaded external monitors are enabled by default from the point of loading during the debugging session. external monitors will be paused when the debuggee program is paused and resumed when the debuggee program is resumed after a break point or watch point, or even between stepping and continuing.

10.2.1 Loading external monitors

load -external monitor
Loads the external stand-alone monitor named "monitor" and enables it by default. The command is valid from any point during the debugging session.

10.1.2 Enabling external monitor

enable -external monitor
Enables the external monitor named "monitor", the command is valid from any point during the debugging session. The only condition is that the enabled external monitor must be previously loaded and disabled. 

10.1.3 Disabling external monitor

disable -external monitor
Disables the external monitor named "monitor", the command is valid from any point during the debugging session. The only condition is that the disabled monitor must be loaded previously.

10.1.4 Information about external monitors

info -external monitor
Provides the current state of the external monitor named "monitor", whether is is disabled or enabled. The command is valid from any point during the debugging session.

info -external
Provides the current state of all loaded external monitors that are available in the system and whether each one is enabled or disabled. The command is valid from any point during the debugging session.

10.3 Migration form externals to internals
External monitors impose an extra level of communication overhead in the form of co-expression context switch (Unicon light weight of threads are called co-expression). for better performance external tools can be migrated to internals. UDB's extensible architecture is open for stand-alone external tools that are:
  1) Alamo event-based monitors.
  2) Written in either Icon or Unicon.

10.3.1 Simple monitor
The following is a very simple Alamo based monitor, where each event is mapped, with one-to-one relation, into a single method. This format allows UDB to provide automatic and easy registration for the used methods and their event mask. All you needs to do is to derive this simple monitor from the Listener() class provided by the UDB's open architecture,   then using the registration function which is:
register("name", object);
where the first parameter is providing a formal name to the monitor and the second parameter is the actual object of that monitor.  For example, in order to register the following simple MyMon() monitor, you need to call the method:
register("calls", MyMon());

from the init()method of the internal() class.

# A simple monitor that counts the number of method/procedure and built-in function calls
class MyMon(eventMask,  pcalls, fcalls, pcalls_rate, fcalls_rate)

  # This method counts the number of method/procedure calls
  method handle_E_Pcall(code, value)
     pcalls +:= 1
  end

  # This method counts the number of built-in function calls
  method handle_E_Fcall(code, value)
     fcalls +:= 1
  end
 
  # This method do some calculations and analyze the collected information
  method analyze_info()
     local total
     
     total := pcalls + fcalls
     pcalls_rate := pcalls/total * 100
     fcalls_rate := fcalls/total * 100
  end

  # This method prints out some information
  method write_info()
     write(" # pcalls = ", pcalls, "  and its ratio is :", pcalls_rate)
     write(" # fcalls = ", fcalls, "  and its ratio is :", fcalls_rate)
  end

# Constructor
initially()
     eventMask := cset(E_Pcall||E_Fcall)
     pcalls := fcalls := 0
end

procedure main(args)
   EvInit(args)
   o := MyMon()
   while EvGet(o.eventMask) do{
      case &eventcode of{
         E_Pcall:{
           o.handle_E_Pcall(&eventcode, &eventvalue)
           }
         E_Fcall:{
           o.handle_E_Fcall(&eventcode, &eventvalue)
           }
         }
      }
   o.analyze_info()
   o.write_info()
end


However, UDB's auto-registration has some restricted assumption about the used monitor, especially its method names. In this auto registration, there is three types of methods inside the monitor class that the auto-registration can recognize:
1) Event handler methods: those methods start with the prefix "handle_" followed by the event name. Each method supposed to handle one event. (i.e. handle_E_Pcall())
2) Information analyzer methods: those methods start with the prefix "analyze_" followed by any name.  This type of method supposed to process and analyze the collected information. (i.e. analyze_info()). and finally
3) Information writer: those methods starts with the prefix "write_" followed by any name. This type of methods supposed to write information collected by the monitor. (i.e. write_info()).

In fact, this suggested formatting is intended to simplify the registration process. Users follow this format, all they have to do is to strip the monitor from its main procedure, use the auto registration method, compile their monitors and link them into the source code of UDB. At that point user are abele to use their own monitors from within UDB and during the debugging session. Different monitors are distinguished by their names. The user is liable to enable/disable and use the monitor facilities on the fly during the debugging session. 

10.3.2 Complex monitors
Complex monitors are those monitors that do not follow the conventional formatting. In such monitors, there is no restriction on how to write the monitor itself, and there is on restriction on the naming of the used methods. In order to register this type of monitors, the user has to call the method register() with some extra parameters, which used to register three types of method: 1) event handler, 2) information analyzer, and 3) information or result writer. The method prototype is as follows:
 register( "name", object, [handlers], [analyzers], [writers],mask);
where
1) [handlers]: is a list of the string names of the methods used to handle events in the external monitor,
2) [analyzers]: is a list of the string names of the methods used to analyze the collected information in the external monitor,
3) [writers] : is a list of the string names of the methods used to write or print information from the external monitor, and
4)  mask :  is the set of events that the monitor is looking for

For example: the following monitor example, named FailedLoop, does not follow the suggested formatting. It has one handler method named "process_Events()" , one analyzer method named "process_Info(j)", and two writer methods "print_header()" and "print_Info( num )". If you noticed, the methods does not follow the suggested naming.  In order to register such a monitor, you need to call the method register() with the following parameters:
register("calls", MyMon(),["process_Events"],["process_Info"],["print_header()","print_Info"],mask);

This way of registration provides an extra layer over the simple registration. It performs the simple auto registration and adds to it those specified methods. This type of registration intended to add an extra level of freedom to the user to write his/her stand-alone monitor in the way that he wants and  to register it, as an internal, with the least possible modification. Here is a real monitor that finds failed loops and a demonstration on how to register it as internal one.


$include
"evdefs.icn"
link syntname

# check failed loop, loops that executes zero times
# otherwise it will show up how many times that loop executed

class FailedLoop : Listener(
   eventMask,     # Monitored events for this detection
   procCallCount, # Table counts the number of times each procedure is called
   loopFailCount, # Table counts the number of time a loop has been iterated
   FailedLoopInfo # a list with the failed loop information
   )

# collect loopes information
method process_Events()
   static loopStart := "while every repeat until"
   static loopEnd := "endwhile endevery endrepeat enduntil"
   static fname, line, pname, k
   local loop

   if &eventcode == E_Pcall then{
      pname := image(&eventvalue)
      pname := pname[find(" ", pname)+1: 0]
      procCallCount[pname] +:= 1
      }
   else if &eventcode == E_Syntax then{
      loop := syntname(&eventvalue)
      if find(loop, loopStart) then{
         line := keyword("line", Monitored)
         fname := keyword("file", Monitored)
         pname := image(proc(Monitored,0))
         pname := pname[find(" ", pname)+1: 0]
         k := fname||"("||line||"){"||pname||"}"||loop
         loopFailCount[k] +:= 1
         }
      }
   else if &eventcode == E_Line then{
      loop := syntname(keyword("syntax",Monitored))
      if find(loop, loopStart) then{
         line := &eventvalue
         fname := keyword("file", Monitored)
         pname := image(proc(Monitored,0))
         pname := pname[find(" ", pname)+1: 0]
         k := fname||"("||line||"){"||pname||"}"||loop
         loopFailCount[k] +:=1
         }
      }
end

# updates the failed loop info,
# it receives the param j which is the most elapsed j loops

method process_Info(j)
   local i:=1, loop, fname, pname, line, p

   if \loopFailCount & *loopFailCount > 0 then{
      if /j then j := *loopFailCount + 1
      else j >=:= *loopFailCount + 1

      FailedLoopInfo := sort(loopFailCount,2)[1:j]
      # 1-"Seq Num"   |# 2-"File Name" | # 3-"Line #" |
      # 4-"Proc Name" | # 5-"#call"    | # 6-"Loop Name" |
      # 7-"Avg(Iter/Call)" | # 8-"Total Iterations" |
      while i <= j & \FailedLoopInfo do{
         loop := get(FailedLoopInfo[i])
         fname := loop[1 : p := find("(", loop)]
         line := loop[p+1 : find(")", loop)]
         pname := loop[find("{",loop)+1 : p := find("}",loop)]
         loop := loop[p+1 : 0]
         push(FailedLoopInfo[i],
              FailedLoopInfo[i][1]/procCallCount[pname],
              loop,
              procCallCount[pname],
              pname,
              line,
              fname,
              i
              )
         i +:= 1
         }
      }
end

# This method prints out the header of the result
method print_header()
   write("\n-- Loop's info [The Least Iterated (",num,") Loops] --")
   write(left("Num",3),            " | ",
         left("File Name",10),     " : ",
         left("Line #",6),         " : ",
         left("proc Name",10),     " : ",
         left("#Calls",6),         " : ",
         left("Loop Name",10),     " : ",
         left("Avg(Iter/Call)",14)," : ",
         left("Total Iteration",15)
         )
end

# Prints out the total elapsed time of a loop in ms
# It is to be used in a console based application such as UDB

method print_Info( num )
   local i:=1

   update_Info(num)
   /num := *FailedLoopInfo

   while i <= num & \FailedLoopInfo do{
      write(left(FailedLoopInfo[i][1],3), " | ",
            left(FailedLoopInfo[i][2],10)," : ",
            left(FailedLoopInfo[i][3],6), " : ",
            left(FailedLoopInfo[i][4],10)," : ",
            left(FailedLoopInfo[i][5],6), " : ",
            left(FailedLoopInfo[i][6],10)," : ",
            left(FailedLoopInfo[i][7],14)," : ",
            left(FailedLoopInfo[i][8],15)
            )
      i +:= 1
      }
end

# Initialize the class attributes
initially(name, state)
   self.Listener.initially(name, state)
   eventMask := cset(E_Pcall || E_Syntax || E_Line)
   procCallCount  := table(0)
   loopFailCount  := table(-2)
   FailedLoopInfo := []
end

# StandAlone is defined when this tool is used as a stand-alone monitor.
# Otherwise, this tool can be statically linked into the main utop/udb
# source code

$ifdef StandAlone
link evinit

procedure main(arg)
   local obj

   EvInit(arg) | stop(" **** can not initialize Monitor !!!")
   obj := FailedLoop()
   while EvGet(obj.eventMask) do
      obj.handle_Events()
   obj.write_Info()
end
$endif

11.
Future Work

A future version of UDB will be running with every Unicon program silently as an observer, if there is something interesting such as a runtime error, it will take the lead putting the user in no time in the debugging process. This will save the user the hassle of regenerating the cause of the bug once a gain inside the debugger. Hence, having UDB as an observer in the back of every program does not cost the execution time of the program any thing noticeable.

12. References

  1. Jeffery, C. L., 1999. Program Monitoring and Visualization: an Exploratory Approach, Springer New York.
  2. Jeffery, C. L., Mohamed, S., Pereda, R., and Parlett, R. 2004. Programming with Unicon. http://unicon.org/book/ub.pdf.
  3. Griswold, R. E., and Griswold, M. T.1997. The Icon Programming Language. Peer-to-Peer Communications, Inc., San Jose, California.
  4. Stallman, R. M., Pesch, R., Shebs, S., et al. 2002. Debugging with GDB: the GNU Source Level Debugger.  http://sourceware.org/gdb/documentation.