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 the current goal is an
instance of G
, i.e. G
and the current goal can be
unified without substituting any variables in the
latter. This unification is then carried out. The goal(G)
condition is thus equivalent to the subsumes(G,
CurrentGoal)
test (subsumes/2
is defined in library(terms)
, see lib-terms).
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
, nor if it is a variable.
You can use non-anonymous variables in the goal
test, and
then put further constraints on these variables using the
true
condition:
| ?- 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
greater than 1
(we assume here that the argument is
numeric). Thus this breakpoint will be applicable if and only if
the first argument of foo/2
is greater than
1
. Generally, an arbitrary Prolog goal can be placed inside
the true
test: the test will succeed if and only if the goal completes
successfully.
Any variable instantiations in the test part will be undone
before executing the action part, as the evaluation of the test part is
enclosed in a double negation (\+ \+ (...)
). This ensures
that the test part has no effect on the variables of the current
goal.
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 qualification inserted in front of the
breakpoint spec of the last example, as shown in the output of the
debugging/0
built-in predicate:
| ?- debugging. (...) Breakpoints: 1 * user:foo/2 if user:[goal(foo(A,B)),true(A>1)]
As no explicit module qualifications were given in the tests, this breakpoint spec is transformed to the following form:
[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 the call occurs 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. The example below shows this: although the
spypoint is placed on user:append
, the message and the
breakpoint list both mention lists:append
.
| ?- use_module(library(lists)). (...) % module lists imported into user (...) | ?- spy user:append. % Plain spypoint for lists:append/3 added, BID=1 | ?- debugging. (...) Breakpoints: 1 + lists:append/3
Note that the debugger does not stop inside a library predicate when doing an exhaustive trace. This is because the library modules are declared hidden (see ref-mod), and no trace is produced for calls inside hidden modules that invoke predicates defined in hidden modules. However, a spypoint is always shown in the trace, even if it occurs in a hidden module:
+ 1 1 Call: append([1,2],[3,4],_531) ? <RET> + 2 2 Call: lists:append([2],[3,4],_1182) ? <RET> + 3 3 Call: lists:append([],[3,4],_1670) ? <RET> + 3 3 Exit: lists:append([],[3,4],[3,4]) ? <RET> (...)
You can narrow a breakpoint to calls from within a particular
module by using the module
test, e.g.
| ?- add_breakpoint([pred(append/3),module(user)], _). % The debugger will first zip -- showing spypoints (zip) % Conditional spypoint for lists:append/3 added, BID=1 % zip | ?- append([1,2], [3,4], L). * 1 1 Call: append([1,2],[3,4],_531) ? <RET> * 1 1 Exit: append([1,2],[3,4],[1,2,3,4]) ? <RET> L = [1,2,3,4]
With this spypoint, the debugger will only stop at the invocations
of append/3
from the user
module.
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-in
predicates.
There are two further interesting breakpoint tests related to
invocations: inv(Inv)
and depth(Depth)
. These unify
their 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 | ?- 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) ? <RET>
When you reach the Exit port of the suspicious invocation (number
86), you remove the plain spypoint (via the - debugger
command), 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, 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, you can do the following:
| ?- add_breakpoint([pred(foo/2),depth(_D),true(_D>=100)], _). % Conditional spypoint for user:foo/2 added, BID=1 % 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 that restrict the breakpoint to an invocation at a specific place in the code.
Assume file /home/bob/myprog.pl
contains the following Prolog
program:
% /home/bob/myprog.plp(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; see below) 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, 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, we can omit the
line number and use the file(File)
test.
For Prolog programs that are interpreted (consulted or
asserted), further positioning information can be obtained, even in the
absence of source information. The test parent_pred(Pred)
unifies the module name expanded Pred
with a
predicate spec (of form
Module:
PredName/
Arity) identifying the
predicate in which the current invocation resides. 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 cause the execution to
stop when the call of is/2
in the second clause of
q/2
is reached:
| ?- add_breakpoint([pred(is/2),parent_pred(q/2,2)], _). % Conditional spypoint for prolog:is/2 added, BID=1 * Predicate prolog:is/2 compiled inline, breakable only in interpreted code % 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 ?
Notice the warning issued by add_breakpoint/2
: there are some
built-in predicates (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 the 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 that 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 predicate. 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.