for review: declarative debugger back end

Mark Anthony BROWN dougl at cs.mu.OZ.AU
Thu Dec 10 19:01:50 AEDT 1998


Hello,

Fergus, would you like to review this please?

Without MR_USE_DECLARATIVE_DEBUGGER defined, these changes have no
effect.  Since Zoltan asked me to commit these changes by Friday,
and since they are unlikely to cause problems for anyone, I will
probably commit them later this evening (before review).  I will
address any problems afterwards.  If there are any serious objections,
please say so now!

Cheers,
Mark.


Estimated hours taken: 210

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.

trace/mercury_trace_internal.{c,h}:
	Declare a global variable, MR_trace_decl_mode,  that stores the
	current mode of the internal debugger, and an enum listing the
	possible modes.
	
	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 (new files).



Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.13
diff -u -t -r1.13 mercury_conf_param.h
--- mercury_conf_param.h	1998/11/05 03:53:31	1.13
+++ mercury_conf_param.h	1998/11/26 00:53:41
@@ -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: trace/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/Mmakefile,v
retrieving revision 1.5
diff -u -t -r1.5 Mmakefile
--- Mmakefile	1998/11/15 16:47:50	1.5
+++ Mmakefile	1998/11/26 01:22:35
@@ -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 -t -r1.16 mercury_trace_internal.c
--- mercury_trace_internal.c	1998/11/15 16:47:52	1.16
+++ mercury_trace_internal.c	1998/12/10 06:32:15
@@ -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
@@ -120,6 +115,12 @@
         const char              *MR_var_spec_name;  /* valid if VAR_NAME   */
 } MR_Var_Spec;
 
+#ifdef  MR_USE_DECLARATIVE_DEBUGGER
+
+MR_Trace_Mode MR_trace_decl_mode = MR_TRACE_INTERACTIVE;
+
+#endif  /* MR_USE_DECLARATIVE_DEBUGGER */
+
 static  void    MR_trace_internal_ensure_init(void);
 static  void    MR_trace_internal_init_from_env(void);
 static  void    MR_trace_internal_init_from_local(void);
@@ -144,10 +145,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 +188,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 +217,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 +1177,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 +1428,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 +2280,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 -t -r1.2 mercury_trace_internal.h
--- mercury_trace_internal.h	1998/10/16 06:20:19	1.2
+++ mercury_trace_internal.h	1998/12/10 07:26:15
@@ -7,11 +7,52 @@
 #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;
+
+#ifdef  MR_USE_DECLARATIVE_DEBUGGER
+
+/*
+** The following enum gives the possible modes that the declarative
+** debugger can be in (see trace/mercury_trace_declarative.{c,h}).
+** MR_TRACE_INTERACTIVE indicates the usual operation of the internal
+** debugger.  The other modes refer to what type of analysis is
+** being performed.
+*/
+
+typedef enum {
+        MR_TRACE_INTERACTIVE,
+        MR_TRACE_WRONG_ANSWER
+} MR_Trace_Mode;
+
+/*
+** This variable is modified whenever we start or stop collecting
+** an EDT for a particular type of analysis (see
+** trace/mercury_trace_declarative.c).
+*/
+
+extern  MR_Trace_Mode   MR_trace_decl_mode;
+
+#endif  /* MR_USE_DECLARATIVE_DEBUGGER */
+
 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.
*/

/*
** Main author: Mark Brown
**
** This file implements the back end of the declarative debugger.  The
** back end is an extension to the internal debugger which collects
** related trace events and builds them into an Evaluation Dependency
** Tree (EDT).  Once built, the EDT is passed to the front end where it can
** be analysed to find bugs.
**
** In this incarnation, the front end just dumps the EDT to stdout where
** the user can do manual analysis.
*/

#include "mercury_imp.h"

#ifdef MR_USE_DECLARATIVE_DEBUGGER

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

/*
** We only build the execution tree to a certain depth.  The following
** macro gives the default depth limit (relative to the starting depth).
*/

#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;

	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)) {
		/* XXX this should be handled better. */
		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 {
		/*
		** At this point depth == MR_edt_max_depth.
		*/

		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;

#ifdef 0
		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");
#endif
	}

	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	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;
}

/*
** The following functions do a fairly unpretty print of the EDT.  They
** currently form the front end of the declarative debugger.  In the
** future the front end will be in a separate module to the back, and
** will be much more detailed.  These functions will probably disappear.
*/

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);
}

#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 */



More information about the developers mailing list