YAP 7.1.0
spy.yap
Go to the documentation of this file.
1/**
2 * @file spy.yap
3 * @brief debugger operation.
4 */
5 :- debug/0debugging/0leash/1nodebug/0nospyall/0notrace/0trace/0'$init_debugger'/0system_module( '$_debug', [,
6 ,
7 ,
8 ,
9 (nospy)/1,
10 ,
11 ,
12 (spy)/1,
13 ], [
14 ]).
15
16:- '$find_goal_definition'/4'$system_catch'/4use_system_module( '$_boot', [,
17 ]).
18
19:- '$Error'/1'$do_error'/2use_system_module( '$_errors', [,
20 ]).
21
22:- '$system_module'/1use_system_module( '$_init', []).
23
24:- '$meta_expansion'/6use_system_module( '$_modules', []).
25
26:- '$clause'/4use_system_module( '$_preds', []).
27
28/*-----------------------------------------------------------------------------
29
30 Debugging / creating spy points
31
32-----------------------------------------------------------------------------*/
33
34/**
35 * @defgroup DebSet Debugger Control
36 * @ingroup Deb_Interaction
37
38@{
39The
40 following predicates are available to control the debugging of
41programs:
42
43+ debug
44
45 Switches the debugger on.
46
47+ debugging
48
49
50 Outputs status information about the debugger which includes the leash
51mode and the existing spy-points, when the debugger is on.
52
53 + nodebug
54
55 Switches the debugger off.
56
57
58*/
59
60
61:- op(900,fx,[spy,nospy]).
62
63% First part : setting and reseting spy points
64
65 % $suspy does most of the work
66'$suspy'(V,S,M) :-
67 var(V) , var,
68 '$do_error'(instantiation_error,M:spy(V,S)).
69 '$suspy'((M:S),P,_) :- '$suspy',
70 '$suspy'(S,P,M).
71 '$suspy'([],_,_) :- '$suspy'.
72 '$suspy'([F|L],S,M) :- '$suspy', ( '$suspy'(F,S,M) ; '$suspy'(L,S,M) ).
73 '$suspy'(F/N,S,M) :- '$suspy',
74 functor(T,F,N),
75 '$do_suspy'(S, F, N, T, M).
76 '$suspy'(A,S,M) :- atom(A), atom,
77 '$suspy_predicates_by_name'(A,S,M).
78 '$suspy'(P,spy,M) :- '$suspy',
79 '$do_error'(domain_error(predicate_spec,P),spy(M:P)).
80 '$suspy'(P,nospy,M) :-
81 '$do_error'(domain_error(predicate_spec,P),nospy(M:P)).
82
83 '$suspy_predicates_by_name'(A,S,M) :-
84 % just check one such predicate exists
85 (
87 *->
88 functor(T,A,N),
89 '$do_suspy'(S,A,N,T,M),
90 '$do_suspy'
91 ;
92 Error =..[S,M:A],
93 print_message(warning,no_match(Error))
94 ).
95 '$suspy_predicates_by_name'(_A,_S,_M).
96
97 %
98 % protect against evil arguments.
99 %
100'$do_suspy'(S, F, N, T, M) :-
101 '$undefined'(T,M), '$undefined',
102 ( S = spy ->
103 print_message(warning,no_match(spy(M:F/N)))
104 ;
105 print_message(warning,no_match(nospy(M:F/N)))
106 ).
107 '$do_suspy'(S, F, N, T, M) :-
108 '$is_system_predicate'(T,M),
109 '$predicate_flags'(T,M,Fl,Fl),
110 Fl /\ 0'$predicate_flags' =\= 0,
111 ( S = spy ->
112 '$do_error'(permission_error(access,private_procedure,T),spy(M:F/N))
113 ;
114 '$do_error'(permission_error(access,private_procedure,T),nospy(M:F/N))
115 ).
116
117'$do_suspy'(S,F,N,T,M) :-
118 '$suspy2'(S,F,N,T,M).
119
120 '$suspy2'(spy,F,N,T,M) :-
121 recorded('$spy','$spy'(T,M),_),
122 recorded,
123 print_message(informational,breakp(bp(debugger,plain,M:T,M:F/N,N),add,already)).
124'$suspy2'(spy,F,N,T,M) :- '$suspy2',
125 recorda('$spy','$spy'(T,M),_),
126 '$set_spy'(T,M),
127 print_message(informational,breakp(bp(debugger,plain,M:T,M:F/N,N),add,ok)).
128'$suspy2'(nospy,F,N,T,M) :-
129 recorded('$spy','$spy'(T,M),R), recorded,
130 erase(R),
131 '$rm_spy'(T,M),
132 print_message(informational,breakp(bp(debugger,plain,M:T,M:F/N,N),remove,last)).
133'$suspy2'(nospy,F,N,_,M) :-
134 print_message(informational,breakp(no,breakpoint_for,M:F/N)).
135
136'$pred_being_spied'(G, M) :-
137 recorded('$spy','$spy'(G,M),_), recorded.
138
139/**
140@pred spy( + _P_ ).
141
142Sets spy-points on all the predicates represented by
143 _P_. _P_ can either be a single specification or a list of
144specifications. Each one must be of the form _Name/Arity_
145or _Name_. In the last case all predicates with the name
146 _Name_ will be spied. As in C-Prolog, system predicates andpredicates written in C, cannot be spied.
147
148
149*/
150spy Spec :-
151 '$init_debugger',
152 recorded:debug_action_hook(spy(Spec)), debug_action_hook.
153 spy L :-
154 '$current_module'(M),
155 '$suspy'(L, spy, M), '$suspy'.
156spy _ :-
157 '$suspy'.
158
159/** @pred nospy( + _P_ )
160
161
162Removes spy-points from all predicates specified by _P_.
163The possible forms for _P_ are the same as in `spy P`.
164
165
166*/
167nospy Spec :-
168 '$init_debugger',
169 '$suspy':debug_action_hook(nospy(Spec)), debug_action_hook.
170 nospy L :-
171 '$current_module'(M),
172 '$suspy'(L, nospy, M), '$suspy'.
173nospy _.
174
175/** @pred nospyall
176
177Removes all existing spy-points.
178*/
179nospy'$suspy' :-
180 '$init_debugger',
181 '$suspy':debug_action_hook(nospyall), debug_action_hook.
182nospydebug_action_hook :-
183 recorded('$spy','$spy'(T,M),_), functor(T,F,N), '$suspy'(F/N,nospy,M), '$suspy'.
184nospy'$suspy'.
185
186 % debug mode -> debug flag = 1
187/** @pred debug
188
189Enables the Prolof debugging. Notice that tracing is disabled, even if it was active.
190*/
191'$suspy' :-
192 ( '__NB_getval__'('$spy_gn',_, fail) -> '__NB_getval__' ; '__NB_setval__'('$spy_gn',1) ),
193 set_prolog_flag(debug,true),
194 '$set_debugger_state'(debug, true),
195 '$set_debugger_state'(trace, off),
196 '$start_user_code',
197 print_message(informational,debug(debug)),
198 '$init_debugger'.
199
200'$start_user_code' :-
201 current_prolog_flag(debug, Can),
202 '$set_debugger_state'(debug, Can),
203 '$stop_creeping'(_).
204
205'$stop_creeping' :-
206 set_prolog_flag(debug, false),
207 '$set_debugger_state'(debug, false),
208 '$set_debugger_state'(trace, off),
209 print_message(informational,debug(off)).
210
211%
212% remove any debugging info after an abort.
213%
214
215
216/** @pred trace
217
218
219Switches on the debugger and enters tracing mode.
220
221
222*/
223print_message :-
224 ( '__NB_getval__'('$spy_gn',_, fail) -> '__NB_getval__' ; '__NB_setval__'('$spy_gn',1) ),
225 print_message(informational,debug(trace)),
226 set_prolog_flag(debug,true),
227 '$set_debugger_state'(debug, true),
228 '$set_debugger_state'(trace, on),
229 '$init_debugger'.
230
231/** @pred notrace
232
233
234Ends tracing and exits the debugger. This is the same as
235nodebug/0.
236 */
237not'$set_debugger_state' :-
238 '$set_debugger_state'.
239
240/*-----------------------------------------------------------------------------
241
242 leash
243
244 -----------------------------------------------------------------------------*/
245
246
247/** @pred leash(+ _M_)
248
249
250Sets leashing mode to _M_.
251The mode can be specified as:
252
253+ `full`
254prompt on Call, Exit, Redo and Fail
255
256+ `tight`
257prompt on Call, Redo and Fail
258
259+ `half`
260prompt on Call and Redo
261
262+ `loose`
263prompt on Call
264
265+ `off`
266never prompt
267
268+ `none`
269never prompt, same as `off`
270
271The initial leashing mode is `full`.
272
273The user may also specify directly the debugger ports
274where he wants to be prompted. If the argument for leash
275is a number _N_, each of lower four bits of the number is used to
276control prompting at one the ports of the box model. The debugger will
277prompt according to the following conditions:
278
279+ if `N/\ 1 =\= 0` prompt on fail
280+ if `N/\ 2 =\= 0` prompt on redo
281+ if `N/\ 4 =\= 0` prompt on exit
282+ if `N/\ 8 =\= 0` prompt on call
283
284Therefore, `leash(15)` is equivalent to `leash(full)` and
285`leash(0)` is equivalent to `leash(off)`.
286
287Another way of using `leash` is to give it a list with the names of
288the ports where the debugger should stop. For example,
289`leash([call,exit,redo,fail])` is the same as `leash(full)` or
290`leash(15)` and `leash([fail])` might be used instead of
291`leash(1)`.
292
293 @}
294
295*/
296leash(X) :- var(X),
297 '$do_error'(instantiation_error,leash(X)).
298leash(X) :-
299 '$init_debugger',
300 '$leashcode'(X,Code),
301 set_value('$leash',Code),
302 '$show_leash'(informational,Code), '$show_leash'.
303leash(X) :-
304 '$do_error'(type_error(leash_mode,X),leash(X)).
305
306'$show_leash'(Msg,0) :-
307 print_message(Msg,leash([])).
308'$show_leash'(Msg,Code) :-
309 '$check_leash_bit'(Code,0x8,L3,call,LF),
310 '$check_leash_bit'(Code,0x4,L2,exit,L3),
311 '$check_leash_bit'(Code,0x2,L1,redo,L2),
312 '$check_leash_bit'(Code,0x1,[],fail,L1),
313 print_message(Msg,leash(LF)).
314
315'$check_leash_bit'(Code,Bit,L0,_,L0) :- Bit /\ Code =:= 0, '$check_leash_bit'.
316'$check_leash_bit'(_,_,L0,Name,[Name|L0]).
317
318'$leashcode'(full,0xf) :- '$leashcode'.
319'$leashcode'(on,0xf) :- '$leashcode'.
320'$leashcode'(half,0xb) :- '$leashcode'.
321'$leashcode'(loose,0x8) :- '$leashcode'.
322'$leashcode'(off,0x0) :- '$leashcode'.
323'$leashcode'(none,0x0) :- '$leashcode'.
324%'$leashcode'([L|M],Code) :- !, '$leashcode_list'([L|M],Code).
325'$leashcode'([L|M],Code) :- '$leashcode',
326 '$list2Code'([L|M],Code).
327'$leashcode'(N,N) :- integer(N), N >= 0, N =< 0integer.
328
329'$list2Code'(V,_) :- var(V), var,
330 '$do_error'(instantiation_error,leash(V)).
331'$list2Code'([],0) :- '$list2Code'.
332'$list2Code'([V|L],_) :- var(V), var,
333 '$do_error'(instantiation_error,leash([V|L])).
334'$list2Code'([call|L],N) :- '$list2Code'(L,N1), N is 0'$list2Code' + N1.
335'$list2Code'([exit|L],N) :- '$list2Code'(L,N1), N is 0'$list2Code' + N1.
336'$list2Code'([redo|L],N) :- '$list2Code'(L,N1), N is 0'$list2Code' + N1.
337'$list2Code'([fail|L],N) :- '$list2Code'(L,N1), N is 0'$list2Code' + N1.
338
339/*-----------------------------------------------------------------------------
340
341 debugging
342
343-----------------------------------------------------------------------------*/
344
345'$list2Code' :-
346 '$init_debugger',
347 '$list2Code':debug_action_hook(nospyall), debug_action_hook.
348debug_action_hook :-
349 ( current_prolog_flag(debug, true) ->
350 print_message(help,debug(debug))
351 ;
352 print_message(help,debug(off))
353 ),
354 findall(M:(N/A),(recorded('$spy','$spy'(T,M),_),functor(T,N,A)),L),
355 print_message(help,breakpoints(L)),
356 get_value('$leash',Leash),
357 '$show_leash'(help,Leash).
358
359/*
360notrace(G) :-
361 strip_module(G, M, G1),
362 ( current_choice_point(CP),
363 '$debug_stop'( State ),
364 '$call'(G1, CP, G, M),
365 current_choice_point(CP2),
366 (CP == CP2 -> ! ; '$debug_state'( NState ), ( true ; '$debug_restart'(NState), fail ) ),
367 '$debug_restart'( State )
368 ;
369 '$debug_restart'( State ),
370 fail
371 ).
372*/
373'$init_debugger' :-
374 '$debugger_io',
375 '$init_debugger_trace',
376 '__NB_setval__'('$if_skip_mode',run),
377 '__NB_setval__'('$spy_glist',[]),
378 '__NB_setval__'('$spy_gdlist',[]),
379 '__NB_setval__'('$spy_gn',1).
380
381'$init_debugger_trace' :-
382 '$get_debugger_state'( trace, on ),
383 '$get_debugger_state',
384 '$set_debugger_state'( creep, 0, stop, on, true ).
385'$init_debugger_trace' :-
386 '$set_debugger_state'( zip, 0, stop, off, true ).
387
388%% @pred $enter_debugging(G,Mod,CP,G0,NG)
389%%
390%% Internal predicate called by top-level;
391%% enable creeping on a goal by just switching execution to debugger.
392%%
393'$enter_debugging'(G,Mod,_CP,_G0,_NG) :-
394 '$creepcalls'(G,Mod),
395 '$creepcalls'.
396'$enter_debugging'(G,_Mod,_CP,_G0,G).
397
398'$enter_debugging'(G,Mod,GN) :-
399 current_prolog_flag( debug, Deb ),
400 '$set_debugger_state'( debug, Deb ),
401 ( Deb = false
402 ->
403 true
404 ;
405 '$do_trace'(G,Mod,GN)
406 ->
407 '$creep'
408 ;
409 '$do_trace'
410 ).
411
412'$exit_debugger'(Mod:G, GN) :-
413 current_prolog_flag( debug, Deb ),
414 '$set_debugger_state'( debug, Deb ),
415 ( Deb = false
416 ->
417 true
418 ;
419 '$do_trace'(G,Mod,GN)
420 ->
421 '$creep'
422 ;
423 '$do_trace'
424 ).
425
426%% @pred $enable_debugging
427%%
428%% Internal predicate called when exiting the debuger through a port;
429%% enable creeping on the next goal.
430%%
431/*'$enable_debugging' :-
432 current_prolog_flag( debug, Deb ),
433 '$set_debugger_state'( debug, Deb ),
434 '$creep'.
435*/
436
437/**
438 * @pred $stop_at_this_goal( Goal, Module, Id)
439 *
440 * debugger should prompt the user if:
441 * - creep on
442 * - spy point enabled
443 * - the goal is older than ourselves: Id is bound
444 * and Id <= StateGoal
445 *
446 */
447 %cannot debug is called at the call port. UNUSED
448/*
449'$cannot_debug'(G, Module, GoalNo) :-
450 (
451 current_prolog_flag( debug, false )
452 ;
453 '$is_private'(G,Module)
454 ;
455 functor(G,Na,_), atom_concat('$',_,Na)
456 ;
457 \+ '$debuggable'(G, Module,GoalNo)
458 ),
459 !.
460 */
461
462'$debuggable'(_G, _Module,_GoalNo) :-
463 current_prolog_flag(debug, false),
464 current_prolog_flag,
465 current_prolog_flag.
466'$debuggable'(G, Module,_GoalNo) :-
467 '$pred_being_spied'(G,Module),
468 '$get_debugger_state'( spy, stop ),
469 '$get_debugger_state'.
470'$debuggable'(_G, _Module,GoalNo) :-
471 '$get_debugger_state'( creep, zip ),
472 '$get_debugger_state',
473 nonvar(GoalNo),
474 '$get_debugger_state'( goal_number, TargetGoal ),
475 nonvar(TargetGoal),
476 GoalNo < TargetGoal.
477'$debuggable'(_G, _Module,_GoalNo).
478
479
480
481'$leap'(Ports,GoalNo) :-
482 '$get_debugger_state'( creep, L),
483 (L == zip; L==leap),
484 ,
485 (
486 var(GoalNo)
487 ->
488 var
489 ;
490 '$get_debugger_state'( goal_number, TargetGoal ),
491 number(GoalNo),
492 number(TargetGoal),
493 (
494 GoalNo > TargetGoal ->
495 true
496 ;
497 GoalNo == TargetGoal
498 ->
499 (
500 Ports == [redo];
501 Ports == [fail,answer]
502 )
503 , !
504 )
505 ).
506
507
508'$run_deb'(Port,GN0,GN) :-
509 '$stop_creeping'(_),
510 '$cross_run_deb'(Port,GN0,GN).
511
512
513'$cross_run_deb'(call,_Ctx,_GN).
514'$cross_run_deb'(internal,_Ctx,_GN).
515'$cross_run_deb'(redo,Ctx,_GN) :-
516 '$continue_debugging'(Ctx).
517'$cross_run_deb'(fail,Ctx,_GN) :-
518 '$continue_debugging'(Ctx).
519'$cross_run_deb'(exit,Ctx,_GN) :-
520 '$continue_debugging'(Ctx).
521'$cross_run_deb'(answer,Ctx,_GN) :-
522 '$continue_debugging'(Ctx).
523'$cross_run_deb'(exception(_),_GN0,_GN) :-
524 '$set_debugger_state'(debug,false).
525'$cross_run_deb'(external_exception(_),_GN0,_GN) :-
526 '$set_debugger_state'(debug,false).
527
528'$exit_goal'(false, _GN) :-
529 '$set_debugger_state'(debug,false).
530'$exit_goal'(true, GN):-
531 '$continue_debugging'(GN).
532
533'$continue_debugging'(_) :-
534 current_prolog_flag(debug, false),
535 current_prolog_flag.
536'$continue_debugging'(_) :-
537 '$get_debugger_state'(trace, on),
538 '$get_debugger_state'(creep,zip),
539 '$set_debugger_state'(creep,creep),
540 '$set_debugger_state'.
541'$continue_debugging'(outer) :-
542 '$set_debugger_state'(debug,true).
543'$continue_debugging'(inner).
544
545'$restart_debugging':-
546 '$set_debugger_state'(debug,Debug),
547 '$get_debugger_state'(creep,Creep),
548 '$may_creep'(Debug,Creep),
549 '$may_creep',
550 '$creep'.
551'$restart_debugging'.
552
553'$may_creep'(true,creep).
554'$may_creep'(true,leap).
555
556/**
557
558@}
559
560*/
561
current_predicate( A, P)
op(+ P,+ T,+ A)
system_module( + Mod)
leash(+ M)
erase(+ R)
findall( T,+ G,- L)
Definition: setof.yap:70
current_prolog_flag(? Flag,- Value)
set_prolog_flag(+ Flag,+ Value)
print_message(+ Severity, +Term)
get_value(+ A,- V)
set_value(+ A,+ C)
atom( T)
functor( T, F, N)
integer( T)
nonvar( T)
number( T)
var( T)