[m-dev.] proposed command set for the internal trace based debugger

Peter Schachte pets at students.cs.mu.OZ.AU
Tue Jun 2 09:56:56 AEST 1998


On Mon, 1 Jun 1998, Zoltan Somogyi wrote:

> break points:
> The user may associate a break point with a specific goal path within
> a predicate. Break points have the same states and the same effects as spy
> points. XXX should an empty goal path cause a break on all of the
> CALL, EXIT and FAIL ports (the interface ports), or only on the CALL port?

I'm not sure I understand the difference between break and spy
points.  Is a break point just a spy point on a particular (lexical)
atom?  Or by "goal path" do you mean something like "the second call
to foo/4 in the fourth clause of bar/2 when called from the first call
to baz/5 in the first clause of zip/2 if it was called from the third
call to zap/2 in the eighth clause for zop/2...."


> print level:
> When a debugger command steps over some events without user interaction at
> those events, the *print level* controls under what circumstances the stepped
> over events will be printed. When the print level is "none", none of the
> stepped over events will be printed. When the print level is "all", all the
> stepped over events will be printed. When the print level is "some",
> the debugger will print the event only if a spy point or a break point
> with a state of "stop" or "print" applies to the event. Regardless of the
> print level, the debugger will print the event that causes execution to stop
> and user interaction to start.

It would be very useful to be able to (separately) turn on and off stopping
and printing based on port. 

It would also be good to have a way to turn off printing (and maybe to turn
it on, as well) for all subgoals of a certain goal, or subgoals of a certain
predicate.  Ideally, there would be a stateless (just zip through this goal
now without stopping or printing anything:  skip in Prolog debuggers) and a
stateful (until I say otherwise, always zip through calls to this predicate
(or this lexical call to this predicate)) without stopping or printing
anything.


> 	An empty command line is interpreted as "skip 1".
> 	XXX or maybe an empty command should do nothing?

How about allowing users to alias "" to do whatever they want?


> redo

Since this command, as far as I know, only exists until now in Prolog
debuggers, and Prolog debuggers call this "retry," and use "redo" to
mean something completely different, how about calling this "retry?"
You'll cause less confusion.


> 	Restarts execution at the call port of the call corresponding to the
> 	current event. Reports an error if the current event refers to a call
> 	port.
> 
> 	The command will report an error unless the values of all the input
> 	arguments are available at the current port. (The compiler will keep
> 	the values of the input arguments of traced predicates as long as
> 	possible, but it cannot keep them beyond the point where they are
> 	destructively updated.) The exception is values of type io__state;
> 	the debugger can perform a redo if the only missing value is of
> 	type io__state (there can be only one io__state at any given time).
> 	Such a redo has the following effects:
> 
> 	-	Any input and/or output actions in the repeated code
> 		will be repeated.
> 
> 	-	Any file close actions in the repeated code for which the
> 		corresponding file open action is not also in the repeated
> 		code may cause later I/O actions referring to the file to fail.
> 
> 	-	Any file open actions in the repeated code for which the
> 		corresponding file close action is not also in the repeated
> 		code may cause later file open actions to fail due to file
> 		descriptor leak.

Wouldn't it be possible to have a debug version of the library that
makes file opening and closing commands "trail" their effects so they
can be redone?  Ideally it would be possible for writers of libraries
containing destructive modes to also write mostly destructive versions and
have the debugger optionally use those instead in a systematic way, so they
could be retried.  Note that when code is being "skipped" over (in Prolog
terminology), you can just use the destructive version, for full speed and
lower memory usage.


One other command that would be useful (if it's implementable) would
be to replace the goal at the current port with one the user types in.
The user's goal would be able to include the variables appearing in
the goal at the current port.  This would be useful when you've found
a bug, and you'd like to keep going and find the next, so you just
want to supply the correct result for a goal and keep going.


> stack
> 	Prints the names of the ancestors of the call specified by the
> 	current event. If two or more ancestor calls are for the same
> 	predicate, the predicate name will be printed once with the
> 	appropriate multiplicity annotation.

What about for mutually recursive predicates?  For example, the case where
the stack has 4 calls to foo/3, then a few calls to other predicates, then 8
more calls to foo/3?  I presume this just shows up as 4 and then 8 calls to
foo/3, not as 12 calls? 

It would be useful to have this print a number for each stack frame, and to
have a command like up and down (maybe "show" or "goto"?) that takes one of
these numbers and makes that the current frame directly. 


> spy <module name> <predicate name>

I think it would be better to use the standard module:name/arity
syntax to spy predicates.  As a convenience to users, it'd be good to
allow everything but name to be omitted, treating the omitted items as
wildcards, and to then spy every matching predicate.

Also it's nice to be able to spy multiple predicates in one command.


> 	Puts a spy point on the named predicate in the named module.
> 
> 	The options -stop, -print and -none specify the initial state of
> 	the spy point.
> 
> 	By default, the initial state of the spy point is "stop".
> 
> break <module name> <predicate name>
> 	Puts a break point on the CALL port of the named predicate in the

Whoa!  Alright, now I'm really confused.  What's a break point?

I think one wants the following abilities regarding spy/break points:

	1.  Stop at some or all ports of calls to a particular
	    predicate.
	2.  Stop at some or all ports of a particular (lexical) call
	    to a particular predicate.  By this I mean something like
	    "the third call to foo/2 in the fourth clause of bar/3."
	3.  Print the goal but don't stop, and maybe stop but don't
	    print the goal (just some indication of where you are) in
	    any of those contexts.
	4.  Ideally, some of the capabilities pretty much standard in
	    C debuggers like "only stop/print if this condition holds,"
	    and "execute this command whenever this condition holds,
	    then print/don't print and stop/don't stop."


> 	named module. (XXX Should it be on all the interface ports, i.e.
> 	CALL, EXIT and FAIL?)

You seem to have omitted the REDO port.  That one's pretty important.

> here
> 	Puts a break point on the predicate referred to by the current event
> 	at the goal path named by the current event.

I think it would be much better to have a syntax for specifying "here"
as a predicate spec in spy and break commands.


Also, does all of this work exactly the same for functions?  Maybe
there should be a syntax for spying functions, in case there is a
function and predicate with the same name and arity?


-Peter Schachte               | Capitalism is the astounding belief that the
mailto:pets at cs.mu.OZ.AU       | most wickedest of men will do the most
http://www.cs.mu.oz.au/~pets/ | wickedest of things for the greatest good of
PGP: finger pets at 128.250.37.3 | everyone. -- John Maynard Keynes 




More information about the developers mailing list