Node:Breakpoint Processing, Next:, Previous:Breakpoint Predicates, Up:Debug Intro



The Processing of Breakpoints

This section describes in detail how the debugger handles the breakpoints. For the purpose of this section disabled breakpoints are not taken into account: whenever we refer to the existence of some breakpoint(s), we always mean the existence of enabled breakpoint(s).

The Prolog engine can be in one of the following three states with respect to the debugger:

no debugging
if there are no advice-points and the debugger is either switched off, or doing a skip;
full debugging
if the debugger is in trace or debug mode (creeping or leaping), or there are any generic breakpoints;
selective debugging
in all other cases.

In the selective debugging state only those predicate invocations are examined, for which there exists a specific breakpoint. In the full debugging state all invocations are examined, except those calling a non-exported predicate of a hidden module (but even these will be examined, if there is a specific breakpoint for them). In the no debugging state the debugger is not entered at predicate invocations.

Now we describe what the debugger does when examining an invocation of a predicate, i.e. executing its Call port. The debugger activities can be divided into three stages: advice-point processing, spypoint processing and interaction with the user. The last stage may be repeated several times before program execution continues.

The first two stages are similar, as they both search for an applicable breakpoint (spypoint or advice-point). This breakpoint search is carried out as follows. The debugger considers all breakpoints of the given type, most recent first. The first breakpoint, for which the evaluation of the test part succeeds is selected. Next, the action part of the selected breakpoint is evaluated, normally setting some debugger action variables. If the action part succeeds, then the breakpoint search is said to complete successfully. If the action part fails, then the breakpoint search is still considered successful. As a side effect, however, it is ensured that a procedure box is built (if the command action variable is flit, it is changed to proceed). If none of the test parts evaluated successfully then the search is said to have failed.

Now let us look at the details of the first stage, advice-point processing. This stage is executed only if there are any advice-points set. First, the debugger action variables are initialized: mode is set to the current debugger mode, command to proceed and show to silent. Next, advice-point search takes place. If this fails, command is set to flit, otherwise its value is unchanged.

Having completed the advice-point search, the command variable is examined. If its value is divertive, i.e. different from proceed and flit, then the spypoint search stage is omitted, and the debugger continues with the third stage. Otherwise, it is noted if advice-point processing has requested the building of a procedure box (i.e. command = proceed), and the debugger continues with the second stage.

The second stage is spypoint processing. This stage is skipped if the debugger is switched off or doing a skip (mode is off or skip(_)). First the the show and command variables are re-assigned, based on the hiddenness of the predicate being invoked, the debugger mode and the leashing status of the port. If the predicate is both defined in, and called from a hidden module, then their values will be silent and flit. An example of this is when a built-in predicate is called from a hidden module, e.g. from a library. Otherwise, in trace mode, their values are print and ask for leashed ports, and print and proceed for unleashed ports. In debug mode, the variables are set to silent and proceed, while in zip mode to silent and flit (Breakpoint Actions contains a tabulated listing of these initialization values).

Having initialized the debugger action variables, spypoint search is performed. If an empty action part has been selected in a successful search, then show and command are set to print and ask. The failure of the search is ignored.

The third stage is the interactive part. First, the goal in question is displayed according to the value of show. Next, the value of command is checked: if it is other than ask, then the interactive stage ends. Otherwise, (it is ask), the variable show is re-initialized to print, or to print-Sel, if its value was of form Method-Sel. Next, the debugger prompts the user for a command which is interpreted either in the standard way, or through user:debugger_command_hook/2. In both cases the debugger action variables are modified as requested, and the interactive part is repeated.

After the debugger went through all the three stages, it decides whether to build a procedure box. This will happen if either the advice-point stage or the other two stages require it. The latter is decided by checking the command variable: if that is flit or flit(Old,New), then no procedure box is required by the spypoint part. If the advice-point does require the building of a procedure box, then the above command values are replaced by proceed and proceed(Old,New), respectively.

At the end of the process the value of mode will be the new debugging mode, and command will determine what the debugger will do; see Action Variables.

A similar three-stage process is carried out when the debugger arrives at a non-Call port of a predicate. The only difference is that the building of a procedure box is not considered (flit is equivalent to proceed), and the hiddenness of the predicate is not taken into account.

While the Prolog system is executing the above three-stage process for any of the ports, it is said to be inside the debugger. This is relevant, because some of the conditions can only be evaluated in this context.