Node:Breakpoint Tests, Next:, Previous:Processing Breakpoints, Up:Advanced Debugging



Breakpoint Tests

This section gives a tour of the most important simple breakpoint tests. In all examples here, the action part will be empty. Note that the examples are independent, so if you want to try out these, you should get rid of the old breakpoints (e.g. using ?- nospyall.) before you enter a new one.

The goal(...) test is a generalization of the pred(...) test, as it allows us to check the arguments of the invocation. For example:

| ?- add_breakpoint(goal(foo(1,_)), _).
% Conditional spypoint for user:foo/2 added, BID=1

The goal(G) breakpoint test specifies that the breakpoint should be applied only if it unifies with G. Thus in the above example the debugger will stop if foo/2 is called with 1 as its first argument, but not if the first argument is, say, 2.

Note that the above breakpoint can only be used safely if the first argument of foo/2 is input, i.e. it is never uninstantiated at the Call port. This is because the debugger actually unifies the term given within the goal test with the current goal. If foo/2 is called with a variable first argument, then the above breakpoint instantiates the variable to 1, which is probably not what you intended to do!

If you have a predicate foo/2 which sometimes is called with a variable first argument, and you want the debugger to stop when the first argument is a specific constant (say 1), here is what you should do:

| ?- add_breakpoint([goal(foo(X,_)),true(X==1)], _).
% Conditional spypoint for user:foo/2 added, BID=1

Here the first test, goal, specifies that we are only interested in invocations of foo/2, and names the first argument of the goal as X. The second, the true/1 test specifies a further condition stated as a Prolog goal: X is identical to 1. Thus this breakpoint will be applicable if and only if the first argument of foo/2 is identical to 1. Generally, an arbitrary Prolog goal can be placed inside the true test: the test will succeed iff the goal completes successfully.

Both the pred and the goal tests may include a module name. In fact, the first argument of add_breakpoint is module name expanded, and the (explicit or implicit) module name of this argument is then inherited by default by the pred, goal, and true tests. Notice the module names inserted in the breakpoint spec of the last example, as shown in the output of the debugging built-in predicate:

| ?- debugging.
(...)
Breakpoints:
      1 *  user:foo/2 if [goal(user:foo(A,B)),true(user:(A==1))]

For exported predicates, a pred or goal test will be found applicable for all invocations of the predicate, irrespective of the module they occur in. When you add the breakpoint you can use the defining or an importing module name, but this information is not remembered: the module name is "normalized", i.e. it is changed to the defining module. For example:

| ?- use_module(library(lists)).
(...)
% module lists imported into user
(...)
| ?- spy user:append.
% Plain spypoint for lists:append/3 added, BID=1
yes
| ?- debugging.
(...)
Breakpoints:
      1 +  lists:append/3

If you would like to restrict a breakpoint to calls from within a particular module, then you should use the module test, e.g.

| ?- add_breakpoint([pred(append/3),module(user)], _).
% Conditional spypoint for lists:append/3 added, BID=1
yes
% zip
| ?- append([1,2], [3,4], L).
 *      1      1 Call: append([1,2],[3,4],_458) ? z
 *      1      1 Exit: append([1,2],[3,4],[1,2,3,4]) ?
L = [1,2,3,4] ?
yes

With this spypoint, the debugger will only stop at the invocations of append/3 from the user module. In the above example the debugger does not stop at the recursive calls to append/3 (from within the lists module), as would be the case with a plain spypoint.

Note that calling module information is not kept by the compiler for the built-in predicates, therefore the module test will always unify its argument with prolog in case of compiled calls to built-ins.

There are two further interesting breakpoint tests related to invocations: inv(Inv) and depth(Depth). These unify they arguments with the invocation number and the depth, respectively (the two numbers shown at the beginning of each trace message). Such tests are most often used in more complex breakpoints, but there may be some simple cases when they are useful.

Assume you put a plain spypoint on foo/2, and start leaping through your program. After some time, you notice some inconsistency at an Exit port, but you cannot go back to the Call port for retrying this invocation, because of side effects. So you would like to restart the whole top-level goal and get back to the Call port of the suspicious goal as fast as possible. Here is what you can do:

| ?- spy foo/2.
% Plain spypoint for user:foo/2 added, BID=1
yes
| ?- debug, foo(23, X).
% The debugger will first leap -- showing spypoints (debug)
 +      1      1 Call: foo(23,_414) ? l
(...)
 +     81     17 Call: foo(7,_9151) ? l
 +     86     18 Call: foo(6,_9651) ? l
 +     86     18 Exit: foo(6,8) ? -
% Plain spypoint for user:foo/2, BID=1, removed (last)
       86     18 Exit: foo(6,8) ? *
Placing spypoint on user:foo/2 with conditions: inv(86).
% Conditional spypoint for user:foo/2 added, BID=1
 *     86     18 Exit: foo(6,8) ? a
% Execution aborted
% source_info
| ?- debug, foo(23, X).
% The debugger will first leap -- showing spypoints (debug)
 *     86     18 Call: foo(6,_2480) ?

When you reach the Exit port of the suspicious invocation (number 86), you remove the plain spypoint, and add a conditional one using the * debugger command. This automatically includes pred(foo/2) among the conditions and displays the prompt Placing spypoint ... with conditions:, requesting further ones. You enter here the inv test with the invocation number in question, resulting in a breakpoint with the [pred(foo/2),inv(86)] conditions. If you restart the original top-level goal in debug mode, the debugger immediately positions you at the invocation with the specified number.

Note that when the debugger executes a skip or a zip command, no procedure boxes are built. Consequently, the invocation and depth counters are not incremented. If skip and/or zip commands were used during the first execution, then the suspicious invocation gets an invocation number higher than 86 in the second run. Therefore it is better to supply the inv(I),true(I>=86) condition to the * debugger command, which will bring you to the first call of foo/2 at, or after invocation number 86 (which still might not be the suspicious invocation).

In the examples, the inv test was used both with a numeric and a variable argument (inv(86) and inv(I)). This is possible because the debugger unifies the given feature with the argument of the test. This holds for most tests, we will mention the exceptions.

Another similar example: if you suspect that a given predicate goes into an infinite recursion, and would like the execution to stop when entering this predicate somewhere inside the recursion, then you can do the following:

| ?- add_breakpoint([pred(foo/2),depth(_D),true(_D>=100)], _).
% Conditional spypoint for user:foo/2 added, BID=1
yes
% zip,source_info
 | ?- debug, foo(200, X).
% The debugger will first leap -- showing spypoints (debug)
 *    496    100 Call: foo(101,_12156) ?

The above breakpoint spec will cause the debugger to stop at the first invocation of foo/2 at depth 100 or greater. Note again that debug mode has to be entered for this to work (in zip mode no debugging information is kept, so the depth does not change).

We now continue with tests which restrict the breakpoint to an invocation at a specific place in the code.

Assume file /home/bob/myprog.pl contains the following Prolog program:

p(X, U) :-                               % line 1
        q(X, Y),                         % line 2
        q(Y, Z),                         % line 3
        (   \+ q(Z, _)                   % line 4
        ->  q(Z+1, U)                    % line 5
        ;   q(Z+2, U)                    % line 6
        ).                               % ...

q(X, Y) :-
        X < 10, !, Y is X+1.             % line 10
q(X, Y) :-
        Y is X+2.                        % line 12

If you are interested only in the last invocation of q/2 within p/2, you can use the following breakpoint:

| ?- add_breakpoint([pred(q/2),line('/home/bob/myprog.pl',6)], _).
% Conditional spypoint for user:q/2 added, BID=1

Generally, the test line(File,Line) holds, if the current invocation was in line number Line of a file whose absolute name is File. This test (as well as the line/1 and file/1 tests) require the presence of source information: the file in question had to be consulted or compiled with the source_info prolog flag switched on (i.e. set to on or emacs).

If e.g. q/2 is called only from a single file, then the file name need not be mentioned and a line/1 test suffices: line(6). On the other hand, if we are interested in all invocations of a predicate within a file, then we can omit the line number and use the file(File) test.

For Prolog programs which are interpreted (consulted or asserted), further positioning information can be obtained, even in the absence of source information. The test parent_pred(Pred) unifies Pred with a predicate spec (of form Module:PredName/Arity) identifying the predicate in which the current invocation resides, while the test parent_pred(Pred,N) will additionally unify N with the serial number of the clause containing the current goal.

For example, assuming the above myprog.pl file is consulted, the breakpoint below will stop when execution reaches the call of is/2 in the second clause of q/2:

| ?- add_breakpoint([pred(is/2),parent_pred(user:q/2,2)], _).
% Conditional spypoint for prolog:is/2 added, BID=1
* Predicate prolog:is/2 compiled inline, breakable only in interpreted code
yes
% zip,source_info
| ?- p(20, X).
in scope of a goal at line 12 in /home/bob/myprog.pl
 *      1      1 Call: _579 is 20+2 ?

Note that one has to include an explicit module name prefix in the first argument of parent_pred, for the unification of the predicate spec to succeed. Also notice the warning issued by add_breakpoint/2: there are some built-ins (e.g. arithmetic, functor/3, arg/3, etc.), for which the compiler generates specific inline translation, rather than the generic predicate invocation code. Therefore compiled calls to such predicates are not visible to the debugger.

More exact positioning information can be obtained for interpreted programs by using the parent_clause(Cl,Sel,I) test. This unifies Cl with the clause containing the current invocation, while Sel and I both identify the current invocation within the body of this clause. Sel is unified with a subterm selector, while I with the serial number of the call. This test has variants parent_clause/[1,2], in which only the Cl argument, or the Cl,Sel arguments are present.

As an example, two further alternatives of putting a breakpoint on the last call of q/2 within myprog.pl (line 6) are shown below, together with a listing showing the selectors and call serial numbers for the body of p/2:

| ?- add_breakpoint([pred(q/2),parent_clause((p(_,_):-_),[2,2,2])],_).

| ?- add_breakpoint([pred(q/2),parent_clause((p(_,_):-_),_,5)],_).

p(X, U) :-                 % line  % call no.  % subterm selector
        q(X, Y),           %  2        1       [1]
        q(Y, Z),           %  3        2       [2,1]
        (   \+ q(Z, _)     %  4        3       [2,2,1,1,1]
        ->  q(Z+1, U)      %  5        4       [2,2,1,2]
        ;   q(Z+2, U)      %  6        5       [2,2,2]
        ).                 %  7

Here, the first argument of the parent_clause test ensures that the current invocation is in (the only clause of) p/2. If p/2 had more clauses, we would have to use an additional test, say parent_pred(user:p/2,1), and then the first argument of parent_clause could be an anonymous variable.

In the examples so far the breakpoint tests referred only to the goal in question. Therefore, the breakpoint was found applicable at all ports of the procedure box of the predicate. We can distinguish between ports using the port breakpoint test:

| ?- add_breakpoint([pred(foo/2),port(call)], _).

With this breakpoint, the debugger will stop at the Call port of foo/2, but not at other ports. Note that the port(call) test can be simplified to call -- add_breakpoint/2 will recognize this as a port name, and treat it as if it were enclosed in a port/1 functor.

Here are two equivalent formulations for a breakpoint which will cause the debugger to stop only at the Call and Exit ports of foo/2:

| ?- add_breakpoint([pred(foo/2),(call;exit)], _).

| ?- add_breakpoint([pred(foo/2),port(P),true((P=call;P=exit(_)))], _).

In both cases we have to use disjunction. In the first example we have a disjunctive breakpoint condition of the two simple tests port(call) and port(exit) (with the port functor omitted). In the second case the disjunction is inside the Prolog test within the true test.

Notice that the two examples refer to the Exit port differently. When you use port(P), where P is a variable, then, at an exit port, P will be unified with either exit(nondet) or exit(det), depending on the determinacy of the exited procedure. However, for convenience, the test port(exit) will also succeed at Exit ports. So in the first example above, exit can be replaced by exit(_), but the exit(_) in the second can not be replaced by exit.

Finally, there is a subtle point to note with respect to activating the debugger at non Call ports. Let us look at the following breakpoint:

| ?- add_breakpoint([pred(foo/2),fail], _).

The intention here is to have the debugger stop at only the Fail port of foo/2. This is very useful if foo/2 is not supposed to fail, but we suspect that it does. The above breakpoint will behave as expected when the debugger is leaping, but not while zipping. This is because for the debugger to be able to stop at a non Call port, a procedure box has to be built at the Call port of the given invocation. However, no debugging information is collected in zip mode by default, i.e. procedure boxes are not built. Later we will show how to achieve the required effect, even in zip mode.