1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: jan@swi-prolog.org 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2021-2023, SWI-Prolog Solutions b.v. 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(prolog_debug_tools, 36 [ (spy)/1, % :Spec (some users tend to define these as 37 (nospy)/1, % :Spec an operator) 38 nospyall/0, 39 debugging/0, 40 trap/1, % +Exception 41 notrap/1 % +Exception 42 ]). 43:- use_module(library(broadcast), [broadcast/1]). 44:- autoload(library(edinburgh), [debug/0]). 45:- autoload(library(gensym), [gensym/2]). 46 47:- set_prolog_flag(generate_debug_info, false).
63:- multifile 64 prolog:debug_control_hook/1. % +Action 65 66:- meta_predicate 67 spy( ), 68 nospy( ).
informational
, with one of
the following terms, where Spec is of the form M:Head.
spy(Spec)
nospy(Spec)
85spy(Spec) :- 86 '$notrace'(spy_(Spec)). 87 88spy_(_:X) :- 89 var(X), 90 throw(error(instantiation_error, _)). 91spy_(_:[]) :- !. 92spy_(M:[H|T]) :- 93 !, 94 spy(M:H), 95 spy(M:T). 96spy_(Spec) :- 97 prolog:debug_control_hook(spy(Spec)), 98 !. 99spy_(Spec) :- 100 '$find_predicate'(Spec, Preds), 101 '$member'(PI, Preds), 102 pi_to_head(PI, Head), 103 '$define_predicate'(Head), 104 '$spy'(Head), 105 fail. 106spy_(_). 107 108nospy(Spec) :- 109 '$notrace'(nospy_(Spec)). 110 111nospy_(_:X) :- 112 var(X), 113 throw(error(instantiation_error, _)). 114nospy_(_:[]) :- !. 115nospy_(M:[H|T]) :- 116 !, 117 nospy(M:H), 118 nospy(M:T). 119nospy_(Spec) :- 120 prolog:debug_control_hook(nospy(Spec)), 121 !. 122nospy_(Spec) :- 123 '$find_predicate'(Spec, Preds), 124 '$member'(PI, Preds), 125 pi_to_head(PI, Head), 126 '$nospy'(Head), 127 fail. 128nospy_(_). 129 130nospyall :- 131 '$notrace'(nospyall_). 132 133nospyall_ :- 134 prolog:debug_control_hook(nospyall), 135 fail. 136nospyall_ :- 137 spy_point(Head), 138 '$nospy'(Head), 139 fail. 140nospyall_. 141 142pi_to_head(M:PI, M:Head) :- 143 !, 144 pi_to_head(PI, Head). 145pi_to_head(Name/Arity, Head) :- 146 functor(Head, Name, Arity).
152debugging :- 153 '$notrace'(debugging_). 154 155debugging_ :- 156 prolog:debug_control_hook(debugging), 157 !. 158debugging_ :- 159 ( current_prolog_flag(debug, true) 160 -> print_message(informational, debugging(on)), 161 findall(H, spy_point(H), SpyPoints), 162 print_message(informational, spying(SpyPoints)) 163 ; print_message(informational, debugging(off)) 164 ), 165 trapping, 166 forall(debugging_hook, true). 167 168spy_point(Module:Head) :- 169 current_predicate(_, Module:Head), 170 '$get_predicate_attribute'(Module:Head, spy, 1), 171 \+ predicate_property(Module:Head, imported_from(_)).
forall(debugging_hook, true)
and
that may be used to extend the information printed from other
debugging libraries.179:- multifile debugging_hook/0. 180 181 182 /******************************* 183 * EXCEPTIONS * 184 *******************************/
error(Formal, Context)
exceptions that unify. The
tracer is started when a matching exception is raised. This
predicate enables debug mode using debug/0 to get more context
about the exception. Even with debug mode disabled exceptions are
still trapped and thus one may call nodebug/0 to run in normal mode
after installing a trap. Exceptions are trapped in any thread. Debug
mode is only enabled in the calling thread. To enable debug mode in
all threads use tdebug/0.
Calling debugging/0 lists the enabled traps. The predicate notrap/1 removes matching (unifying) traps.
In many cases debugging an exception that is caught is as simple as below (assuming run/0 starts your program).
?- trap(_). ?- run.
213:- dynamic 214 exception/4, % Name, Term, NotCaught, Caught 215 installed/1. % ClauseRef 216 217trap(Error) :- 218 '$notrace'(trap_(Error)). 219 220trap_(Error) :- 221 gensym(ex, Rule), 222 asserta(exception(Rule, error(Error, _), true, true)), 223 print_message(informational, trap(Rule, error(Error, _), true, true)), 224 install_exception_hook, 225 debug. 226 227notrap(Error) :- 228 '$notrace'(notrap_(Error)). 229 230notrap_(Error) :- 231 Exception = error(Error, _), 232 findall(exception(Name, Exception, NotCaught, Caught), 233 retract(exception(Name, error(Error, _), Caught, NotCaught)), 234 Trapping), 235 print_message(informational, notrap(Trapping)). 236 237 238trapping :- 239 findall(exception(Name, Term, NotCaught, Caught), 240 exception(Name, Term, NotCaught, Caught), 241 Trapping), 242 print_message(information, trapping(Trapping)). 243 244:- dynamic prolog:prolog_exception_hook/5. 245:- multifile prolog:prolog_exception_hook/5.
251:- public exception_hook/5. 252 253exception_hook(Ex, Ex, _Frame, Catcher, _Debug) :- 254 thread_self(Me), 255 thread_property(Me, debug(true)), 256 broadcast(debug(exception(Ex))), 257 exception(_, Ex, NotCaught, Caught), 258 !, 259 ( Caught == true 260 -> true 261 ; Catcher == none, 262 NotCaught == true 263 ), 264 trace, fail.
271install_exception_hook :- 272 installed(Ref), 273 ( nth_clause(_, I, Ref) 274 -> I == 1, ! % Ok, we are the first 275 ; retractall(installed(Ref)), 276 erase(Ref), % Someone before us! 277 fail 278 ). 279install_exception_hook :- 280 asserta((prolog:prolog_exception_hook(Ex, Out, Frame, Catcher, Debug) :- 281 exception_hook(Ex, Out, Frame, Catcher, Debug)), Ref), 282 assert(installed(Ref)). 283 284 285 /******************************* 286 * MESSAGES * 287 *******************************/ 288 289:- multifile 290 prolog:message//1. 291 292prologmessage(trapping([])) --> 293 [ 'No exception traps'-[] ]. 294prologmessage(trapping(Trapping)) --> 295 [ 'Exception traps on'-[], nl ], 296 trapping(Trapping). 297prologmessage(trap(_Rule, Error, _Caught, _NotCaught)) --> 298 [ 'Installed trap for exception '-[] ], 299 exception(Error), 300 [ nl ]. 301prologmessage(notrap([])) --> 302 [ 'No matching traps'-[] ]. 303prologmessage(notrap(Trapping)) --> 304 [ 'Removed traps from exceptions'-[], nl ], 305 trapping(Trapping). 306 307trapping([]) --> []. 308trapping([exception(_Rule, Error, _Caught, _NotCaught)|T]) --> 309 [ ' '-[] ], 310 exception(Error), 311 [ nl ], 312 trapping(T). 313 314exception(Term) --> 315 { copy_term(Term, T2), 316 numbervars(T2, 0, _, [singletons(true)]) 317 }, 318 [ '~p'-[T2] ]
User level debugging tools
This library provides tools to control the Prolog debuggers. Traditionally this code was built-in. Because these tools are only required in (interactive) debugging sessions they have been moved into the library. */