Node:Built-in Predicates for Breakpoint Handling, Next:, Previous:Advice-points, Up:Advanced Debugging



Built-in Predicates for Breakpoint Handling

For the last advice-point example to be practical, it should be improved to assert only line numbers not recorded so far. For this you will write a Prolog predicate for the conditional assertion of file/line information, assert_line_reached(File,Line). The breakpoint spec will then look as follows:

| ?- add_breakpoint([advice,goal(_:_),call,line(F,L)]
                      -[true(assert_line_reached(F,L)),flit], _).

The above breakpoint spec can be simplified by moving the line(F,L) query into the Prolog goal called within the true/1 condition. To achieve this, the built-in predicate execution_state/1 can be used. This predicate takes a simple or a composite breakpoint condition as its argument and evaluates it, as if in the test part of a breakpoint spec. The predicate will succeed iff the breakpoint condition evaluates successfully. Thus execution_state/1 allows you to access debugging information from within Prolog code. For example, you can write a Prolog predicate, assert_line_reached/0, which queries the debugger for the current line information and then processes the line number:

assert_line_reached :-
        (   execution_state(line(F,L)) -> assert_line_reached(F,L).
        ;   true
        ).

| ?- add_breakpoint([advice,goal(_:_),call]
                      -[true(assert_line_reached),flit], _).

Note that assert_line_reached/0 succeeds even if no source information is available. This is to avoid the creation of procedure boxes (if the action part fails, a procedure box is created).

Arbitrary tests can be used in execution_state/1, if it is called from within a true condition. It can also be called from outside the debugger, but then only a subset of conditions is available. Furthermore, the built-in predicate execution_state/2 allows accessing information from past debugger states (see Accessing Past Debugger States.

The built-in predicates remove_breakpoints(BIDs), disable_breakpoints(BIDs) and enable_breakpoints(BIDs) serve for removing, disabling and enabling the given breakpoints. Here BIDs can be a single breakpoint identifier, a list of these, or one of the atoms all, advice, debugger.

We now show an application of remove_breakpoints/1 for implementing one-off breakpoints, i.e. breakpoints which are removed when first activated.

For this we need to get hold of the currently selected breakpoint identifier. The bid(BID) condition serves for this purpose: it unifies its argument with the identifier of the breakpoint being processed. The following is an example of a one-off breakpoint.

| ?- spy(foo/2, -[bid(BID),true(remove_breakpoints(BID)),leash]).
% Conditional spypoint for user:foo/2 added, BID=1
true ?
yes
% zip
| ?- foo(2, X).
% Conditional spypoint for user:foo/2, BID=1, removed (last)
        1      1 Call: foo(2,_402) ? z
X = 1 ?

The action part of the above breakpoint calls the bid test to obtain the breakpoint identifier. It then uses this number as the argument to the built-in predicate remove_breakpoints, which removes the activated breakpoint.

The built-in predicate current_breakpoint(Spec, BID, Status, Kind) enumerates all breakpoints present in the debugger. Here Spec is the breakpoint spec of the breakpoint with identifier BID, Status is on for enabled breakpoints and off for disabled ones, while Kind is one of plain, conditional or generic. The Spec returned by current_breakpoint/4 is not necessarily the same as the one given in add_breakpoint/2, as the breakpoint spec is subject to some normalization, see Breakpoint Predicates.