for review: declarative debugging back end

Mark Anthony BROWN dougl at cs.mu.OZ.AU
Fri Nov 27 17:38:32 AEDT 1998


Hi,

These are the changes I have been working on to implement the back end
of a declarative debugger under the internal debugger.  The idea is
as follows:

	- add state to the internal debugger, to tell it whether we
	  are collecting a proof tree (MR_TRACE_WRONG_ANSWER) or
	  not (MR_TRACE_INTERACTIVE);
	- add a new command, dd_wrong, which initialises the proof
	  tree and changes the internal debugger state;
	- when collecting a proof tree call MR_trace_decl_wrong_answer
	  from within MR_trace_event_internal instead of reading
	  further mdb commands;
	- when a full proof has been collected, it is passed to the
	  front end (except that since there is no front end yet, I
	  just dump the proof to stdout).

This code is not really ready for review, but since Zoltan is leaving
soon I don't want to leave it too much longer before people see this.
Any comments now will be welcome, but feel free to save them for a
_real_ review at a later stage (Zoltan, I would appreciate any
feedback you have now, though).

Some of the problems I am aware of are:

	- It compiles, but doesn't work, on murlibobo  :(.  I am still
	  yet to figure out why; when I do, I will post another diff.
	  It compiles and runs correctly (at least in some cases) under
	  Linux at home -- I am currently trying to get a version
	  working here.
	- Most of it is poorly documented.
	- I am unsure whether memory is being allocated correctly; I am
	  sure memory is not being deallocated correctly.
	- The goal path is not recorded correctly.
	- I don't think procedure arguments are recorded correctly.
	- Some code to print debugging messages is still in there.
	- The changes in runtime/mercury_trace_base.{c,h} instead
	  probably should be in trace/mercury_trace_internal.{c,h},
	  since they are not used outside the internal debugger.


Cheers,
Mark.


Estimated hours taken: 200

Changes to the internal tracer to implement a declarative
debugging back end.

runtime/mercury_conf_param.h:
	Document the new MR_USE_DECLARATIVE_DEBUGGER configuration
	parameter.

runtime/mercury_trace_base.{c,h}:
	Declare a global variable that stores the current mode of
	the internal debugger, and an enum listing the possible modes.

trace/mercury_trace_internal.{c,h}:
	Move MR_Event_Details and MR_trace_retry into
	mercury_trace_internal.h, and make the latter extern, so that
	the declarative debugger back end can use them.

trace/mercury_trace_internal.c:
	Call the back end in mercury_trace_declarative.c.
	Add a new command, dd_wrong, to start wrong answer analysis.

trace/Mmakefile:
	Add mercury_trace_declarative.{c,h} to the dependencies.

trace/mercury_trace_declarative.{c,h}:
	The declarative debugging back end.



Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.13
diff -u -r1.13 mercury_conf_param.h
--- mercury_conf_param.h	1998/11/05 03:53:31	1.13
+++ mercury_conf_param.h	1998/11/25 12:33:18
@@ -117,6 +117,10 @@
 **	Causes the generated code to become VERY big and VERY inefficient.
 **	Slows down compilation a LOT.
 **
+** MR_USE_DECLARATIVE_DEBUGGER
+**	Enable this if you want declarative debugging support in the
+**	internal debugger.
+**
 ** MR_DEBUG_GOTOS
 **	(Implied by MR_LOWLEVEL_DEBUG.)
 **	Enables low-level debugging of gotos.
Index: runtime/mercury_trace_base.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.c,v
retrieving revision 1.8
diff -u -r1.8 mercury_trace_base.c
--- mercury_trace_base.c	1998/11/19 06:19:19	1.8
+++ mercury_trace_base.c	1998/11/25 12:33:22
@@ -102,6 +102,12 @@
 
 #endif
 
+#ifdef	MR_USE_DECLARATIVE_DEBUGGER
+
+MR_Trace_Mode MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
+
+#endif	/* MR_USE_DECLARATIVE_DEBUGGER */
+
 Code *
 MR_trace(const MR_Stack_Layout_Label *layout, MR_Trace_Port port,
 	const char * path, int max_mr_num)
Index: runtime/mercury_trace_base.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_base.h,v
retrieving revision 1.4
diff -u -r1.4 mercury_trace_base.h
--- mercury_trace_base.h	1998/11/09 10:24:40	1.4
+++ mercury_trace_base.h	1998/11/25 12:33:23
@@ -143,4 +143,15 @@
 
 #endif	/* MR_TRACE_HISTOGRAM */
 
+#ifdef  MR_USE_DECLARATIVE_DEBUGGER
+
+typedef enum {
+	MR_TRACE_INTERACTIVE,
+	MR_TRACE_WRONG_ANSWER
+} MR_Trace_Mode;
+
+extern	MR_Trace_Mode	MR_trace_decl_mode;
+
+#endif	/* MR_USE_DECLARATIVE_DEBUGGER */
+
 #endif /* MERCURY_TRACE_BASE_H */
Index: trace/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/Mmakefile,v
retrieving revision 1.5
diff -u -r1.5 Mmakefile
--- Mmakefile	1998/11/15 16:47:50	1.5
+++ Mmakefile	1998/11/25 12:33:27
@@ -28,6 +28,7 @@
 			mercury_trace.h			\
 			mercury_trace_alias.h		\
 			mercury_trace_browse.h		\
+			mercury_trace_declarative.h	\
 			mercury_trace_external.h 	\
 			mercury_trace_help.h		\
 			mercury_trace_internal.h	\
@@ -40,6 +41,7 @@
 			mercury_trace.c			\
 			mercury_trace_alias.c		\
 			mercury_trace_browse.c		\
+			mercury_trace_declarative.c	\
 			mercury_trace_external.c 	\
 			mercury_trace_help.c		\
 			mercury_trace_internal.c	\
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.16
diff -u -r1.16 mercury_trace_internal.c
--- mercury_trace_internal.c	1998/11/15 16:47:52	1.16
+++ mercury_trace_internal.c	1998/11/25 12:33:47
@@ -13,6 +13,7 @@
 #include "mercury_imp.h"
 #include "mercury_trace.h"
 #include "mercury_trace_internal.h"
+#include "mercury_trace_declarative.h"
 #include "mercury_trace_alias.h"
 #include "mercury_trace_help.h"
 #include "mercury_trace_browse.h"
@@ -98,12 +99,6 @@
 static	MR_Line			*MR_line_head = NULL;
 static	MR_Line			*MR_line_tail = NULL;
 
-typedef struct MR_Event_Details_Struct {
-	int			MR_call_seqno;
-	int			MR_call_depth;
-	int			MR_event_number;
-} MR_Event_Details;
-
 typedef enum {
 	KEEP_INTERACTING,
 	STOP_INTERACTING
@@ -144,10 +139,6 @@
 static	bool	MR_trace_options_confirmed(bool *confirmed, char ***words,
 			int *word_count, const char *cat, const char *item);
 static	void	MR_trace_usage(const char *cat, const char *item);
-static	void	MR_trace_retry(const MR_Stack_Layout_Label *layout,
-			Word *saved_regs, MR_Event_Details *event_details,
-			int seqno, int depth, int *max_mr_num,
-			Code **jumpaddr);
 static	Word	MR_trace_find_input_arg(const MR_Stack_Layout_Label *label,
 			Word *saved_regs, const char *name, bool *succeeded);
 static	void	MR_trace_internal_add_spy_point(MR_Spy_When when,
@@ -191,10 +182,6 @@
 static	void	MR_insert_line_at_head(const char *line);
 static	void	MR_insert_line_at_tail(const char *line);
 
-static	Code	*MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
-			const MR_Stack_Layout_Label *layout, Word *saved_regs,
-			MR_Trace_Port port, int seqno, int depth,
-			const char *path, int *max_mr_num);
 static	void	MR_trace_event_print_internal_report(
 			const MR_Stack_Layout_Label *layout,
 			MR_Trace_Port port, int seqno, int depth,
@@ -224,6 +211,13 @@
 				port, seqno, depth, path, max_mr_num);
 	}
 
+#ifdef	MR_USE_DECLARATIVE_DEBUGGER
+	if (MR_trace_decl_mode == MR_TRACE_WRONG_ANSWER) {
+		return MR_trace_decl_wrong_answer(cmd, layout, saved_regs,
+				port, seqno, depth, path, max_mr_num);
+	}
+#endif	MR_USE_DECLARATIVE_DEBUGGER
+
 	MR_trace_enabled = FALSE;
 	MR_trace_internal_ensure_init();
 
@@ -1177,6 +1171,23 @@
 		} else {
 			MR_trace_usage("misc", "quit");
 		}
+#ifdef	MR_USE_DECLARATIVE_DEBUGGER
+        } else if (streq(words[0], "dd_wrong")) {
+		if (word_count != 1) {
+			fprintf(stderr,
+				"mdb: dd_wrong requires no arguments.\n");
+		} else if (port != MR_PORT_EXIT) {
+			fprintf(stderr, "mdb: wrong answer analysis is only "
+					"available from EXIT events.\n");
+		} else if (MR_trace_start_wrong_answer(cmd, layout,
+				saved_regs, event_details, seqno, depth,
+				max_mr_num, jumpaddr)) {
+			goto return_stop_interacting;
+		} else {
+			fprintf(stderr, "mdb: unable to start declarative "
+					"debugging.\n");
+		}
+#endif  /* MR_USE_DECLARATIVE_DEBUGGER */
 	} else {
 		printf("Unknown command `%s'. "
 			"Give the command `help' for help.\n", words[0]);
@@ -1411,7 +1422,7 @@
 		item, item);
 }
 
-static void
+void
 MR_trace_retry(const MR_Stack_Layout_Label *this_label, Word *saved_regs,
 	MR_Event_Details *event_details, int seqno, int depth,
 	int *max_mr_num, Code **jumpaddr)
@@ -2263,7 +2274,7 @@
 	}
 }
 
-static Code *
+Code *
 MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
 	const MR_Stack_Layout_Label *layout, Word *saved_regs,
 	MR_Trace_Port port, int seqno, int depth, const char *path,
Index: trace/mercury_trace_internal.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_trace_internal.h
--- mercury_trace_internal.h	1998/10/16 06:20:19	1.2
+++ mercury_trace_internal.h	1998/11/25 12:33:47
@@ -7,11 +7,27 @@
 #ifndef	MERCURY_TRACE_INTERNAL_H
 #define	MERCURY_TRACE_INTERNAL_H
 
+typedef struct MR_Event_Details_Struct {
+	int			MR_call_seqno;
+	int			MR_call_depth;
+	int			MR_event_number;
+} MR_Event_Details;
+
 extern	Code	*MR_trace_event_internal(MR_Trace_Cmd_Info *cmd,
 			bool interactive,
 			const MR_Stack_Layout_Label *layout,
 			Word *saved_regs, MR_Trace_Port port,
 			int seqno, int depth,
+			const char *path, int *max_mr_num);
+
+extern	void	MR_trace_retry(const MR_Stack_Layout_Label *layout,
+			Word *saved_regs, MR_Event_Details *event_details,
+			int seqno, int depth, int *max_mr_num,
+			Code **jumpaddr);
+
+extern	Code	*MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
+			const MR_Stack_Layout_Label *layout, Word *saved_regs,
+			MR_Trace_Port port, int seqno, int depth,
 			const char *path, int *max_mr_num);
 
 #endif	/* MERCURY_TRACE_INTERNAL_H */

--- trace/mercury_trace_declarative.c:

/*
** Copyright (C) 1998 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.
*/

/*
** This file contains code to support declarative debugging extensions
** to the internal debugger.
**
** Main author: Mark Brown
*/

#include "mercury_imp.h"

#ifdef MR_USE_DECLARATIVE_DEBUGGER

#include "mercury_trace.h"
#include "mercury_trace_internal.h"
#include "mercury_trace_declarative.h"
#include "mercury_layout_util.h"
#include <stdio.h>

#define MR_EDT_DEPTH_STEP_SIZE		8

/*
** The declarative debugger back end is controlled by the
** settings of the following variables.  They are set in
** MR_trace_start_wrong_answer when the back end is started.  They
** are used by MR_trace_decl_wrong_answer to decide what action to
** take for a particular trace event.  Events that are outside
** the given depth range are ignored.  Events that are beyond the
** given last event cause the internal debugger to be switched
** back into interactive mode.
*/

static	int		MR_edt_min_depth;
static	int		MR_edt_max_depth;
static	int		MR_edt_last_event;

/*
** MR_edt_parent points to the the parent edt_node of a procedure
** that is being called.  When a CALL event occurs, this value is
** saved in a dedicated stackvar (or framevar).  It is then set to
** point to the new edt_node for that procedure, ready to be used
** by CALL events at the next depth down.
*/

static	MR_Edt_Node	*MR_edt_parent;

static void
MR_trace_decl_wrong_answer_call(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot);

static void
MR_trace_decl_wrong_answer_exit(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot);

static void
MR_trace_decl_wrong_answer_redo(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot);

static void
MR_trace_decl_wrong_answer_fail(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot);

static void
MR_trace_decl_update_path(const MR_Stack_Layout_Label *layout, 
		const char *path, int decl_slot);

static void
MR_trace_decl_save_args(const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Edt_Node *edt_node);

static 	void
MR_edt_print(MR_Edt_Node *root, int level);

static 	void
MR_edt_print_node(MR_Edt_Node *node, int level);

static	MR_Edt_Node *
MR_edt_node_construct(const MR_Stack_Layout_Label *layout,
		MR_Edt_Node_Type node_tag, int start_event);

Code *
MR_trace_decl_wrong_answer(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num)
{
	int			decl_slot;
	MR_Stack_Layout_Entry 	*entry = layout->MR_sll_entry;
	MR_Edt_Node		*edt_node;

/*
	MR_trace_event_internal_report(cmd, layout, saved_regs, port, seqno,
			depth, path, max_mr_num);
*/

	if (MR_trace_event_number > MR_edt_last_event) {
		MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
		return MR_trace_event_internal(cmd, TRUE, layout, saved_regs,
				port, seqno, depth, path, max_mr_num);
	}

	if (!MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(entry)) {
		fatal_error("layout has no execution tracing");
	}

	if (depth > MR_edt_max_depth ||
		depth < MR_edt_min_depth ||
		entry->MR_sle_maybe_decl_debug < 1 ) {
		/*
		** We can just ignore any event with a depth outside the
		** range given by MR_edt_{min,max}_depth, or which
		** does not have slots reserved for declarative
		** debugging.
		*/
		return NULL;
	}

	MR_trace_enabled = FALSE;
	decl_slot = entry->MR_sle_maybe_decl_debug;

	switch (port) {
		case MR_PORT_CALL:
			MR_trace_decl_wrong_answer_call(cmd, layout,
					saved_regs, port, seqno, depth, path,
					max_mr_num, decl_slot);
			break;
		case MR_PORT_EXIT:
			MR_trace_decl_wrong_answer_exit(cmd, layout,
					saved_regs, port, seqno, depth, path,
					max_mr_num, decl_slot);
			break;
		case MR_PORT_REDO:
			MR_trace_decl_wrong_answer_redo(cmd, layout,
					saved_regs, port, seqno, depth, path,
					max_mr_num, decl_slot);
			break;
		case MR_PORT_FAIL:
			MR_trace_decl_wrong_answer_fail(cmd, layout,
					saved_regs, port, seqno, depth, path,
					max_mr_num, decl_slot);
			break;
		case MR_PORT_THEN:
		case MR_PORT_ELSE:
		case MR_PORT_DISJ:
		case MR_PORT_SWITCH:
			MR_trace_decl_update_path(layout, path, decl_slot);
		case MR_PORT_PRAGMA_FIRST:
		case MR_PORT_PRAGMA_LATER:
			break;
		default:
			fatal_error("Unknown port type");
	}
	
	if (MR_trace_event_number == MR_edt_last_event) {
		/* Call the front end */
		MR_edt_print(MR_edt_parent->MR_edt_node_children, 0);

		MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
	}

	MR_trace_enabled = TRUE;

	return NULL;
}

static void
MR_trace_decl_wrong_answer_call(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot)
{
	MR_Edt_Node		*edt_node;
	MR_Edt_Node_Type	node_tag;
	MR_Stack_Layout_Entry 	*entry = layout->MR_sll_entry;

	if (depth < MR_edt_max_depth) {
		node_tag = MR_EDT_WRONG_ANSWER_EXPLICIT;
	} else {
		node_tag = MR_EDT_WRONG_ANSWER_IMPLICIT;
	}

	edt_node = MR_edt_node_construct(layout, node_tag,
			MR_trace_event_number);

	if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
		MR_stackvar(decl_slot) = (Word) edt_node;
		MR_stackvar(decl_slot + 1) = (Word) MR_edt_parent;
	} else {
		MR_framevar(decl_slot) = (Word) edt_node;
		MR_framevar(decl_slot + 1) = (Word) MR_edt_parent;
	}
	/*
	** The children of edt_node will refer to the
	** global variable MR_edt_parent to locate their
	** parent.
	*/
	MR_edt_parent = edt_node;
}

static void
MR_trace_decl_wrong_answer_exit(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot)
{
	MR_Edt_Node			*edt_node;
	MR_Stack_Layout_Entry 		*entry = layout->MR_sll_entry;

	if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
		edt_node = (MR_Edt_Node *) MR_stackvar(decl_slot);
		MR_edt_parent = (MR_Edt_Node *) MR_stackvar(decl_slot + 1);
	} else {
		edt_node = (MR_Edt_Node *) MR_framevar(decl_slot);
		MR_edt_parent = (MR_Edt_Node *) MR_framevar(decl_slot + 1);
	}

	edt_node->MR_edt_node_layout = layout;
	edt_node->MR_edt_node_end_event = MR_trace_event_number;
	edt_node->MR_edt_node_seqno = seqno;

	MR_trace_decl_save_args(layout, saved_regs, edt_node);

	/*
	** Attach this node to the child list of its parent.
	*/
	edt_node->MR_edt_node_sibling = MR_edt_parent->MR_edt_node_children;
	MR_edt_parent->MR_edt_node_children = edt_node;
}

static void
MR_trace_decl_wrong_answer_redo(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot)
{
	MR_Edt_Node		*edt_node;
	MR_Stack_Layout_Entry 	*entry = layout->MR_sll_entry;

	/*
	** Re-use the node that was allocated at the CALL event.
	*/
	if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
		edt_node = (MR_Edt_Node *) MR_stackvar(decl_slot);
		MR_edt_parent = (MR_Edt_Node *) MR_stackvar(decl_slot + 1);
	} else {
		edt_node = (MR_Edt_Node *) MR_framevar(decl_slot);
		MR_edt_parent = (MR_Edt_Node *) MR_framevar(decl_slot + 1);
	}

	/*
	** Remove the nodes that we have bactracked over.  Since we have
	** a REDO event for this goal, we must have had an EXIT event
	** earlier, therefore the current node is known to be attached
	** to the current parent.
	**
	** XXX need to deallocate properly.
	*/
	if (MR_edt_parent != NULL ) {
		MR_edt_parent->MR_edt_node_children =
				edt_node->MR_edt_node_sibling;
	}

	MR_edt_parent = edt_node;
}

static void
MR_trace_decl_wrong_answer_fail(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Trace_Port port, int seqno, int depth, const char *path,
		int *max_mr_num, int decl_slot)
{
	MR_Edt_Node		*edt_node;
	MR_Stack_Layout_Entry 	*entry = layout->MR_sll_entry;

	if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
		edt_node = (MR_Edt_Node *) MR_stackvar(decl_slot);
		MR_edt_parent = (MR_Edt_Node *) MR_stackvar(decl_slot + 1);
	} else {
		edt_node = (MR_Edt_Node *) MR_framevar(decl_slot);
		MR_edt_parent = (MR_Edt_Node *) MR_framevar(decl_slot + 1);
	}
	deallocate_memory(edt_node);
}

/*
** MR_trace_decl_update_path adds to the record of the execution path
** taken for the current edt_node.
**
** XXX It currently just overwrites all but the last path seen.  If
** the goal is a conjunction of two disjunctions, only the path 
** through the second disjunction is remembered.
*/
static void
MR_trace_decl_update_path(const MR_Stack_Layout_Label *layout, 
		const char *path, int decl_slot)
{
	MR_Edt_Node	*edt_node;

	if (MR_DETISM_DET_STACK(layout->MR_sll_entry->MR_sle_detism)) {
		edt_node = (MR_Edt_Node *) MR_stackvar(decl_slot);
	} else {
		edt_node = (MR_Edt_Node *) MR_framevar(decl_slot);
	}
	edt_node->MR_edt_node_path = path;
}

static void
MR_trace_decl_save_args(const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Edt_Node *edt_node)
{
	Word				*arg_values;
	Word				*arg_types;
	int				arg_count;
	const MR_Stack_Layout_Vars	*vars;
	Word				*base_sp;
	Word				*base_curfr;
	Word				*type_params;
	const MR_Stack_Layout_Var	*var;
	MR_Live_Lval			locn;
	int				i;
	bool				succeeded;
	Word				*pseudo_type_info;
	Word				type_info;

	arg_count = layout->MR_sll_var_count;
	if (arg_count < 0) {
		printf("mdb: no info about live variables.\n");
		edt_node->MR_edt_node_arg_values = NULL;
		edt_node->MR_edt_node_arg_types = NULL;
		return;
	}
	arg_values = allocate_array(Word, arg_count);
	arg_types = allocate_array(Word, arg_count);
	vars = &layout->MR_sll_var_info;
	base_sp = MR_saved_sp(saved_regs);
	base_curfr = MR_saved_curfr(saved_regs);
	type_params = MR_materialize_typeinfos_base(vars, saved_regs, 
			base_sp, base_curfr);
	for (i = 0; i < arg_count; i++) {
		var = &vars->MR_slvs_pairs[i];
		MR_get_type_and_value_base(var, saved_regs, base_sp,
				base_curfr, type_params, &arg_types[i],
				&arg_values[i]);
		locn = var->MR_slv_locn;
/*
		printf("var %d: lval type = %d, "
				"lval number = %d, value = ",
				i,
				MR_LIVE_LVAL_TYPE(locn),
				MR_LIVE_LVAL_NUMBER(locn)
		);
		MR_write_variable(arg_types[i], arg_values[i]);
		printf("\n");
*/
	}

	edt_node->MR_edt_node_arg_values = arg_values;
	edt_node->MR_edt_node_arg_types = arg_types;
}

bool
MR_trace_start_wrong_answer(MR_Trace_Cmd_Info *cmd, 
		const MR_Stack_Layout_Label *layout, Word *saved_regs,
		MR_Event_Details *event_details, int seqno, int depth,
		int *max_mr_num, Code **jumpaddr)
{
	MR_Stack_Layout_Entry 	*entry = layout->MR_sll_entry;
	int			decl_slot;

	if (!MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(entry)) {
		return FALSE;
	}

	decl_slot = entry->MR_sle_maybe_decl_debug;
	if (decl_slot < 1) {
		/* No slots are reserved for declarative debugging */
		return FALSE;
	}

	MR_trace_decl_mode = MR_TRACE_WRONG_ANSWER;
	MR_edt_parent = MR_edt_node_construct(NULL,
			MR_EDT_WRONG_ANSWER_EXPLICIT, 0);
	MR_edt_last_event = MR_trace_event_number;
	MR_edt_min_depth = depth;
	MR_edt_max_depth = depth + MR_EDT_DEPTH_STEP_SIZE;

	MR_trace_retry(layout, saved_regs, event_details, seqno, depth,
			max_mr_num, jumpaddr);

	cmd->MR_trace_cmd = MR_CMD_GOTO;
	cmd->MR_trace_stop_event = MR_trace_event_number + 1;
	cmd->MR_trace_strict = FALSE;
	cmd->MR_trace_print_level = MR_PRINT_LEVEL_ALL;

	return TRUE;
}

static void
MR_edt_print(MR_Edt_Node *root, int level)
{
	int i;

	if (root->MR_edt_node_sibling != NULL) {
		MR_edt_print(root->MR_edt_node_sibling, level);
	}

	MR_edt_print_node(root, level);

	if (root->MR_edt_node_tag == MR_EDT_WRONG_ANSWER_IMPLICIT) {
		for (i = 0; i < level + 1; i++) {
			printf("    ");
		}
		printf("/* implicit */\n");
	}

	if (root->MR_edt_node_children != NULL) {
		MR_edt_print(root->MR_edt_node_children, level + 1);
	}
}

static void
MR_edt_print_node(MR_Edt_Node *node, int level)
{
	int i;

	for (i = 0; i < level; i++) {
		printf("    ");
	}
	printf("(");
	MR_write_variable(node->MR_edt_node_arg_types[0],
			node->MR_edt_node_arg_values[0]);
	for (i = 1; i < node->MR_edt_node_layout->MR_sll_var_count; i++) {
		printf(", ");
		MR_write_variable(node->MR_edt_node_arg_types[i],
				node->MR_edt_node_arg_values[i]);
	}
	printf(") ");
	if (node->MR_edt_node_path != NULL) {
		printf("%s ", node->MR_edt_node_path);
	}
	MR_print_proc_id_for_debugger(node->MR_edt_node_layout->MR_sll_entry);
}

static	MR_Edt_Node *
MR_edt_node_construct(const MR_Stack_Layout_Label *layout,
		MR_Edt_Node_Type node_tag, int start_event)
{
	MR_Edt_Node 	*edt_node;

	edt_node = allocate_object(MR_Edt_Node);
	edt_node->MR_edt_node_tag = node_tag;
	edt_node->MR_edt_node_layout = layout;
	edt_node->MR_edt_node_path = NULL;
	edt_node->MR_edt_node_start_event = start_event;
	edt_node->MR_edt_node_children = NULL;
	edt_node->MR_edt_node_sibling = NULL;

	return edt_node;
}

#endif	/* MR_USE_DECLARATIVE_DEBUGGER */


--- trace/mercury_trace_declarative.h:

/*
** Copyright (C) 1998 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.
*/

#include "mercury_imp.h"

#ifndef MERCURY_TRACE_DECLARATIVE_H
#define MERCURY_TRACE_DECLARATIVE_H

/*
** This file defines the MR_Edt_Node data type, which stores nodes
** of an Evaluation Dependency Tree (EDT), used for declarative
** debugging.  It also defines an interface to the back end of the
** declarative debugger from the internal debugger.
*/

/*
** Each node in an EDT has a tag to denote its type.  At the moment
** the only type of analysis is wrong answer analysis, so the tag
** is just used to distinguish between implicitly and explicitly
** represented nodes.
**
** Implicit nodes are similar to explicit nodes, but they do not
** store their children.  The children can be created by re-executing
** the events in the stored range and collecting a new EDT.
*/

typedef enum {
	MR_EDT_WRONG_ANSWER_EXPLICIT,
	MR_EDT_WRONG_ANSWER_IMPLICIT
} MR_Edt_Node_Type;

/*
** Wrong answer analysis is currently the only type of analysis available.
** Consequently, the EDT nodes only contain enough information to support
** this type of analysis.
*/

typedef struct MR_Edt_Node_Struct MR_Edt_Node;

struct MR_Edt_Node_Struct {
						/*
						** Type of EDT node.
						*/
	MR_Edt_Node_Type		MR_edt_node_tag;
						/*
						** The layout of the EXIT port.
						*/
	const MR_Stack_Layout_Label	*MR_edt_node_layout;
						/*
						** The arguments.
						*/
	Word				*MR_edt_node_arg_values;
	Word				*MR_edt_node_arg_types;
	const char			*MR_edt_node_path;
						/*
						** The event numbers of the
						** CALL and EXIT events for
						** this proof.
						*/
	int				MR_edt_node_start_event;
	int				MR_edt_node_end_event;
						/*
						** The sequence number of the
						** CALL and EXIT events.
						*/
	int				MR_edt_node_seqno;
						/*
						** The rightmost child of this
						** node, or NULL if there are
						** no children.
						*/
	MR_Edt_Node			*MR_edt_node_children;
						/*
						** The next sibling to the
						** left of this node, or NULL
						** if this is the leftmost.
						*/
	MR_Edt_Node			*MR_edt_node_sibling;
};

/*
** When in declarative debugging mode, the internal debugger calls
** MR_trace_decl_wrong_answer for each event.  
*/

extern	Code	*MR_trace_decl_wrong_answer(MR_Trace_Cmd_Info *cmd,
			const MR_Stack_Layout_Label *layout,
			Word *saved_regs, MR_Trace_Port port,
			int seqno, int depth,
			const char *path, int *max_mr_num);

/*
** The internal (interactive) debugger calls this to change to
** declarative debugging mode.
*/

extern	bool	MR_trace_start_wrong_answer(MR_Trace_Cmd_Info *cmd,
			const MR_Stack_Layout_Label *layout,
			Word *saved_regs, MR_Event_Details *event_details,
			int seqno, int depth, int *max_mr_num,
			Code **jumpaddr);

#endif	/* MERCURY_TRACE_DECLARATIVE_H */

--
Mark Brown  (dougl at cs.mu.oz.au)       )O+   |  For Microsoft to win,
MEngSc student,                             |  the customer must lose
Dept of Computer Science, Melbourne Uni     |          -- Eric S. Raymond



More information about the developers mailing list