mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Estimated hours taken: 10 Branches: main Split the existing browser library into two libraries, by making the program_representation module into its own library. This is useful because the compiler refers to program_representation.m, whose code thus needs to be linked into compiler executables even if the compiler isn't compiled with debugging enabled. By creating a new library for this module, we avoid any chance of the linker dragging in the rest of the modules in the browser library. (This is a problem with an upcoming diff.). The name of the new library is "mdbcomp", because the intention is that it contain code that is shared between the debugger and the compiler. This means mostly the definitions of data structures that the compiler generates for the debugger, and the predicates that operate on them. Mmake.common.in: Allow MDB_COMP_ as a prefix for symbol names in the browser directory. Mmake.workspace: Add a make variable holding for the name of the new library, and add the name to the relevant lists of libraries. Avoid duplicating the lists of filenames that need to be updated when adding new libraries or changing their names. Mmakefile: Use make variables to refer to library names. browser/mdbcomp.m: browser/mer_mdbcomp.m: Add these files as the top modules of the new library. browser/program_representation.m: Make program_representation.m a submodule of mdbcomp, not mdb. browser/program_representation.m: browser/browser_info.m: Move a predicate from program_representation.m to browser_info.m to avoid the mdbcomp library depend on the browser library, since this would negate the point of the exercise. browser/mdb.m: Delete program_representation.m from the list of submodules. browser/Mmakefile: Update this file to handle the new module. browser/Mercury.options: Mention the new module. browser/*.m: Update the lists of imported modules. Import only one browser module per line. compiler/notes/overall_design.html: Document the new library. compiler/compile_target_code.m: Add the mdbcomp library to the list of libraries we need to link with. compiler/prog_rep.m: trace/mercury_trace_internal.c: Import program_representation.m by its new name. scripts/c2init.in: Centralize knowledge about which files need to be updated when the list of libraries changes here. scripts/c2init.in: scripts/ml.in: tools/binary: tools/binary_step: tools/bootcheck: tools/linear: tools/lml: Update the list of libraries programs are linked with.
600 lines
19 KiB
Mathematica
600 lines
19 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2003 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: declarative_debugger.m
|
|
% Author: Mark Brown
|
|
%
|
|
% This module has two main purposes:
|
|
% - to define the interface between the front and back ends of
|
|
% a Mercury declarative debugger, and
|
|
% - to implement a front end.
|
|
%
|
|
% The interface is defined by a procedure that can be called from
|
|
% the back end to perform diagnosis, and a typeclass which represents
|
|
% a declarative view of execution used by the front end.
|
|
%
|
|
% The front end implemented in this module analyses the EDT it is
|
|
% passed to diagnose a bug. It does this by a simple top-down search.
|
|
%
|
|
% Because Mercury modules are able to be compiled with different levels
|
|
% of tracing, the trace sequences generated by the back end, and passed
|
|
% to the front end as "annotated traces", can include or exclude certain
|
|
% types of events. This front end is able to cope with some variation in
|
|
% the trace events produced, but there are some basic requirements on
|
|
% trace sequences which the back end must meet:
|
|
%
|
|
% 1) if there are any events from a certain class (e.g. interface
|
|
% events, negation events, disj events) then we require all events
|
|
% of that class;
|
|
%
|
|
% 2) if there are any disj events, we require all negation events
|
|
% and if-then-else events.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module mdb__declarative_debugger.
|
|
|
|
:- interface.
|
|
|
|
:- import_module mdb__declarative_execution.
|
|
:- import_module mdb__io_action.
|
|
:- import_module mdbcomp__program_representation.
|
|
|
|
:- import_module io, bool, list, std_util, string.
|
|
|
|
% This type represents the possible truth values for nodes
|
|
% in the EDT.
|
|
%
|
|
:- type decl_truth == bool.
|
|
|
|
% This type represents the possible responses to being
|
|
% asked to confirm that a node is a bug.
|
|
%
|
|
:- type decl_confirmation
|
|
---> confirm_bug
|
|
; overrule_bug
|
|
; abort_diagnosis.
|
|
|
|
% This type represents the bugs which can be diagnosed.
|
|
% The parameter of the constructor is the type of EDT nodes.
|
|
%
|
|
:- type decl_bug
|
|
% An EDT whose root node is incorrect,
|
|
% but whose children are all correct.
|
|
%
|
|
---> e_bug(decl_e_bug)
|
|
|
|
% An EDT whose root node is incorrect, and
|
|
% which has no incorrect children but at
|
|
% least one inadmissible one.
|
|
%
|
|
; i_bug(decl_i_bug).
|
|
|
|
:- type decl_e_bug
|
|
---> incorrect_contour(
|
|
final_decl_atom,% The head of the clause, in its
|
|
% final state of instantiation.
|
|
decl_contour, % The path taken through the body.
|
|
event_number % The exit event.
|
|
)
|
|
; partially_uncovered_atom(
|
|
init_decl_atom, % The called atom, in its initial
|
|
% state.
|
|
event_number % The fail event.
|
|
)
|
|
; unhandled_exception(
|
|
init_decl_atom, % The called atom, in its initial
|
|
% state.
|
|
decl_exception, % The exception thrown.
|
|
event_number % The excp event.
|
|
).
|
|
|
|
:- type decl_i_bug
|
|
---> inadmissible_call(
|
|
init_decl_atom, % The parent atom, in its initial
|
|
% state.
|
|
decl_position, % The location of the call in the
|
|
% parent's body.
|
|
init_decl_atom, % The inadmissible child, in its
|
|
% initial state.
|
|
event_number % The call event.
|
|
).
|
|
|
|
% XXX not yet implemented.
|
|
%
|
|
:- type decl_contour == unit.
|
|
:- type decl_position == unit.
|
|
|
|
% Values of the following two types represent questions from the
|
|
% analyser to the oracle about some aspect of program behaviour,
|
|
% and responses from the oracle, respectively. In both cases the
|
|
% type parameter is for the type of EDT nodes -- each question and
|
|
% answer keeps a reference to the node which generated it, so that
|
|
% the analyser is able to figure out what to do when the answer
|
|
% arrives back from the oracle.
|
|
%
|
|
:- type decl_question(T)
|
|
% The node is a suspected wrong answer. The first
|
|
% argument is the EDT node the question came from.
|
|
% The second argument is the atom in its final
|
|
% state of instantiatedness (ie. at the EXIT event).
|
|
%
|
|
---> wrong_answer(T, final_decl_atom)
|
|
|
|
% The node is a suspected missing answer. The
|
|
% first argument is the EDT node the question came
|
|
% from. The second argument is the atom in its
|
|
% initial state of instantiatedness (ie. at the
|
|
% CALL event), and the third argument is the list
|
|
% of solutions.
|
|
%
|
|
; missing_answer(T, init_decl_atom, list(final_decl_atom))
|
|
|
|
% The node is a possibly unexpected exception.
|
|
% The first argument is the EDT node the question
|
|
% came from. The second argument is the atom in
|
|
% its initial state of instantiation, and the third
|
|
% argument is the exception thrown.
|
|
%
|
|
; unexpected_exception(T, init_decl_atom, decl_exception).
|
|
|
|
:- type decl_answer(T)
|
|
% The oracle knows the truth value of this node.
|
|
%
|
|
---> truth_value(T, decl_truth)
|
|
|
|
% The oracle does not say anything about the truth
|
|
% value, but is suspicious of the subterm at the
|
|
% given term_path and arg_pos.
|
|
%
|
|
; suspicious_subterm(T, arg_pos, term_path).
|
|
|
|
% The evidence that a certain node is a bug. This consists of the
|
|
% smallest set of questions whose answers are sufficient to
|
|
% diagnose that bug.
|
|
%
|
|
:- type decl_evidence(T) == list(decl_question(T)).
|
|
|
|
% Extract the EDT node from a question.
|
|
%
|
|
:- func get_decl_question_node(decl_question(T)) = T.
|
|
|
|
:- type some_decl_atom
|
|
---> init(init_decl_atom)
|
|
; final(final_decl_atom).
|
|
|
|
:- type init_decl_atom
|
|
---> init_decl_atom(
|
|
init_atom :: trace_atom
|
|
).
|
|
|
|
:- type final_decl_atom
|
|
---> final_decl_atom(
|
|
final_atom :: trace_atom,
|
|
final_io_actions :: list(io_action)
|
|
).
|
|
|
|
:- type decl_exception == univ.
|
|
|
|
% The diagnoser eventually responds with a value of this type
|
|
% after it is called.
|
|
%
|
|
:- type diagnoser_response
|
|
|
|
% There was a bug found and confirmed. The
|
|
% event number is for a call port (inadmissible
|
|
% call), an exit port (incorrect contour),
|
|
% a fail port (partially uncovered atom),
|
|
% or an exception port (unhandled exception).
|
|
%
|
|
---> bug_found(event_number)
|
|
|
|
% There was another symptom of incorrect behaviour
|
|
% found; this symptom will be closer, in a sense,
|
|
% to the location of a bug.
|
|
%
|
|
; symptom_found(event_number)
|
|
|
|
% There was no symptom found, or the diagnoser
|
|
% aborted before finding a bug.
|
|
%
|
|
; no_bug_found
|
|
|
|
% The analyser requires the back end to reproduce
|
|
% part of the annotated trace, with a greater
|
|
% depth bound. The event number and sequence
|
|
% number are for the final event required (the
|
|
% first event required is the call event with
|
|
% the same sequence number).
|
|
%
|
|
; require_subtree(event_number, sequence_number).
|
|
|
|
:- type diagnoser_state(R).
|
|
|
|
:- pred diagnoser_state_init(io_action_map::in, io__input_stream::in,
|
|
io__output_stream::in, diagnoser_state(R)::out) is det.
|
|
|
|
:- pred diagnosis(S::in, R::in, int::in, int::in, int::in,
|
|
diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
:- pred unravel_decl_atom(some_decl_atom::in, trace_atom::out,
|
|
list(io_action)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The diagnoser generates exceptions of the following type.
|
|
%
|
|
:- type diagnoser_exception
|
|
---> internal_error(
|
|
string, % predicate/function name
|
|
string % error message
|
|
)
|
|
; io_error(
|
|
string, % predicate/function name
|
|
string % error message
|
|
)
|
|
; unimplemented_feature(
|
|
string % feature that is NYI
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module mdb__declarative_analyser.
|
|
:- import_module mdb__declarative_oracle.
|
|
:- import_module mdb__declarative_tree.
|
|
|
|
:- import_module exception, int, map.
|
|
|
|
unravel_decl_atom(DeclAtom, TraceAtom, IoActions) :-
|
|
(
|
|
DeclAtom = init(init_decl_atom(TraceAtom)),
|
|
IoActions = []
|
|
;
|
|
DeclAtom = final(final_decl_atom(TraceAtom, IoActions))
|
|
).
|
|
|
|
get_decl_question_node(wrong_answer(Node, _)) = Node.
|
|
get_decl_question_node(missing_answer(Node, _, _)) = Node.
|
|
get_decl_question_node(unexpected_exception(Node, _, _)) = Node.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type diagnoser_state(R)
|
|
---> diagnoser(
|
|
analyser_state :: analyser_state(edt_node(R)),
|
|
oracle_state :: oracle_state
|
|
).
|
|
|
|
:- pred diagnoser_get_analyser(diagnoser_state(R),
|
|
analyser_state(edt_node(R))).
|
|
:- mode diagnoser_get_analyser(in, out) is det.
|
|
|
|
diagnoser_get_analyser(diagnoser(Analyser, _), Analyser).
|
|
|
|
:- pred diagnoser_set_analyser(diagnoser_state(R), analyser_state(edt_node(R)),
|
|
diagnoser_state(R)).
|
|
:- mode diagnoser_set_analyser(in, in, out) is det.
|
|
|
|
diagnoser_set_analyser(diagnoser(_, B), A, diagnoser(A, B)).
|
|
|
|
:- pred diagnoser_get_oracle(diagnoser_state(R), oracle_state).
|
|
:- mode diagnoser_get_oracle(in, out) is det.
|
|
|
|
diagnoser_get_oracle(diagnoser(_, Oracle), Oracle).
|
|
|
|
:- pred diagnoser_set_oracle(diagnoser_state(R), oracle_state,
|
|
diagnoser_state(R)).
|
|
:- mode diagnoser_set_oracle(in, in, out) is det.
|
|
|
|
diagnoser_set_oracle(diagnoser(A, _), B, diagnoser(A, B)).
|
|
|
|
diagnoser_state_init(IoActionMap, InStr, OutStr, Diagnoser) :-
|
|
analyser_state_init(IoActionMap, Analyser),
|
|
oracle_state_init(InStr, OutStr, Oracle),
|
|
Diagnoser = diagnoser(Analyser, Oracle).
|
|
|
|
diagnosis(Store, NodeId, UseOldIoActionMap, IoActionStart, IoActionEnd,
|
|
Response, Diagnoser0, Diagnoser) -->
|
|
( { UseOldIoActionMap > 0 } ->
|
|
{ Diagnoser1 = Diagnoser0 }
|
|
;
|
|
make_io_action_map(IoActionStart, IoActionEnd, IoActionMap),
|
|
{ Analyser0 = Diagnoser0 ^ analyser_state },
|
|
{ analyser_state_replace_io_map(IoActionMap,
|
|
Analyser0, Analyser1) },
|
|
{ Diagnoser1 = Diagnoser0 ^ analyser_state := Analyser1 }
|
|
),
|
|
try_io(diagnosis_2(Store, NodeId, Diagnoser1), Result),
|
|
(
|
|
{ Result = succeeded({Response, Diagnoser}) }
|
|
;
|
|
{ Result = exception(UnivException) },
|
|
(
|
|
{ univ_to_type(UnivException, DiagnoserException) }
|
|
->
|
|
handle_diagnoser_exception(DiagnoserException,
|
|
Response, Diagnoser1, Diagnoser)
|
|
;
|
|
{ rethrow(Result) }
|
|
)
|
|
).
|
|
|
|
:- pred diagnosis_2(S::in, R::in, diagnoser_state(R)::in,
|
|
{diagnoser_response, diagnoser_state(R)}::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
diagnosis_2(Store, NodeId, Diagnoser0, {Response, Diagnoser}) -->
|
|
{ Analyser0 = Diagnoser0 ^ analyser_state },
|
|
{ start_analysis(wrap(Store), dynamic(NodeId), AnalyserResponse,
|
|
Analyser0, Analyser) },
|
|
{ diagnoser_set_analyser(Diagnoser0, Analyser, Diagnoser1) },
|
|
{ debug_analyser_state(Analyser, MaybeOrigin) },
|
|
handle_analyser_response(Store, AnalyserResponse, MaybeOrigin,
|
|
Response, Diagnoser1, Diagnoser).
|
|
|
|
:- pred handle_analyser_response(S::in, analyser_response(edt_node(R))::in,
|
|
maybe(subterm_origin(edt_node(R)))::in, diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
handle_analyser_response(_, no_suspects, _, no_bug_found, D, D) -->
|
|
io__write_string("No bug found.\n").
|
|
|
|
handle_analyser_response(Store, bug_found(Bug, Evidence), _, Response,
|
|
Diagnoser0, Diagnoser) -->
|
|
|
|
confirm_bug(Store, Bug, Evidence, Response, Diagnoser0, Diagnoser).
|
|
|
|
handle_analyser_response(Store, oracle_queries(Queries), MaybeOrigin, Response,
|
|
Diagnoser0, Diagnoser) -->
|
|
{ diagnoser_get_oracle(Diagnoser0, Oracle0) },
|
|
debug_origin(Flag),
|
|
(
|
|
{ MaybeOrigin = yes(Origin) },
|
|
{ Flag > 0 }
|
|
->
|
|
io__write_string("Origin: "),
|
|
write_origin(wrap(Store), Origin),
|
|
io__nl
|
|
;
|
|
[]
|
|
),
|
|
query_oracle(Queries, OracleResponse, Oracle0, Oracle),
|
|
{ diagnoser_set_oracle(Diagnoser0, Oracle, Diagnoser1) },
|
|
handle_oracle_response(Store, OracleResponse, Response, Diagnoser1,
|
|
Diagnoser).
|
|
|
|
handle_analyser_response(Store, require_explicit(Tree), _, Response,
|
|
Diagnoser, Diagnoser) -->
|
|
{
|
|
edt_subtree_details(Store, Tree, Event, Seqno),
|
|
Response = require_subtree(Event, Seqno)
|
|
}.
|
|
|
|
:- pred handle_oracle_response(S::in, oracle_response(edt_node(R))::in,
|
|
diagnoser_response::out,
|
|
diagnoser_state(R)::in, diagnoser_state(R)::out,
|
|
io__state::di, io__state::uo) is cc_multi <= annotated_trace(S, R).
|
|
|
|
handle_oracle_response(Store, oracle_answers(Answers), Response, Diagnoser0,
|
|
Diagnoser) -->
|
|
{ diagnoser_get_analyser(Diagnoser0, Analyser0) },
|
|
{ continue_analysis(wrap(Store), Answers, AnalyserResponse,
|
|
Analyser0, Analyser) },
|
|
{ diagnoser_set_analyser(Diagnoser0, Analyser, Diagnoser1) },
|
|
{ debug_analyser_state(Analyser, MaybeOrigin) },
|
|
handle_analyser_response(Store, AnalyserResponse, MaybeOrigin,
|
|
Response, Diagnoser1, Diagnoser).
|
|
|
|
handle_oracle_response(_, no_oracle_answers, no_bug_found, D, D) -->
|
|
[].
|
|
|
|
handle_oracle_response(Store, exit_diagnosis(Node), Response, D, D) -->
|
|
{ edt_subtree_details(Store, Node, Event, _) },
|
|
{ Response = symptom_found(Event) }.
|
|
|
|
handle_oracle_response(_, abort_diagnosis, no_bug_found, D, D) -->
|
|
io__write_string("Diagnosis aborted.\n").
|
|
|
|
:- pred confirm_bug(S::in, decl_bug::in, decl_evidence(T)::in,
|
|
diagnoser_response::out, diagnoser_state(R)::in,
|
|
diagnoser_state(R)::out, io__state::di, io__state::uo) is cc_multi
|
|
<= annotated_trace(S, R).
|
|
|
|
confirm_bug(Store, Bug, Evidence, Response, Diagnoser0, Diagnoser) -->
|
|
{ diagnoser_get_oracle(Diagnoser0, Oracle0) },
|
|
oracle_confirm_bug(Bug, Evidence, Confirmation, Oracle0, Oracle),
|
|
{ diagnoser_set_oracle(Diagnoser0, Oracle, Diagnoser1) },
|
|
(
|
|
{ Confirmation = confirm_bug },
|
|
{ decl_bug_get_event_number(Bug, Event) },
|
|
{ Response = bug_found(Event) },
|
|
{ Diagnoser = Diagnoser1 }
|
|
;
|
|
{ Confirmation = overrule_bug },
|
|
overrule_bug(Store, Response, Diagnoser1, Diagnoser)
|
|
;
|
|
{ Confirmation = abort_diagnosis },
|
|
{ Response = no_bug_found },
|
|
{ Diagnoser = Diagnoser1 }
|
|
).
|
|
|
|
:- pred overrule_bug(S::in, diagnoser_response::out, diagnoser_state(R)::in,
|
|
diagnoser_state(R)::out, io__state::di, io__state::uo) is cc_multi
|
|
<= annotated_trace(S, R).
|
|
|
|
overrule_bug(Store, Response, Diagnoser0, Diagnoser) -->
|
|
{ Analyser0 = Diagnoser0 ^ analyser_state },
|
|
{ revise_analysis(wrap(Store), AnalyserResponse, Analyser0, Analyser) },
|
|
{ Diagnoser1 = Diagnoser0 ^ analyser_state := Analyser },
|
|
{ debug_analyser_state(Analyser, MaybeOrigin) },
|
|
handle_analyser_response(Store, AnalyserResponse, MaybeOrigin,
|
|
Response, Diagnoser1, Diagnoser).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Export a monomorphic version of diagnosis_state_init/4, to
|
|
% make it easier to call from C code.
|
|
%
|
|
:- pred diagnoser_state_init_store(io__input_stream, io__output_stream,
|
|
diagnoser_state(trace_node_id)).
|
|
:- mode diagnoser_state_init_store(in, in, out) is det.
|
|
|
|
:- pragma export(diagnoser_state_init_store(in, in, out),
|
|
"MR_DD_decl_diagnosis_state_init").
|
|
|
|
diagnoser_state_init_store(InStr, OutStr, Diagnoser) :-
|
|
diagnoser_state_init(map__init, InStr, OutStr, Diagnoser).
|
|
|
|
% Export a monomorphic version of diagnosis/10, to make it
|
|
% easier to call from C code.
|
|
%
|
|
:- pred diagnosis_store(trace_node_store::in, trace_node_id::in,
|
|
int::in, int::in, int::in, diagnoser_response::out,
|
|
diagnoser_state(trace_node_id)::in,
|
|
diagnoser_state(trace_node_id)::out, io__state::di, io__state::uo)
|
|
is cc_multi.
|
|
|
|
:- pragma export(diagnosis_store(in, in, in, in, in, out, in, out, di, uo),
|
|
"MR_DD_decl_diagnosis").
|
|
|
|
diagnosis_store(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
|
|
Response, State0, State) -->
|
|
diagnosis(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
|
|
Response, State0, State).
|
|
|
|
% Export some predicates so that C code can interpret the
|
|
% diagnoser response.
|
|
%
|
|
:- pred diagnoser_bug_found(diagnoser_response, event_number).
|
|
:- mode diagnoser_bug_found(in, out) is semidet.
|
|
|
|
:- pragma export(diagnoser_bug_found(in, out), "MR_DD_diagnoser_bug_found").
|
|
|
|
diagnoser_bug_found(bug_found(Event), Event).
|
|
|
|
:- pred diagnoser_symptom_found(diagnoser_response, event_number).
|
|
:- mode diagnoser_symptom_found(in, out) is semidet.
|
|
|
|
:- pragma export(diagnoser_symptom_found(in, out),
|
|
"MR_DD_diagnoser_symptom_found").
|
|
|
|
diagnoser_symptom_found(symptom_found(Event), Event).
|
|
|
|
:- pred diagnoser_no_bug_found(diagnoser_response).
|
|
:- mode diagnoser_no_bug_found(in) is semidet.
|
|
|
|
:- pragma export(diagnoser_no_bug_found(in), "MR_DD_diagnoser_no_bug_found").
|
|
|
|
diagnoser_no_bug_found(no_bug_found).
|
|
|
|
:- pred diagnoser_require_subtree(diagnoser_response, event_number,
|
|
sequence_number).
|
|
:- mode diagnoser_require_subtree(in, out, out) is semidet.
|
|
|
|
:- pragma export(diagnoser_require_subtree(in, out, out),
|
|
"MR_DD_diagnoser_require_subtree").
|
|
|
|
diagnoser_require_subtree(require_subtree(Event, SeqNo), Event, SeqNo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred handle_diagnoser_exception(diagnoser_exception::in,
|
|
diagnoser_response::out, diagnoser_state(R)::in,
|
|
diagnoser_state(R)::out, io__state::di, io__state::uo) is det.
|
|
|
|
handle_diagnoser_exception(internal_error(Loc, Msg), Response, D, D) -->
|
|
io__stderr_stream(StdErr),
|
|
io__write_strings(StdErr, [
|
|
"An internal error has occurred; diagnosis will be aborted. Debugging\n",
|
|
"message follows:\n",
|
|
Loc, ": ", Msg, "\n",
|
|
"Please report bugs to mercury-bugs@cs.mu.oz.au.\n"]),
|
|
{ Response = no_bug_found }.
|
|
|
|
handle_diagnoser_exception(io_error(Loc, Msg), Response, D, D) -->
|
|
io__stderr_stream(StdErr),
|
|
io__write_strings(StdErr, [
|
|
"I/O error: ", Loc, ": ", Msg, ".\n",
|
|
"Diagnosis will be aborted.\n"]),
|
|
{ Response = no_bug_found }.
|
|
|
|
handle_diagnoser_exception(unimplemented_feature(Feature), Response, D, D) -->
|
|
io__write_strings([
|
|
"Sorry, the diagnosis cannot continue because it requires support for\n",
|
|
"the following: ", Feature, ".\n",
|
|
"The debugger is a work in progress, and this is not supported in the\n",
|
|
"current version.\n"]),
|
|
{ Response = no_bug_found }.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred decl_bug_get_event_number(decl_bug, event_number).
|
|
:- mode decl_bug_get_event_number(in, out) is det.
|
|
|
|
decl_bug_get_event_number(e_bug(EBug), Event) :-
|
|
(
|
|
EBug = incorrect_contour(_, _, Event)
|
|
;
|
|
EBug = partially_uncovered_atom(_, Event)
|
|
;
|
|
EBug = unhandled_exception(_, _, Event)
|
|
).
|
|
decl_bug_get_event_number(i_bug(IBug), Event) :-
|
|
IBug = inadmissible_call(_, _, _, Event).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred write_origin(wrap(S)::in, subterm_origin(edt_node(R))::in,
|
|
io__state::di, io__state::uo) is det <= annotated_trace(S, R).
|
|
|
|
write_origin(wrap(Store), Origin) -->
|
|
( { Origin = output(dynamic(NodeId), ArgPos, TermPath) } ->
|
|
{ exit_node_from_id(Store, NodeId, ExitNode) },
|
|
{ ProcName = ExitNode ^ exit_atom ^ proc_name },
|
|
io__write_string("output("),
|
|
io__write_string(ProcName),
|
|
io__write_string(", "),
|
|
io__write(ArgPos),
|
|
io__write_string(", "),
|
|
io__write(TermPath),
|
|
io__write_string(")")
|
|
;
|
|
io__write(Origin)
|
|
).
|
|
|
|
:- pragma foreign_code("C",
|
|
"
|
|
|
|
/*
|
|
** The declarative debugger will print diagnostic information about the origins
|
|
** computed by dependency tracking if this flag has a positive value.
|
|
*/
|
|
|
|
int MR_DD_debug_origin = 0;
|
|
|
|
").
|
|
|
|
:- pragma foreign_decl("C",
|
|
"
|
|
extern int MR_DD_debug_origin;
|
|
").
|
|
|
|
:- pred debug_origin(int::out, io__state::di, io__state::uo) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
debug_origin(Flag::out, IO0::di, IO::uo),
|
|
[will_not_call_mercury, promise_pure, tabled_for_io],
|
|
"
|
|
Flag = MR_DD_debug_origin;
|
|
IO = IO0;
|
|
").
|
|
debug_origin(_) -->
|
|
{ private_builtin__sorry("declarative_debugger.debug_origin") }.
|