The Liberty Eiffel debugger is an Embedded debugger. This means that in order to use it, you need to compile your application with a special flag -sedb. The executable will then have the debugger inside, you can launch your application the usual way.
The debugger offers powerful commands which allows you to examine the bowels of your program:
- commands to control execution,
- commands to set or unset breakpoints,
- commands to print your data,
- other various commands.
These commands allow your program to execute. You can either run step by step or make bigger strides, or even force execution until the end.
Whatever your choice is, the program will run until the next breakpoint (see below), or until the next ^C.
The available commands are (in increasing order of step size):
|s||Move only one step forward. This means entering a routine if the step is a feature call.|
|n||Move only one step forward (next), but without entering a routine (this means that a feature call is considered as one step).|
|f||Move to the next routine return (finish).|
|c||Move as far as possible (continue), perhaps even to the end of the program.|
|C||Continue until the end of the program, ignoring all breakpoints (whether static or dynamic).|
There are two kinds of breakpoints:
- those explicitly placed in the code, with the instruction sedb_breakpoint,
- those dynamically placed in the debugger. To modify dynamic breakpoints, you can use the following commands:
|b||Add a dynamic breakpoint. There are many possible criteria, described below. All chosen criteria must be valid to activate the breakpoint.|
|B||Print all dynamic breakpoints.|
|-<num>||Remove a dynamic breakpoint designated by its number. The numbers are printed by the B command.|
The sedb_breakpoint instruction
The sedb_breakpoint instruction is defined in ANY. It places a static breakpoint directly in the Eiffel source. This command does nothing if the program is not compiled with the -sedb flag.
These breakpoints cannot be removed by the -<num> command. The only way to ignore them is to use the C command (continue until the end of the program).
Specifications of a dynamic breakpoint
To set up a dynamic breakpoint, you can specify one or more criteria.
- Name: the name of the method and the class name in which the method is defined, separated by a space, for example "item STRING". You can specify a substring of this name. Thus, if you specify item, the program will stop at the beginning of the item method of STRING, but also at the beginning of the one in ARRAY, etc. Similarly, if you specify STRING, the program will stop when encountering any method of STRING, but also of HASHED_DICTIONARY[STRING, INTEGER]. You can even be original: I will let you guess the behaviour of the is_ specification :-)
- File: for example, string.e. As the file name is applied to the complete path, you can specify lib/kernel which will stop at all the methods in the classes of that cluster.
- Line numbers: you can specify a range of lines, for example [12,13].
- Execution stack: this condition lets you track the size of the execution stack (useful for debugging a recursive function, for example). For instance, you can specify a stack size limit of 10, which will stop the execution when the stack size reaches 10. An optional automatic increment permits the limit to be incremented each time the breakpoint is reached. If you don't use this option, this breakpoint can be a good way to track the stack's memory consumption.
Of course, all these specifications are cumulative: they must all be true at the same time to activate the breakpoint.
The following commands allow to print the data of your program:
|e <exp>||Evaluates and prints the result of an expression. Note that the general Eiffel expressions are not supported.|
| Only the following can be printed:
|Re-evaluates the last expression by suffixing a dot and the expression <exp> (if present). This is very useful for chain printing. Instead of a single dot you can also use the notation .. which goes one level up, .... which goes two levels up, etc.|
| Example of the use of e and p :
sedb> e Current STD_OUTPUT#0x807ab00 [ filter = Void buffer_position = 0 buffer = NATIVE_ARRAY[CHARACTER]#0x806c030 capacity = 4096 ] sedb> e buffer NATIVE_ARRAY[CHARACTER]#0x806c030 sedb> p.0 (sedb) e buffer.0 'H' sedb> p..1 (sedb) e buffer.1 'e' sedb> p....buffer_position (sedb) e buffer_position 0 sedb>
|.||Print the current frame; that is the content of the local variables of the current routine.|
|u||Goes up in the stack (i.e. goes to the caller). This means that the calling routine becomes the current routine. Note that the e, p and . commands follow the current routine.|
|d||Goes down in the stack (opposite of u).|
|S|| Prints the execution stack. There are two printing modes:
|q||Quits the debugger; the program will be stopped. You can also use Q which doesn't ask for confirmation.|
|H||Prints detailed help.|
|G||Runs the garbage collector, if it is present.|
|T||Changes the trace mode, if it is present (flag -trace when compiling). If the mode is active, the file trace.se fills up (very quickly!)|
|Return||Re-executes the last command.|