Previous Up Next

15.5  Debugging Parts of Programs

15.5.1  Mixing debuggable and non-debuggable code

The debugger can trace only procedures which have been compiled in debug mode. The compiler debug mode is by default switched on and it can be changed globally by setting the flag debug_compile with the set_flag/2 predicate or using dbgcomp/0 or nodbgcomp/0. The global compiler debug mode can be overruled on a file-by-file basis using one of the compiler pragmas

:- pragma(nodebug).
:- pragma(debug).

Once a program (or a part of it) has been debugged, it can be compiled in nodbgcomp mode so that all optimisations are done by the compiler. The advantages of non-debugged procedures are

Although only procedures compiled in the dbgcomp mode can be traced, it is possible to mix the execution of procedures in both modes. Then, calls of nodbgcomp procedures from dbgcomp ones are traced, however further execution within nodbgcomp procedures, i.e., the execution of their subgoals, no matter in which mode, is not traced. In particular, when a nodbgcomp procedure calls a dbgcomp one, the latter is normally not traced. There are two important exceptions from this rule:

Setting a procedure to skipped (with set_flag/3 or skipped/1 ) is another way to speed up the execution of procedures that need not be debugged. The debugger will ignore everything that is called inside the skipped procedure like for a procedure compiled in nodbgcomp mode. However, the debugger will keep track of the execution of a procedure skipped with the command s of the debugger so that it will be possible to “creep” in it on later backtracking or switch the debugger to creep mode while the skip is running (e.g., by interrupting a looping predicate with ^C and switching to creep mode).

The two predicates trace/1 and debug/1 can be used to switch on the debugger in the middle of a program. They execute their argument in creep or leap mode respectively. This is particularly useful when debugging large programs that take too much time (or need a lot of memory) to run completely with the debugger.

[eclipse 1]: debugging.
Debugger is switched off

yes.
[eclipse 2]: big_goal1, trace(buggy_goal), big_goal2.
Start debugging - creep mode
  (1) 0  CALL   buggy_goal %> c creep
  (1) 0  EXIT   buggy_goal %> c creep
Stop debugging.

yes.

It is also possible to enable the debugger in the middle of execution without changing the code. To do so, use set_flag/3 to set the start_tracing flag of the predicate of interest. Tracing will then start (in leap mode) at every call of this predicate.1 To see the starting predicate itself, set a spy point in addition to the start_tracing flag:

[eclipse 1]: debugging.
Debugger is switched off

yes.
[eclipse 2]: set_flag(buggy_goal/0, start_tracing, on),
             set_flag(buggy_goal/0, spy, on).

yes.
[eclipse 3]: big_goal1, buggy_goal, big_goal2.
 +(0) 0 CALL  buggy_goal   %> creep
 +(0) 0 EXIT  buggy_goal   %> creep

yes.

In tkeclipse, the debugger can also be started in this way. The tracer tool will popup at the appropriate predicate if it has not been invoked already. The start_tracing flag can also be set with the predicate browser tool.


1
Provided the call has been compiled in debug_compile mode, or the call is a meta-call.

Previous Up Next