[m-rev.] for review: add --resume dd option

Ian MacLarty maclarty at cs.mu.OZ.AU
Thu Feb 24 13:02:38 AEDT 2005


For review by anyone.

Estimated hours taken: 25
Branches: main

Add --resume option to `dd' command.  This resumes the previous declarative
debugging session and allows the user to switch between the procedural and
declarative debuggers freely.

browser/declarative_analyser.m
	Add analysis_type type which is used to tell the analyser whether
	it must start a new session or resume a previous session.

browser/declarative_debugger.m
	Add two versions of the exported diagnosis predicate: one to 
	resume a previous session and one to start a new session.

browser/declarative_user.m
	Print usage message to the correct output stream.

runtime/mercury_stack_trace.c
runtime/mercury_stack_trace.h
	Add a function to find the first call on the stack whose event
	number is less than or equal to a given event number or whose
	call sequence number is less than or equal to a given call sequence
	number.  
	
	Since this new function uses some code very similar to existing
	code in the function that prints the stack, seperate this code into
	a new function called MR_call_details_are_valid.

trace/mercury_trace_declarative.c
trace/mercury_trace_declarative.h
	Previously it could be safely assumed that the current event would
	be somewhere inside the materialized portion of the annotated trace,
	so it was sufficient to record the topmost node of the annotated
	trace and retry to there whenever we needed to build a new subtree
	(and to the topmost node plus some extra for a supertree).  
	
	Now, however, the user may go to any event in the program before
	resuming the previous dd session.  We could just retry to the call
	event for main/2, but this would be far from optimal, especially if the
	user is debugging code deep down in the program's call tree.  
	
	Instead we retry to the first call on the stack whose event number
	is less than or equal to the call event number of the node we
	want to build a subtree for and then start forward execution from 
	there.  When building a supertree we retry to the first call on the
	stack whose event number is less than or equal to the event number of
	the call at the top of the currently materialized portion of the
	annotated trace.  Then when we get to the call at the top of the
	currently materialized portion of the annotated trace through forward
	execution, we do a retry to the desired depth and start building the
	new supertree.

	Desribe the function of some of the global variables in more detail.
	
	Remove the global MR_edt_topmost_call_depth since it is no longer 
	needed.

	Fix an inconsistency where the depth limit was being set to
	MR_edt_depth_step_size when starting a dd session, but to
	MR_edt_depth_step_size + 1 when building an additional portion of the
	annotated trace.
	
tests/debugger/declarative/Mmakefile
tests/debugger/declarative/resume.exp
tests/debugger/declarative/resume.inp
tests/debugger/declarative/resume.m
	Test the --resume option.  Specifically test the creation of a 
	supertree and subtree from a resumed session where the user
	has gone to an event before and after the materialized portion
	of the annotated trace.

trace/mercury_trace_internal.c
	Handle the --resume option.

Index: browser/declarative_analyser.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_analyser.m,v
retrieving revision 1.19
diff -u -r1.19 declarative_analyser.m
--- browser/declarative_analyser.m	13 Jan 2005 11:14:47 -0000	1.19
+++ browser/declarative_analyser.m	24 Feb 2005 00:28:48 -0000
@@ -72,13 +72,27 @@
 :- pred analyser_state_replace_io_map(io_action_map::in,
 	analyser_state(T)::in, analyser_state(T)::out) is det.
 
+:- type analysis_type(T)
+			% Use the given tree to do analysis.  The tree will be
+			% a new explicitly generated portion of the annotated
+			% trace.  start_or_resume_analysis should be called
+			% with this type of analysis when a new declarative
+			% debugging session has been started or a requested
+			% subtree or supertree has been generated.
+	--->	new_tree(T)
+			% Continue the previous analysis.  This will happen
+			% when the user suspends a declarative debugging
+			% session with a `pd' or `abort' command and now wants
+			% to continue the suspended session.
+	;	resume_previous.
+
 	% Perform analysis on the given EDT, which may be a new tree
 	% to diagnose, or a sub-tree that was required to be made
 	% explicit.
 	%
-:- pred start_or_resume_analysis(S::in, T::in, analyser_response(T)::out,
-	analyser_state(T)::in, analyser_state(T)::out) is det
-	<= mercury_edt(S, T).
+:- pred start_or_resume_analysis(S::in, analysis_type(T)::in,
+	analyser_response(T)::out, analyser_state(T)::in,
+	analyser_state(T)::out) is det <= mercury_edt(S, T).
 
 	% Continue analysis after the oracle has responded with an
 	% answer.
@@ -270,38 +284,44 @@
 
 debug_analyser_state(Analyser, Analyser ^ debug_origin).
 
-start_or_resume_analysis(Store, Node, Response, !Analyser) :-
-	MaybeRequireExplicit = !.Analyser ^ require_explicit,
+start_or_resume_analysis(Store, AnalysisType, Response, !Analyser) :-
 	(
-		MaybeRequireExplicit = yes(TreeType),
-		SearchSpace0 = !.Analyser ^ search_space,
+		AnalysisType = new_tree(Node),
+		MaybeRequireExplicit = !.Analyser ^ require_explicit,
 		(
-			TreeType = explicit_supertree,
-			incorporate_explicit_supertree(Store, Node, 
-				SearchSpace0, SearchSpace)
+			MaybeRequireExplicit = yes(TreeType),
+			SearchSpace0 = !.Analyser ^ search_space,
+			(
+				TreeType = explicit_supertree,
+				incorporate_explicit_supertree(Store, Node, 
+					SearchSpace0, SearchSpace)
+			;
+				TreeType = explicit_subtree(SuspectId),
+				incorporate_explicit_subtree(SuspectId, Node, 
+					SearchSpace0, SearchSpace)
+			),
+			!:Analyser = !.Analyser ^ search_space := SearchSpace,
+			!:Analyser = !.Analyser ^ require_explicit := no,
+			decide_analyser_response(Store, Response, !Analyser)
 		;
-			TreeType = explicit_subtree(SuspectId),
-			incorporate_explicit_subtree(SuspectId, Node, 
-				SearchSpace0, SearchSpace)
-		),
-		!:Analyser = !.Analyser ^ search_space := SearchSpace,
-		!:Analyser = !.Analyser ^ require_explicit := no,
-		decide_analyser_response(Store, Response, !Analyser)
+			MaybeRequireExplicit = no,
+			%
+			% An explicit subtree was not requested, so this is the 
+			% start of a new declarative debugging session.
+			%
+			reset_analyser(!Analyser),
+			initialise_search_space(Store, Node, SearchSpace),
+			!:Analyser = !.Analyser ^ search_space := SearchSpace,
+			topmost_det(SearchSpace, TopMostId),
+			!:Analyser = !.Analyser ^ last_search_question := 
+				yes(TopMostId),
+			edt_question(!.Analyser ^ io_action_map, Store, Node, 
+				Question),
+			Response = revise(Question)
+		)
 	;
-		MaybeRequireExplicit = no,
-		%
-		% An explicit subtree was not requested, so this is the 
-		% start of a new declarative debugging session.
-		%
-		reset_analyser(!Analyser),
-		initialise_search_space(Store, Node, SearchSpace),
-		!:Analyser = !.Analyser ^ search_space := SearchSpace,
-		topmost_det(SearchSpace, TopMostId),
-		!:Analyser = !.Analyser ^ last_search_question := 
-			yes(TopMostId),
-		edt_question(!.Analyser ^ io_action_map, Store, Node, 
-			Question),
-		Response = revise(Question)
+		AnalysisType = resume_previous,
+		decide_analyser_response(Store, Response, !Analyser)
 	).
 
 continue_analysis(Store, Answer, Response, !Analyser) :-
Index: browser/declarative_debugger.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_debugger.m,v
retrieving revision 1.51
diff -u -r1.51 declarative_debugger.m
--- browser/declarative_debugger.m	1 Feb 2005 07:11:26 -0000	1.51
+++ browser/declarative_debugger.m	22 Feb 2005 22:24:53 -0000
@@ -58,7 +58,9 @@
 :- interface.
 
 :- import_module mdb.browser_info.
+:- import_module mdb.declarative_analyser.
 :- import_module mdb.declarative_execution.
+:- import_module mdb.declarative_tree.
 :- import_module mdb.io_action.
 :- import_module mdb.term_rep.
 :- import_module mdbcomp.program_representation.
@@ -266,8 +268,8 @@
 	io.output_stream::in, browser_info.browser_persistent_state::in,
 	diagnoser_state(R)::out) is det.
 
-:- pred diagnosis(S::in, R::in, int::in, int::in, int::in,
-	diagnoser_response(R)::out,
+:- pred diagnosis(S::in, analysis_type(edt_node(R))::in, int::in, int::in,
+	int::in, diagnoser_response(R)::out,
 	diagnoser_state(R)::in, diagnoser_state(R)::out,
 	browser_info.browser_persistent_state::in,
 	browser_info.browser_persistent_state::out,
@@ -297,10 +299,8 @@
 
 :- implementation.
 
-:- import_module mdb.declarative_analyser.
 :- import_module mdb.declarative_edt.
 :- import_module mdb.declarative_oracle.
-:- import_module mdb.declarative_tree.
 :- import_module mdb.util.
 :- import_module mdbcomp.prim_data.
 
@@ -357,7 +357,7 @@
 	oracle_state_init(InStr, OutStr, Browser, Oracle),
 	Diagnoser = diagnoser(Analyser, Oracle).
 
-diagnosis(Store, NodeId, UseOldIoActionMap, IoActionStart, IoActionEnd,
+diagnosis(Store, AnalysisType, UseOldIoActionMap, IoActionStart, IoActionEnd,
 		Response, !Diagnoser, !Browser,
 		!IO) :-
 	mdb.declarative_oracle.set_browser_state(!.Browser, !.Diagnoser ^
@@ -375,7 +375,7 @@
 			Analyser0, Analyser1),
 		!:Diagnoser = !.Diagnoser ^ analyser_state := Analyser1
 	),
-	try_io(diagnosis_2(Store, NodeId, !.Diagnoser), Result, !IO),
+	try_io(diagnosis_2(Store, AnalysisType, !.Diagnoser), Result, !IO),
 	(
 		Result = succeeded({Response, !:Diagnoser})
 	;
@@ -392,13 +392,14 @@
 	!:Browser = mdb.declarative_oracle.get_browser_state(
 		!.Diagnoser ^ oracle_state).
 
-:- pred diagnosis_2(S::in, R::in, diagnoser_state(R)::in,
+:- pred diagnosis_2(S::in, analysis_type(edt_node(R))::in, 
+	diagnoser_state(R)::in,
 	{diagnoser_response(R), diagnoser_state(R)}::out,
 	io::di, io::uo) is cc_multi <= annotated_trace(S, R).
 
-diagnosis_2(Store, NodeId, Diagnoser0, {Response, Diagnoser}, !IO) :-
+diagnosis_2(Store, AnalysisType, Diagnoser0, {Response, Diagnoser}, !IO) :-
 	Analyser0 = Diagnoser0 ^ analyser_state,
-	start_or_resume_analysis(wrap(Store), dynamic(NodeId), 
+	start_or_resume_analysis(wrap(Store), AnalysisType, 
 		AnalyserResponse, Analyser0, Analyser),
 	diagnoser_set_analyser(Analyser, Diagnoser0, Diagnoser1),
 	debug_analyser_state(Analyser, MaybeOrigin),
@@ -557,10 +558,10 @@
 :- pragma export(mdb.declarative_debugger.divide_and_query_search_mode = out, 
 	"MR_DD_decl_divide_and_query_search_mode").
 
-	% Export a monomorphic version of diagnosis/10, to make it
-	% easier to call from C code.
+	% Export a monomorphic version of diagnosis/10 that passes a newly
+	% materialized tree for use with the C backend code.
 	%
-:- pred diagnosis_store(trace_node_store::in, trace_node_id::in,
+:- pred diagnosis_new_tree(trace_node_store::in, trace_node_id::in,
 	int::in, int::in, int::in, diagnoser_response(trace_node_id)::out,
 	diagnoser_state(trace_node_id)::in,
 	diagnoser_state(trace_node_id)::out, 
@@ -568,13 +569,32 @@
 	browser_info.browser_persistent_state::out, io::di, io::uo) 
 	is cc_multi.
 
-:- pragma export(diagnosis_store(in, in, in, in, in, out, in, out, in, out, 
-	di, uo), "MR_DD_decl_diagnosis").
+:- pragma export(diagnosis_new_tree(in, in, in, in, in, out, in, out, in, out, 
+	di, uo), "MR_DD_decl_diagnosis_new_tree").
+
+diagnosis_new_tree(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
+		Response, !State, !Browser, !IO) :-
+	diagnosis(Store, new_tree(dynamic(Node)), UseOldIoActionMap, 
+		IoActionStart, IoActionEnd, Response, !State, !Browser, !IO).
+
+	% Export a monomorphic version of diagnosis/10 that requests the
+	% continuance of a previously suspended declarative debugging session.
+	%
+:- pred diagnosis_resume_previous(trace_node_store::in, int::in, int::in,
+	int::in, diagnoser_response(trace_node_id)::out,
+	diagnoser_state(trace_node_id)::in,
+	diagnoser_state(trace_node_id)::out, 
+	browser_info.browser_persistent_state::in, 
+	browser_info.browser_persistent_state::out, io::di, io::uo) 
+	is cc_multi.
+
+:- pragma export(diagnosis_resume_previous(in, in, in, in,out, in, out, in,
+	out, di, uo), "MR_DD_decl_diagnosis_resume_previous").
 
-diagnosis_store(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
+diagnosis_resume_previous(Store, UseOldIoActionMap, IoActionStart, IoActionEnd,
 		Response, !State, !Browser, !IO) :-
-	diagnosis(Store, Node, UseOldIoActionMap, IoActionStart, IoActionEnd,
-		Response, !State, !Browser, !IO).
+	diagnosis(Store, resume_previous, UseOldIoActionMap, IoActionStart,
+		IoActionEnd, Response, !State, !Browser, !IO).
 
 	% Export some predicates so that C code can interpret the
 	% diagnoser response.
Index: browser/declarative_user.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/declarative_user.m,v
retrieving revision 1.43
diff -u -r1.43 declarative_user.m
--- browser/declarative_user.m	10 Feb 2005 04:41:43 -0000	1.43
+++ browser/declarative_user.m	23 Feb 2005 00:12:58 -0000
@@ -239,7 +239,8 @@
 
 handle_command(illegal_command, UserQuestion, Response, !User, 
 		!IO) :-
-	io.write_string("Unknown command, 'h' for help.\n", !IO),
+	io.write_string(!.User ^ outstr, "Unknown command, 'h' for help.\n", 
+		!IO),
 	query_user(UserQuestion, Response, !User, !IO).
 
 :- func arg_num_to_arg_pos(int) = arg_pos.
Index: runtime/mercury_stack_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.c,v
retrieving revision 1.70
diff -u -r1.70 mercury_stack_trace.c
--- runtime/mercury_stack_trace.c	17 Jan 2005 05:58:05 -0000	1.70
+++ runtime/mercury_stack_trace.c	22 Feb 2005 22:25:10 -0000
@@ -86,6 +86,14 @@
                         MR_bool print_parent, MR_bool verbose,
                         const char *filename, int lineno);
 
+static  MR_bool     MR_call_details_are_valid(const MR_Proc_Layout *entry, 
+                        MR_Word *base_sp, MR_Word *base_curfr);
+static  MR_bool     MR_call_is_before_event_or_seq(
+                        MR_find_first_call_seq_or_event seq_or_event, 
+                        MR_Unsigned seq_no_or_event_no, 
+                        const MR_Proc_Layout *entry, MR_Word *base_sp, 
+                        MR_Word *base_curfr);
+
 /* see comments in mercury_stack_trace.h */
 MR_Code *MR_stack_trace_bottom;
 MR_Word *MR_nondet_stack_trace_bottom;
@@ -1214,30 +1222,7 @@
         }
     }
 
-    if (MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry)) {
-        MR_Integer maybe_from_full = entry->MR_sle_maybe_from_full;
-        if (maybe_from_full > 0) {
-            /*
-            ** For procedures compiled with shallow
-            ** tracing, the details will be valid only
-            ** if the value of MR_from_full saved in
-            ** the appropriate stack slot was MR_TRUE.
-            */
-            if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
-                print_details = MR_based_stackvar(base_sp, maybe_from_full);
-            } else {
-                print_details = MR_based_framevar(base_curfr, maybe_from_full);
-            }
-        } else {
-            /*
-            ** For procedures compiled with full tracing,
-            ** we can always print out the details.
-            */
-            print_details = MR_TRUE;
-        }
-    } else {
-        print_details = MR_FALSE;
-    }
+    print_details = MR_call_details_are_valid(entry, base_sp, base_curfr);
 
     if (print_details) {
         unsigned long event_num;
@@ -1521,6 +1506,115 @@
             fprintf(fp, " (%s:%d)", filename, lineno);
         }
     }
+}
+
+static  MR_bool
+MR_call_details_are_valid(const MR_Proc_Layout *entry, MR_Word *base_sp, 
+    MR_Word *base_curfr)
+{
+    if (MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry)) {
+        MR_Integer maybe_from_full = entry->MR_sle_maybe_from_full;
+        if (maybe_from_full > 0) {
+            /*
+            ** For procedures compiled with shallow
+            ** tracing, the details will be valid only
+            ** if the value of MR_from_full saved in
+            ** the appropriate stack slot was MR_TRUE.
+            */
+            if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
+                return MR_based_stackvar(base_sp, maybe_from_full);
+            } else {
+                return MR_based_framevar(base_curfr, maybe_from_full);
+            }
+        } else {
+            return MR_TRUE;
+        }
+    } else {
+        return MR_FALSE;
+    }
+}
+
+static MR_bool
+MR_call_is_before_event_or_seq(MR_find_first_call_seq_or_event seq_or_event, 
+    MR_Unsigned seq_no_or_event_no, 
+    const MR_Proc_Layout *entry, MR_Word *base_sp, MR_Word *base_curfr)
+{
+    MR_Unsigned     call_event_num;
+    MR_Unsigned     call_seq_num;
+    
+    if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
+        if (base_sp == NULL) {
+            return MR_FALSE;
+        }
+    } else {
+        if (base_curfr == NULL) {
+            return MR_FALSE;
+        }
+    }
+
+    if (MR_call_details_are_valid(entry, base_sp, base_curfr)) {
+        if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
+            call_event_num = MR_event_num_stackvar(base_sp) + 1;
+            call_seq_num = MR_call_num_stackvar(base_sp);
+        } else {
+            call_event_num = MR_event_num_framevar(base_curfr) + 1;
+            call_seq_num = MR_call_num_framevar(base_curfr);
+        }
+        if (seq_or_event == MR_FIND_FIRST_CALL_BEFORE_EVENT) {
+            return call_event_num <= seq_no_or_event_no;
+        } else if (seq_or_event == MR_FIND_FIRST_CALL_BEFORE_SEQ) {
+            return call_seq_num <= seq_no_or_event_no;
+        } else {
+            MR_fatal_error("Unknown MR_find_first_call_seq_or_event");
+        }
+    } else {
+        return MR_FALSE;
+    }
+}
+
+int
+MR_find_first_call_less_eq_seq_or_event(
+    MR_find_first_call_seq_or_event seq_or_event, 
+    MR_Unsigned seq_no_or_event_no, 
+    const MR_Label_Layout *label_layout, MR_Word *det_stack_pointer, 
+    MR_Word *current_frame, const char **problem)
+{
+    MR_Stack_Walk_Step_Result       result;
+    const MR_Label_Layout           *cur_label_layout;
+    MR_Word                         *stack_trace_sp;
+    MR_Word                         *stack_trace_curfr;
+    int                             ancestor_level;
+
+    MR_do_init_modules();
+
+    stack_trace_sp = det_stack_pointer;
+    stack_trace_curfr = current_frame;
+
+    cur_label_layout = label_layout;
+
+    ancestor_level = 0;
+
+    while (cur_label_layout != NULL) {
+
+        if (MR_call_is_before_event_or_seq(seq_or_event, seq_no_or_event_no, 
+                cur_label_layout->MR_sll_entry, stack_trace_sp,
+                stack_trace_curfr)) {
+            return ancestor_level;
+        }
+
+        result = MR_stack_walk_step(cur_label_layout->MR_sll_entry, 
+            &cur_label_layout, &stack_trace_sp, &stack_trace_curfr, problem);
+        
+        if (result != MR_STEP_OK) {
+            return -1;
+        } 
+
+        ancestor_level++;
+
+    } while (cur_label_layout != NULL);
+
+    *problem = "no more stack";
+    return -1;
 }
 
 /*
Index: runtime/mercury_stack_trace.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.h,v
retrieving revision 1.36
diff -u -r1.36 mercury_stack_trace.h
--- runtime/mercury_stack_trace.h	17 Jan 2005 05:58:06 -0000	1.36
+++ runtime/mercury_stack_trace.h	22 Feb 2005 22:25:10 -0000
@@ -297,4 +297,25 @@
 			const char *filename, int linenumber,
 			const char *goal_path, MR_bool context_mismatch);
 
+/*
+** Find the first call event in the stack whose event number or sequence number
+** is less than or equal to the given event number or sequence number.  The
+** level of the call in the stack is returned.  This can then be passed to
+** MR_trace_retry as the ancestor_level.  If no such call is found then -1 is
+** returned and problem is set to the reason why the call could not be
+** found.
+*/
+
+typedef	enum {
+	MR_FIND_FIRST_CALL_BEFORE_SEQ,
+	MR_FIND_FIRST_CALL_BEFORE_EVENT
+} MR_find_first_call_seq_or_event;
+
+extern	int	MR_find_first_call_less_eq_seq_or_event(
+			MR_find_first_call_seq_or_event seq_or_event,
+			MR_Unsigned seq_no_or_event_no, 
+			const MR_Label_Layout *label_layout, 
+			MR_Word *det_stack_pointer, MR_Word *current_frame, 
+    			const char **problem);
+
 #endif /* MERCURY_STACK_TRACE_H */
Index: tests/debugger/declarative/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/declarative/Mmakefile,v
retrieving revision 1.72
diff -u -r1.72 Mmakefile
--- tests/debugger/declarative/Mmakefile	19 Jan 2005 09:55:20 -0000	1.72
+++ tests/debugger/declarative/Mmakefile	23 Feb 2005 23:49:01 -0000
@@ -53,6 +53,7 @@
 	propositional		\
 	queens			\
 	remember_modes		\
+	resume			\
 	revise			\
 	revise_2		\
 	small			\
@@ -383,6 +384,10 @@
 remember_modes.out: remember_modes remember_modes.inp
 	$(MDB_STD) ./remember_modes < remember_modes.inp \
 			> remember_modes.out 2>&1 \
+	|| { grep . $@ /dev/null; exit 1; }
+
+resume.out: resume resume.inp
+	$(MDB_STD) ./resume < resume.inp > resume.out 2>&1 \
 	|| { grep . $@ /dev/null; exit 1; }
 
 revise.out: revise revise.inp
Index: tests/debugger/declarative/resume.exp
===================================================================
RCS file: tests/debugger/declarative/resume.exp
diff -N tests/debugger/declarative/resume.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/resume.exp	24 Feb 2005 00:22:25 -0000
@@ -0,0 +1,210 @@
+      E1:     C1 CALL pred resume.main/2-0 (det) resume.m:13
+mdb> mdb> Contexts will not be printed.
+mdb> echo on
+Command echo enabled.
+mdb> break -E3 resume.l
+ 0: + stop  interface func resume.l/1-0 (semidet)
+            (ignore next 3 call events)
+mdb> c
+      E2:     C2 CALL func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface func resume.l/1-0 (semidet)
+mdb> f
+      E3:     C2 EXIT func resume.l/1-0 (semidet)
+mdb> dd
+l([4, 5]) = 5
+Valid? pd
+      E3:     C2 EXIT func resume.l/1-0 (semidet)
+mdb> dd -r
+l([4, 5]) = 5
+Valid? y
+l([3, 4, 5]) = 5
+Valid? pd
+      E4:     C3 EXIT func resume.l/1-0 (semidet)
+mdb> break wrapper
+ 0: + stop  interface pred resume.wrapper/6-0 (semidet)
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> retry
+      E6:     C4 CALL pred resume.wrapper/6-0 (semidet)
+mdb> dd -r
+l([3, 4, 5]) = 5
+Valid? a
+Diagnosis aborted.
+      E6:     C4 CALL pred resume.wrapper/6-0 (semidet)
+mdb> dd -r
+l([3, 4, 5]) = 5
+Valid? pd
+      E4:     C3 EXIT func resume.l/1-0 (semidet)
+mdb> print
+l([3, 4, 5]) = 5
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> retry
+      E6:     C4 CALL pred resume.wrapper/6-0 (semidet)
+mdb> break resume.m:33
+ 1: + stop  linenumber resume.m:33
+mdb> c
+      E7:     C5 CALL func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface pred resume.wrapper/6-0 (semidet)
+ 1: E stop  linenumber resume.m:33
+mdb> break -E3 resume.l
+ 0: + stop  interface func resume.l/1-0 (semidet)
+            (ignore next 3 call events)
+mdb> c
+      E8:     C6 CALL func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface func resume.l/1-0 (semidet)
+mdb> f
+      E9:     C6 EXIT func resume.l/1-0 (semidet)
+mdb> dd
+l([10]) = 10
+Valid? pd
+      E9:     C6 EXIT func resume.l/1-0 (semidet)
+mdb> break wrapper
+ 0: + stop  interface pred resume.wrapper/6-0 (semidet)
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> retry
+      E6:     C4 CALL pred resume.wrapper/6-0 (semidet)
+mdb> dd -r
+l([10]) = 10
+Valid? y
+l([9, 10]) = 10
+Valid? y
+l([8, 9, 10]) = 10
+Valid? n
+Found incorrect contour:
+l([9, 10]) = 10
+l([8, 9, 10]) = 10
+Is this a bug? y
+     E10:     C7 EXIT func resume.l/1-0 (semidet)
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> retry
+      E6:     C4 CALL pred resume.wrapper/6-0 (semidet)
+mdb> break resume.m:34
+ 2: + stop  linenumber resume.m:34
+mdb> c
+     E11:     C8 CALL func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface pred resume.wrapper/6-0 (semidet)
+ 2: E stop  linenumber resume.m:34
+mdb> break -E3 resume.l
+ 0: + stop  interface func resume.l/1-0 (semidet)
+            (ignore next 3 call events)
+mdb> c
+     E12:     C9 CALL func resume.l/1-0 (semidet)
+mdb> f
+     E13:     C9 EXIT func resume.l/1-0 (semidet)
+mdb> dd
+l([15]) = 15
+Valid? pd
+     E13:     C9 EXIT func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface func resume.l/1-0 (semidet)
+mdb> break wrapper
+ 0: + stop  interface pred resume.wrapper/6-0 (semidet)
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> dd -r
+l([15]) = 15
+Valid? y
+l([14, 15]) = 15
+Valid? pd
+     E14:    C10 EXIT func resume.l/1-0 (semidet)
+mdb> break resume.m:35
+ 3: + stop  linenumber resume.m:35
+mdb> c
+     E15:    C11 CALL func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface pred resume.wrapper/6-0 (semidet)
+ 3: E stop  linenumber resume.m:35
+mdb> f
+     E16:    C11 EXIT func resume.l/1-0 (semidet)
+mdb> dd -d 2
+l([16, 17, 18, 19, 20]) = 20
+Valid? pd
+     E16:    C11 EXIT func resume.l/1-0 (semidet)
+mdb> dd -r
+l([16, 17, 18, 19, 20]) = 20
+Valid? n
+l([17, 18, 19, 20]) = 20
+Valid? n
+l([18, 19, 20]) = 20
+Valid? n
+l([19, 20]) = 20
+Valid? n
+l([20]) = 20
+Valid? n
+Found incorrect contour:
+l([20]) = 20
+Is this a bug? y
+     E17:    C12 EXIT func resume.l/1-0 (semidet)
+mdb> break resume.m:36
+ 4: + stop  linenumber resume.m:36
+mdb> c
+     E18:    C13 CALL func resume.l/1-0 (semidet)
+mdb> f
+     E19:    C13 EXIT func resume.l/1-0 (semidet)
+mdb> dd -d 2
+l([21, 22, 23, 24, 25]) = 25
+Valid? pd
+     E19:    C13 EXIT func resume.l/1-0 (semidet)
+mdb> delete *
+ 4: E stop  linenumber resume.m:36
+mdb> break wrapper
+ 0: + stop  interface pred resume.wrapper/6-0 (semidet)
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> retry
+      E6:     C4 CALL pred resume.wrapper/6-0 (semidet)
+mdb> dd -r
+l([21, 22, 23, 24, 25]) = 25
+Valid? n
+l([22, 23, 24, 25]) = 25
+Valid? n
+l([23, 24, 25]) = 25
+Valid? n
+l([24, 25]) = 25
+Valid? n
+l([25]) = 25
+Valid? n
+Found incorrect contour:
+l([25]) = 25
+Is this a bug? y
+     E20:    C14 EXIT func resume.l/1-0 (semidet)
+mdb> break resume.m:37
+ 5: + stop  linenumber resume.m:37
+mdb> c
+     E21:    C15 CALL func resume.l/1-0 (semidet)
+mdb> f
+     E22:    C15 EXIT func resume.l/1-0 (semidet)
+mdb> dd -d 2
+l([26, 27, 28, 29, 30]) = 30
+Valid? pd
+     E22:    C15 EXIT func resume.l/1-0 (semidet)
+mdb> delete *
+ 0: E stop  interface pred resume.wrapper/6-0 (semidet)
+ 5: E stop  linenumber resume.m:37
+mdb> break wrapper
+ 0: + stop  interface pred resume.wrapper/6-0 (semidet)
+mdb> c
+      E5:     C4 EXIT pred resume.wrapper/6-0 (semidet)
+mdb> dd -r
+l([26, 27, 28, 29, 30]) = 30
+Valid? n
+l([27, 28, 29, 30]) = 30
+Valid? n
+l([28, 29, 30]) = 30
+Valid? n
+l([29, 30]) = 30
+Valid? n
+l([30]) = 30
+Valid? n
+Found incorrect contour:
+l([30]) = 30
+Is this a bug? y
+     E23:    C16 EXIT func resume.l/1-0 (semidet)
+mdb> quit -y
Index: tests/debugger/declarative/resume.inp
===================================================================
RCS file: tests/debugger/declarative/resume.inp
diff -N tests/debugger/declarative/resume.inp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/resume.inp	23 Feb 2005 23:44:02 -0000
@@ -0,0 +1,100 @@
+register --quiet
+context none
+echo on
+break -E3 resume.l
+c
+delete *
+f
+dd
+pd
+dd -r
+y
+pd
+break wrapper
+c
+retry
+dd -r
+a
+dd -r
+pd
+print
+c
+retry
+break resume.m:33
+c
+delete *
+break -E3 resume.l
+c
+delete *
+f
+dd
+pd
+break wrapper
+c
+retry
+dd -r
+y
+y
+n
+y
+c
+retry
+break resume.m:34
+c
+delete *
+break -E3 resume.l
+c
+f
+dd
+pd
+delete *
+break wrapper
+c
+dd -r
+y
+pd
+break resume.m:35
+c
+delete *
+f
+dd -d 2
+pd
+dd -r
+n
+n
+n
+n
+n
+y
+break resume.m:36
+c
+f
+dd -d 2
+pd
+delete *
+break wrapper
+c
+retry
+dd -r
+n
+n
+n
+n
+n
+y
+break resume.m:37
+c
+f
+dd -d 2
+pd
+delete *
+break wrapper
+c
+dd -r
+n
+n
+n
+n
+n
+y
+quit -y
Index: tests/debugger/declarative/resume.m
===================================================================
RCS file: tests/debugger/declarative/resume.m
diff -N tests/debugger/declarative/resume.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/declarative/resume.m	23 Feb 2005 01:13:17 -0000
@@ -0,0 +1,42 @@
+:- module resume.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module list, int.
+
+main(!IO) :-
+	(
+		wrapper(A, B, C, D, E, F)
+	->
+		io.write(A, !IO),
+		io.write(B, !IO),
+		io.write(C, !IO),
+		io.write(D, !IO),
+		io.write(E, !IO),
+		io.write(F, !IO)
+	;
+		io.write_string("fail", !IO)
+	),
+	io.nl(!IO).
+
+:- pred wrapper(int::out, int::out, int::out, int::out, int::out, int::out) 
+	is semidet.
+
+wrapper(A, B, C, D, E, F) :-
+	A = l([1, 2, 3, 4, 5]),
+	B = l([6, 7, 8, 9, 10]),
+	C = l([11, 12, 13, 14, 15]),
+	D = l([16, 17, 18, 19, 20]),
+	E = l([21, 22, 23, 24, 25]),
+	F = l([26, 27, 28, 29, 30]).
+
+:- func l(list(T)) = T is semidet.
+
+l([H | []]) = H.
+l([_ | [TH | TT]]) = l([TH | TT]).
Index: trace/mercury_trace_declarative.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_declarative.c,v
retrieving revision 1.79
diff -u -r1.79 mercury_trace_declarative.c
--- trace/mercury_trace_declarative.c	27 Jan 2005 06:17:40 -0000	1.79
+++ trace/mercury_trace_declarative.c	24 Feb 2005 01:59:14 -0000
@@ -5,7 +5,7 @@
 */
 
 /*
-** Main author: Mark Brown
+** Main authors: Mark Brown, Ian MacLarty
 **
 ** This file implements the back end of the declarative debugger.  The
 ** back end is an extension to the internal debugger which collects
@@ -104,18 +104,29 @@
 ** MR_trace_start_decl_debug when the back end is started.  They
 ** are used by MR_trace_decl_debug to decide what action to
 ** take for a particular trace event.
-**
-** Events that are deeper than the maximum depth, or which are
-** outside the top call being debugged, are ignored.  Events which
-** are beyond the given last event cause the internal debugger to
-** be switched back into interactive mode.
 */
 
-static	MR_Unsigned	MR_edt_max_depth;
+/*
+** If we are building a subtree then reaching this event will cause the
+** declarative debugger to continue its analysis.  Reaching this event means
+** generation of the desired subtree is complete.  This variable is not used
+** when building a new explicit supertree (a supertree is a tree above the
+** currently materialized portion of the annotated trace).
+*/
+
 static	MR_Unsigned	MR_edt_last_event;
+
+/*
+** If we are materializing a new subtree then MR_edt_start_seqno is the
+** call sequence number of the call at the top the the subtree we want to 
+** materialize.  If we are building a new supertree then MR_edt_start_seqno
+** is the call sequence number of the call at the top of the existing
+** materialized portion of the annotated trace.
+*/
+
 static	MR_Unsigned	MR_edt_start_seqno;
+
 static	MR_Unsigned	MR_edt_start_io_counter;
-static	MR_Unsigned	MR_edt_topmost_call_depth;
 
 /*
 ** This tells MR_trace_decl_debug whether it is inside a portion of the
@@ -165,6 +176,13 @@
 
 static	MR_Integer	MR_edt_depth;
 
+/* 
+** Events where the value of MR_edt_depth above is greater than the value of
+** MR_edt_max_depth will not be included in tha annotated trace.
+*/
+
+static	MR_Unsigned	MR_edt_max_depth;
+
 /*
 ** The declarative debugger ignores modules that were not compiled with
 ** the required information.  However, this may result in incorrect
@@ -253,7 +271,6 @@
 				MR_Word *saved_regs);
 static	const char	*MR_trace_start_collecting(MR_Unsigned event,
 				MR_Unsigned seqno, MR_Unsigned maxdepth,
-				MR_Unsigned topmost_call_depth,
 				MR_bool create_supertree,
 				MR_Trace_Cmd_Info *cmd,
 				MR_Event_Info *event_info,
@@ -275,6 +292,13 @@
 				MR_Trace_Cmd_Info *cmd,
 				MR_Event_Info *event_info,
 				MR_Event_Details *event_details);
+	/*
+	** Retry max_distance if there are that many ancestors, otherwise
+	** retry as far as possible.
+	*/
+static	MR_Code		*MR_trace_decl_retry_max(MR_Unsigned max_distance, 
+				MR_Event_Info *event_info,
+				MR_Event_Details *event_details);
 static	MR_String	MR_trace_node_path(MR_Trace_Node node);
 static	MR_Trace_Port	MR_trace_node_port(MR_Trace_Node node);
 static	MR_Unsigned	MR_trace_node_seqno(MR_Trace_Node node);
@@ -340,6 +364,10 @@
 		return NULL;
 	}
 
+	event_details.MR_call_seqno = MR_trace_call_seqno;
+	event_details.MR_call_depth = MR_trace_call_depth;
+	event_details.MR_event_number = MR_trace_event_number;
+
 	/*
 	** Decide if we are inside or outside the subtree or supertree that
 	** needs to be materialized, ignoring for now any depth limit.  
@@ -359,6 +387,22 @@
 				** MR_edt_start_seqno.
 				*/
 				MR_edt_inside = MR_TRUE;
+			} else if (event_info->MR_call_seqno == 
+				MR_edt_start_seqno && MR_port_is_entry(
+					event_info->MR_trace_port))
+			{
+				/*
+				** We are entering the top of the currently
+				** materialized portion of the annotated trace.
+				** Since we are building a supertree we must
+				** retry to above the current event and start
+				** building the new portion of the annotated
+				** trace from there.
+				*/
+				MR_edt_inside = MR_TRUE;
+				return MR_trace_decl_retry_max(
+					MR_edt_max_depth - 1, 
+					event_info, &event_details);
 			} else {
 				/*
 				** We are in an existing explicit subtree.
@@ -464,10 +508,6 @@
 		return NULL;
 	}
 
-	event_details.MR_call_seqno = MR_trace_call_seqno;
-	event_details.MR_call_depth = MR_trace_call_depth;
-	event_details.MR_event_number = MR_trace_event_number;
-
 	MR_debug_enabled = MR_FALSE;
 	MR_update_trace_func_enabled();
 	MR_decl_checkpoint_event(event_info);
@@ -550,6 +590,45 @@
 	return NULL;
 }
 
+static	MR_Code *
+MR_trace_decl_retry_max(MR_Unsigned max_distance, MR_Event_Info *event_info,
+	MR_Event_Details *event_details)
+{
+	MR_Code		*jumpaddr;
+	int		retry_distance;
+	const char	*problem;
+	MR_Retry_Result retry_result;
+
+	if (max_distance >= event_info->MR_call_depth) {
+		retry_distance = event_info->MR_call_depth - 1;
+	} else {
+		retry_distance = max_distance;
+	}
+	
+	retry_result = MR_trace_retry(event_info, event_details,
+		retry_distance, MR_RETRY_IO_INTERACTIVE,
+		MR_trace_decl_assume_all_io_is_tabled, &problem, MR_mdb_in,
+		MR_mdb_out, &jumpaddr);
+
+	if (retry_result != MR_RETRY_OK_DIRECT) {
+		if (retry_result == MR_RETRY_ERROR) {
+			MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err, "mdb: retry aborted in "
+				"MR_trace_decl_retry_max: %s\n",
+				problem);
+			return NULL;
+		} else {
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err, "mdb: internal error in "
+				"MR_trace_decl_retry_max: direct retry "
+				"impossible\n");
+			return NULL;
+		}
+	}
+	return jumpaddr;
+}
+
 static	MR_Trace_Node
 MR_trace_decl_call(MR_Event_Info *event_info, MR_Trace_Node prev)
 {
@@ -1284,7 +1363,7 @@
 
 MR_bool
 MR_trace_start_decl_debug(MR_Trace_Mode trace_mode, const char *outfile,
-	MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
+	MR_bool new_session, MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info,
 	MR_Event_Details *event_details, MR_Code **jumpaddr)
 {
 	MR_Retry_Result		result;
@@ -1293,10 +1372,25 @@
 	MR_Unsigned		edt_depth_limit;
 	const char		*message;
 	MR_Trace_Level		trace_level;
+	static	MR_bool		first_time = MR_TRUE;
 
-	MR_edt_return_node = (MR_Trace_Node) NULL;
+	MR_edt_initial_event = event_info->MR_event_number;
+
+	/*
+	** If it was requested that the previous session be resumed and
+	** there was a previous dd session, then there is no need to 
+	** build a new annotated trace.  Just call the front end, passing
+	** NULL as the root node to let it know it must resume the 
+	** previous session.
+	*/
+	if (!new_session && !first_time) {
+		MR_trace_decl_mode = trace_mode;
+		*jumpaddr = MR_decl_diagnosis((MR_Trace_Node) NULL, cmd, 
+			event_info, event_details);
+		return MR_TRUE;
+	}
 
-	MR_edt_initial_event = event_details->MR_event_number;
+	MR_edt_return_node = (MR_Trace_Node) NULL;
 
 	if (!MR_port_is_final(event_info->MR_trace_port)) {
 		fflush(MR_mdb_out);
@@ -1362,17 +1456,16 @@
 
 	MR_trace_decl_ensure_init();
 	edt_depth_limit = MR_edt_depth_step_size;
-	MR_edt_topmost_call_depth = event_info->MR_call_depth;
 	MR_edt_depth = 0;
 	
 	MR_trace_current_node = (MR_Trace_Node) NULL;
 	
 	message = MR_trace_start_collecting(event_info->MR_event_number,
 			event_info->MR_call_seqno, edt_depth_limit,
-			MR_edt_topmost_call_depth, MR_FALSE, cmd, event_info, 
-			event_details, jumpaddr);
+			MR_FALSE, cmd, event_info, event_details, jumpaddr);
 
 	if (message == NULL) {
+		first_time = MR_FALSE;
 		return MR_TRUE;
 	} else {
 		fflush(MR_mdb_out);
@@ -1402,24 +1495,13 @@
 	*/
 	MR_trace_current_node = call_preceding;
 
-	/*
-	** If we're going to build a supertree above the current root, then
-	** adjust the depth of the topmost node.
-	*/
-	if (create_supertree) {
-		if (MR_edt_depth_step_size < MR_edt_topmost_call_depth) {
-			MR_edt_topmost_call_depth -= MR_edt_depth_step_size;
-		} else {
-			MR_edt_topmost_call_depth = 1;
-		}
-	}
-	edt_depth_limit = MR_edt_depth_step_size + 1;
+	edt_depth_limit = MR_edt_depth_step_size;
 	
 	MR_edt_depth = 0;
 
 	message = MR_trace_start_collecting(event, seqno, edt_depth_limit,
-			MR_edt_topmost_call_depth, create_supertree, cmd, 
-			event_info, event_details, &jumpaddr);
+			create_supertree, cmd, event_info, event_details,
+			&jumpaddr);
 
 	if (message != NULL) {
 		fflush(MR_mdb_out);
@@ -1435,28 +1517,58 @@
 
 static	const char *
 MR_trace_start_collecting(MR_Unsigned event, MR_Unsigned seqno,
-	MR_Unsigned maxdepth, MR_Unsigned topmost_call_depth, 
-	MR_bool create_supertree, MR_Trace_Cmd_Info *cmd, MR_Event_Info
-	*event_info, MR_Event_Details *event_details, MR_Code **jumpaddr)
+	MR_Unsigned maxdepth, MR_bool create_supertree, MR_Trace_Cmd_Info *cmd,
+	MR_Event_Info *event_info, MR_Event_Details *event_details, 
+	MR_Code **jumpaddr)
 {
 	const char		*problem;
 	MR_Retry_Result		retry_result;
-	MR_Unsigned		retry_levels;
+	int			retry_distance;
 
-	/*
-	** Go back to an event before the topmost call.
+	/* 
+	** We need to do a retry if the current event is greater than the
+	** call event number corresponding to seqno.  Since we don't have the
+	** call event number for seqno (`event' is the final event number, 
+	** not the call event number), we do a retry if:
+	**    a) The call sequence number of the current call is greater than
+	**       or equal to seqno, or
+	**    b) The current event number is greater than the final event
+	**       for seqno.
+	**
+	** Case b) covers the situation where the current event is after the
+	** final event for seqno and case a) covers the case where the current
+	** event is greater than or equal to the call event for seqno and less
+	** than or equal to the final event for seqno.  This means we will do
+	** a retry if the call event for seqno is equal to the current event
+	** but thats not a problem since the retry will be a no-op.
 	*/
-	retry_result = MR_trace_retry(event_info, event_details, 
-		event_info->MR_call_depth - topmost_call_depth, 
-		MR_RETRY_IO_INTERACTIVE,
-		MR_trace_decl_assume_all_io_is_tabled, &problem, 
-		MR_mdb_in, MR_mdb_out, jumpaddr);
-	if (retry_result != MR_RETRY_OK_DIRECT) {
-		if (retry_result == MR_RETRY_ERROR) {
+	if (event_info->MR_call_seqno >= seqno || 
+		event_info->MR_event_number > event) 
+	{
+		retry_distance = MR_find_first_call_less_eq_seq_or_event(
+			MR_FIND_FIRST_CALL_BEFORE_SEQ, seqno, 
+			event_info->MR_event_sll, 
+			MR_saved_sp(event_info->MR_saved_regs),
+			MR_saved_curfr(event_info->MR_saved_regs), &problem);
+		
+		if (retry_distance < 0) {
 			return problem;
-		} else {
-			return "internal error: direct retry impossible";
 		}
+
+		retry_result = MR_trace_retry(event_info, event_details, 
+			retry_distance, MR_RETRY_IO_INTERACTIVE,
+			MR_trace_decl_assume_all_io_is_tabled, &problem, 
+			MR_mdb_in, MR_mdb_out, jumpaddr);
+		if (retry_result != MR_RETRY_OK_DIRECT) {
+			if (retry_result == MR_RETRY_ERROR) {
+				return problem;
+			} else {
+				return "internal error: direct retry "
+					"impossible";
+			}
+		}
+	} else {
+		*jumpaddr = NULL;
 	}
 	
 	/*
@@ -1472,18 +1584,13 @@
 	MR_edt_start_seqno = seqno;
 	MR_edt_start_io_counter = MR_io_tabling_counter;
 	MR_edt_max_depth = maxdepth;
-
-	if (create_supertree) {
-		MR_edt_inside = MR_TRUE;
-	} else {
-		MR_edt_inside = MR_FALSE;
-	}
+	MR_edt_inside = MR_FALSE;
 	MR_edt_building_supertree = create_supertree;
 
 	/*
 	** Restore globals from the saved copies.
 	*/
-        MR_trace_call_seqno = event_details->MR_call_seqno;
+	MR_trace_call_seqno = event_details->MR_call_seqno;
 	MR_trace_call_depth = event_details->MR_call_depth;
 	MR_trace_event_number = event_details->MR_event_number;
 	
@@ -1537,7 +1644,8 @@
 				" the debugging tree.\n");
 	}
 
-	if (MR_trace_decl_mode == MR_TRACE_DECL_DEBUG_DUMP) {
+	if (MR_trace_decl_mode == MR_TRACE_DECL_DEBUG_DUMP 
+			&& root != (MR_Trace_Node) NULL) {
 		MR_mercuryfile_init(MR_trace_store_file, 1, &stream);
 
 		MR_TRACE_CALL_MERCURY(
@@ -1581,7 +1689,10 @@
 	}
 
 	MR_TRACE_CALL_MERCURY(
-		MR_DD_decl_diagnosis(MR_trace_node_store, root, use_old_io_map,
+		if (root == (MR_Trace_Node) NULL) {
+			MR_DD_decl_diagnosis_resume_previous(
+				MR_trace_node_store, 
+				use_old_io_map,
 				MR_io_action_map_cache_start,
 				MR_io_action_map_cache_end,
 				&response, MR_trace_front_end_state,
@@ -1589,6 +1700,17 @@
 				MR_trace_browser_persistent_state,
 				&MR_trace_browser_persistent_state
 			);
+		} else {
+			MR_DD_decl_diagnosis_new_tree(MR_trace_node_store, 
+				root, use_old_io_map,
+				MR_io_action_map_cache_start,
+				MR_io_action_map_cache_end,
+				&response, MR_trace_front_end_state,
+				&MR_trace_front_end_state,
+				MR_trace_browser_persistent_state,
+				&MR_trace_browser_persistent_state
+			);
+		}
 		bug_found = MR_DD_diagnoser_bug_found(response,
 				(MR_Integer *) &bug_event);
 		symptom_found = MR_DD_diagnoser_symptom_found(response,
@@ -1666,38 +1788,71 @@
 	const char		*problem;
 	MR_Retry_Result		retry_result;
 	MR_Code			*jumpaddr;
+	int			ancestor_level;
 
 	/*
-	** Perform a retry to get to somewhere before the
-	** bug event.  Then set the command to go to the bug
-	** event and return to interactive mode.
-	*/
+	** We only need to do a retry if the event number we want to be at is
+	** less than or equal to the current event number (we need to do a
+	** retry if the event numbers are equal, because MR_trace_real will
+	** increment the current event number, so the next event displayed by
+	** mdb will be the current event + 1.
+	*/
+	if (event <= event_info->MR_event_number) {
+		ancestor_level = MR_find_first_call_less_eq_seq_or_event(
+			MR_FIND_FIRST_CALL_BEFORE_EVENT, event, 
+			event_info->MR_event_sll, 
+			MR_saved_sp(event_info->MR_saved_regs),
+			MR_saved_curfr(event_info->MR_saved_regs), &problem);
+
+		if (ancestor_level >= 0) {
+			/*
+			** Perform a retry to get to somewhere before the
+			** given event.  Then set the command to go to the
+			** given event and return to interactive mode.
+			*/
 #ifdef	MR_DEBUG_RETRY
-	MR_print_stack_regs(stdout, event_info->MR_saved_regs);
-	MR_print_succip_reg(stdout, event_info->MR_saved_regs);
+			MR_print_stack_regs(stdout, event_info->MR_saved_regs);
+			MR_print_succip_reg(stdout, event_info->MR_saved_regs);
 #endif
-	retry_result = MR_trace_retry(event_info, event_details, 
-		event_info->MR_call_depth - MR_edt_topmost_call_depth, 
-		MR_RETRY_IO_INTERACTIVE,
-		MR_trace_decl_assume_all_io_is_tabled, &problem, 
-		MR_mdb_in, MR_mdb_out, &jumpaddr);
+			retry_result = MR_trace_retry(event_info,
+				event_details, ancestor_level,
+				MR_RETRY_IO_INTERACTIVE,
+				MR_trace_decl_assume_all_io_is_tabled,
+				&problem, MR_mdb_in, MR_mdb_out, &jumpaddr);
 #ifdef	MR_DEBUG_RETRY
-	MR_print_stack_regs(stdout, event_info->MR_saved_regs);
-	MR_print_succip_reg(stdout, event_info->MR_saved_regs);
-	MR_print_r_regs(stdout, event_info->MR_saved_regs);
+			MR_print_stack_regs(stdout, event_info->MR_saved_regs);
+			MR_print_succip_reg(stdout, event_info->MR_saved_regs);
+			MR_print_r_regs(stdout, event_info->MR_saved_regs);
 #endif
-	if (retry_result != MR_RETRY_OK_DIRECT) {
-		fflush(MR_mdb_out);
-		fprintf(MR_mdb_err, "mdb: diagnosis aborted:\n");
-		if (retry_result == MR_RETRY_ERROR) {
-			fprintf(MR_mdb_err, "%s\n", problem);
-		} else {
-			fprintf(MR_mdb_err, "direct retry impossible\n");
 		}
-		MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
-		MR_debug_enabled = MR_TRUE;
-		MR_update_trace_func_enabled();
-		return MR_trace_event_internal(cmd, MR_TRUE, NULL, event_info);
+		if ((ancestor_level < 0) || 
+				(retry_result != MR_RETRY_OK_DIRECT)) {
+			fflush(MR_mdb_out);
+			fprintf(MR_mdb_err, "mdb: diagnosis aborted:\n");
+			if (ancestor_level < 0) {
+				fprintf(MR_mdb_err, "couldn't find call on "
+					"stack: %s\n", problem);
+			} else {
+				if (retry_result == MR_RETRY_ERROR) {
+					fprintf(MR_mdb_err, "%s\n", problem);
+				} else {
+					fprintf(MR_mdb_err, 
+						"direct retry impossible\n");
+				}
+			}
+			MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
+			MR_debug_enabled = MR_TRUE;
+			MR_update_trace_func_enabled();
+			return MR_trace_event_internal(cmd, MR_TRUE, NULL, 
+				event_info);
+		}
+	} else {
+		/*
+		** Since the event we want to be at is after the current event
+		** don't jump anywhere, just do forward execution until we
+		** get to the right event.
+		*/
+		jumpaddr = NULL;
 	}
 
 	cmd->MR_trace_cmd = MR_CMD_GOTO;
Index: trace/mercury_trace_declarative.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_declarative.h,v
retrieving revision 1.22
diff -u -r1.22 mercury_trace_declarative.h
--- trace/mercury_trace_declarative.h	24 Jan 2005 07:53:38 -0000	1.22
+++ trace/mercury_trace_declarative.h	22 Feb 2005 22:25:14 -0000
@@ -27,7 +27,8 @@
 */
 
 extern	MR_bool	MR_trace_start_decl_debug(MR_Trace_Mode trace_mode,
-			const char *out, MR_Trace_Cmd_Info *cmd,
+			const char *out, MR_bool new_session,
+			MR_Trace_Cmd_Info *cmd,
 			MR_Event_Info *event_info,
 			MR_Event_Details *event_details, MR_Code **jumpaddr);
 
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.195
diff -u -r1.195 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	18 Feb 2005 04:05:35 -0000	1.195
+++ trace/mercury_trace_internal.c	22 Feb 2005 22:25:14 -0000
@@ -598,7 +598,7 @@
                         int *word_count, const char *cat, const char*item);
 static  MR_bool     MR_trace_options_dd(MR_bool *assume_all_io_is_tabled,
                         MR_Integer *depth_step_size, 
-                        MR_Decl_Search_Mode *search_mode, 
+                        MR_Decl_Search_Mode *search_mode, MR_bool *new_session,
                         char ***words, int *word_count, const char *cat, 
                         const char *item);
 static  MR_bool     MR_trace_options_type_ctor(MR_bool *print_rep,
@@ -5688,6 +5688,7 @@
     MR_Code **jumpaddr)
 {
     MR_Decl_Search_Mode search_mode;
+    MR_bool             new_session = MR_TRUE;
 
     MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;
     MR_edt_depth_step_size = MR_TRACE_DECL_INITIAL_DEPTH;
@@ -5695,7 +5696,7 @@
     MR_trace_decl_in_dd_dd_mode = MR_FALSE;
         
     if (! MR_trace_options_dd(&MR_trace_decl_assume_all_io_is_tabled,
-        &MR_edt_depth_step_size, &search_mode,
+        &MR_edt_depth_step_size, &search_mode, &new_session,
         &words, &word_count, "dd", "dd"))
     {
         ; /* the usage message has already been printed */
@@ -5710,7 +5711,7 @@
         MR_trace_decl_set_fallback_search_mode(search_mode);
 
         if (MR_trace_start_decl_debug(MR_TRACE_DECL_DEBUG,
-            NULL, cmd, event_info, event_details, jumpaddr))
+            NULL, new_session, cmd, event_info, event_details, jumpaddr))
         {
             return STOP_INTERACTING;
         }
@@ -5729,6 +5730,7 @@
     MR_Trace_Mode       trace_mode;
     const char          *filename;
     MR_Decl_Search_Mode search_mode;
+    MR_bool             new_session = MR_TRUE;
 
     MR_trace_decl_assume_all_io_is_tabled = MR_FALSE;
     MR_edt_depth_step_size = MR_TRACE_DECL_INITIAL_DEPTH;
@@ -5736,7 +5738,7 @@
     MR_trace_decl_in_dd_dd_mode = MR_TRUE;
     
     if (! MR_trace_options_dd(&MR_trace_decl_assume_all_io_is_tabled,
-        &MR_edt_depth_step_size, &search_mode,
+        &MR_edt_depth_step_size, &search_mode, &new_session,
         &words, &word_count, "dd", "dd_dd"))
     {
         ; /* the usage message has already been printed */
@@ -5752,7 +5754,7 @@
         MR_trace_decl_set_fallback_search_mode(search_mode);
 
         if (MR_trace_start_decl_debug(trace_mode, filename,
-            cmd, event_info, event_details, jumpaddr))
+            new_session, cmd, event_info, event_details, jumpaddr))
         {
             return STOP_INTERACTING;
         }
@@ -6970,18 +6972,20 @@
     { "assume-all-io-is-tabled",    MR_no_argument,         NULL,   'a' },
     { "depth-step-size",            MR_required_argument,   NULL,   'd' },
     { "search-mode",                MR_required_argument,   NULL,   's' },
+    { "resume",                     MR_required_argument,   NULL,   'r' },
     { NULL,                         MR_no_argument,         NULL,   0 }
 };
 
 static MR_bool
 MR_trace_options_dd(MR_bool *assume_all_io_is_tabled, 
     MR_Integer *depth_step_size, MR_Decl_Search_Mode *search_mode, 
-    char ***words, int *word_count, const char *cat, const char *item)
+    MR_bool *new_session, char ***words, int *word_count, const char *cat,
+    const char *item)
 {
     int c;
 
     MR_optind = 0;
-    while ((c = MR_getopt_long(*word_count, *words, "ad:s:", 
+    while ((c = MR_getopt_long(*word_count, *words, "ad:s:r", 
         MR_trace_dd_opts, NULL)) != EOF)
     {
         switch (c) {
@@ -7004,6 +7008,10 @@
                     MR_trace_usage(cat, item);
                     return MR_FALSE;
                 }
+                break;
+
+            case 'r':
+                *new_session = MR_FALSE;
                 break;
 
             default:
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list