for review: new debugger command set, part 2

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Jul 6 19:17:07 AEST 1998


Index: runtime/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_internal.c,v
retrieving revision 1.7
diff -u -u -r1.7 mercury_trace_internal.c
--- mercury_trace_internal.c	1998/06/18 06:08:12	1.7
+++ mercury_trace_internal.c	1998/07/06 10:10:58
@@ -14,36 +14,57 @@
 #include "mercury_trace.h"
 #include "mercury_trace_internal.h"
 #include "mercury_trace_util.h"
+#include "mercury_trace_spy.h"
+#include "mercury_trace_tables.h"
 #include <stdio.h>
 #include <ctype.h>
+#include <unistd.h>
 
+extern	int	optind;
+
 #define	MR_isdigit(c)	isdigit((unsigned char) (c))
 #define	MR_isspace(c)	isspace((unsigned char) (c))
 
-#define	MR_NAME_LEN		80
-#define	MR_MAX_SPY_POINTS	100
-#define	MR_LOG10_MAX_SPY_POINTS	20
-
 #define	MR_MAX_LINE_LEN		256
+
+#define	MR_INIT_SPY_POINTS	10
 
-typedef struct {
-	bool	enabled;
-	char	module_name[MR_NAME_LEN];
-	char	pred_name[MR_NAME_LEN];
-} MR_spy_point;
+static	MR_Spy_Point    	**MR_spy_points;
+static	int			MR_spy_point_next = 0;
+static	int			MR_spy_point_max  = 0;
+
+static	MR_Trace_Print_Level	MR_default_print_level = MR_PRINT_LEVEL_SOME;
+
+static	bool			MR_scroll_control = FALSE;
+static	int			MR_scroll_next = 0;
+static	int			MR_scroll_limit = 20;
+static	bool			MR_echo_commands = FALSE;
+
+static	int			MR_trace_saved_call_seqno;
+static	int			MR_trace_saved_call_depth;
+static	int			MR_trace_saved_event_number;
 
 typedef enum {
 	KEEP_INTERACTING,
 	STOP_INTERACTING
 } MR_next;
 
-static	MR_spy_point	MR_spy_points[MR_MAX_SPY_POINTS];
-static	int		MR_next_spy_point = 0;
-
-static	MR_next	MR_trace_debug_cmd(MR_trace_cmd_info *cmd,
+static	void	MR_trace_internal_ensure_init(void);
+static	MR_next	MR_trace_debug_cmd(MR_Trace_Cmd_Info *cmd,
 			const MR_Stack_Layout_Label *layout,
-			MR_trace_port port, int seqno, int depth,
+			MR_Trace_Port port, int seqno, int depth,
 			const char *path, int *ancestor_level);
+static	bool	MR_trace_options_strict_print(MR_Trace_Cmd_Info *cmd,
+			char ***words, int *word_count, const char *usage);
+static	bool	MR_trace_options_when_action(MR_Spy_When *when,
+			MR_Spy_Action *action, char ***words, int *word_count,
+			const char *usage);
+static	void	MR_trace_restart(const MR_Stack_Layout_Label *layout,
+			int seqno, int depth);
+static	Word	MR_trace_find_input_arg(const MR_Stack_Layout_Label *label,
+			const char *name, bool *succeeded);
+static	void	MR_ensure_room_for_spy_point(void);
+static	void	MR_print_spy_point(int i);
 static	void	MR_trace_list_vars(const MR_Stack_Layout_Label *top_layout,
 			int ancestor_level);
 static	void	MR_trace_browse_one(const MR_Stack_Layout_Label *top_layout,
@@ -59,33 +80,75 @@
 static	bool	MR_trace_is_number(char *word, int *value);
 static	bool	MR_trace_is_number_prefix(char *word, char **suffix,
 			int *value);
-static	int	MR_trace_break_into_words(char line[], char *words[]);
-static	int	MR_trace_getline(FILE *file, char line[], int line_max);
+static	const char *MR_trace_parse_line(char *line,
+			char ***words_ptr, int *word_count_ptr);
+static	int	MR_trace_break_into_words(char *line,
+			char ***words_ptr, int *words_max);
+static	char	*MR_trace_getline(FILE *file);
 
-static	void	MR_trace_print_port(MR_trace_port port);
-static	void	MR_trace_print_detism(Word detism);
+static	void	MR_trace_event_print_internal_report(
+			const MR_Stack_Layout_Label *layout,
+			MR_Trace_Port port, int seqno, int depth,
+			const char *path);
+static	void	MR_trace_print_port(MR_Trace_Port port);
+
+/* If you add a usage message, add it to MR_trace_help as well. */
+static	char	step_usage[] = "step [-NSans] [<number>]";
+static	char	goto_usage[] = "goto [-NSans] <number>";
+static	char	finish_usage[] = "finish [-NSans]";
+static	char	forward_usage[] = "forward [-NSans]";
+static	char	continue_usage[] = "continue [-NSans]";
+static	char	restart_usage[] = "restart";
+static	char	level_usage[] = "level <number>";
+static	char	up_usage[] = "up <number>";
+static	char	down_usage[] = "down <number>";
+static	char	vars_usage[] = "vars";
+static	char	print_usage[] = "print (<number> | *)";
+static	char	stack_usage[] = "stack";
+static	char	stack_regs_usage[] = "stack_regs";
+static	char	break_usage[] = "break (info | [-PSaei] (<module> <pred> [<arity> [<mode>]] | here))";
+static	char	enable_usage[] = "enable (<number> | *)";
+static	char	disable_usage[] = "disable (<number> | *)";
+static	char	register_usage[] = "register";
+static	char	module_table_usage[] = "module_table";
+#ifdef	MR_TRACE_HISTOGRAM
+static	char	histogram_all_usage[] = "histogram_all";
+static	char	histogram_exp_usage[] = "histogram_exp";
+static	char	clear_histogram_usage[] = "clear_histogram";
+#endif
+static	char	printlevel_usage[] = "printlevel [none | some | all]";
+static	char	scroll_usage[] = "scroll [on | off]";
+static	char	echo_usage[] = "echo [on | off]";
+static	char	help_usage[] = "help";
+static	char	quit_usage[] = "quit";
 
 void
-MR_trace_event_internal(MR_trace_cmd_info *cmd,
+MR_trace_event_internal(MR_Trace_Cmd_Info *cmd,
 	const MR_Stack_Layout_Label *layout,
-	MR_trace_port port, int seqno, int depth, const char *path)
+	MR_Trace_Port port, int seqno, int depth, const char *path)
 {
 	int	i;
 	int	c;
 	int	count;
 	bool	count_given;
-	Word	saved_seqno;
-	Word	saved_depth;
-	Word	saved_event;
 	int	ancestor_level;
 
-	MR_trace_event_internal_report(layout, port, seqno, depth, path);
+	MR_trace_internal_ensure_init();
 
-	/* these globals can be overwritten when we call Mercury code */
-	saved_seqno = MR_trace_call_seqno;
-	saved_depth = MR_trace_call_depth;
-	saved_event = MR_trace_event_number;
+	MR_trace_event_print_internal_report(layout, port, seqno, depth, path);
 
+	/*
+	** These globals can be overwritten when we call Mercury code,
+	** such as the term browser. We therefore save and restore them
+	** across calls to MR_trace_debug_cmd. However, we store the
+	** saved values in global instead of local variables, to allow them
+	** to be modified by MR_trace_restart().
+	*/
+
+	MR_trace_saved_call_seqno = MR_trace_call_seqno;
+	MR_trace_saved_call_depth = MR_trace_call_depth;
+	MR_trace_saved_event_number = MR_trace_event_number;
+
 	/* by default, print variables from the current procedure */
 	ancestor_level = 0;
 
@@ -93,211 +156,243 @@
 			&ancestor_level) == KEEP_INTERACTING) {
 		; /* all the work is done in MR_trace_debug_cmd */
 	}
+
+	cmd->MR_trace_must_check = (! cmd->MR_trace_strict) ||
+			(cmd->MR_trace_print_level != MR_PRINT_LEVEL_NONE);
+
+	MR_trace_call_seqno = MR_trace_saved_call_seqno;
+	MR_trace_call_depth = MR_trace_saved_call_depth;
+	MR_trace_event_number = MR_trace_saved_event_number;
 
-	MR_trace_call_seqno = saved_seqno;
-	MR_trace_call_depth = saved_depth;
-	MR_trace_event_number = saved_event;
+	MR_scroll_next = 1;
 }
 
+static void
+MR_trace_internal_ensure_init(void)
+{
+	static	bool	done = FALSE;
+
+	if (! done) {
+		printf("Melbourne Mercury Debugger\n");
+		done = TRUE;
+	}
+}
+
 static MR_next
-MR_trace_debug_cmd(MR_trace_cmd_info *cmd, const MR_Stack_Layout_Label *layout,
-	MR_trace_port port, int seqno, int depth, const char *path,
+MR_trace_debug_cmd(MR_Trace_Cmd_Info *cmd, const MR_Stack_Layout_Label *layout,
+	MR_Trace_Port port, int seqno, int depth, const char *path,
 	int *ancestor_level)
 {
-	char	line[MR_MAX_LINE_LEN];
-	char	count_buf[MR_MAX_LINE_LEN];
-	char	*raw_words[MR_MAX_LINE_LEN / 2 + 1];
-	char	**words;
-	char	raw_word_count;
-	char	word_count;
-	char	*s;
-	int	i, n;
+	char		*line;
+	char		**words;
+	char		**orig_words;
+	int		word_count;
+	const char	*problem;
+	int		i;
+	int		n;
 
-	printf("mtrace> ");
+	printf("mdb> ");
 
-	if (MR_trace_getline(stdin, line, MR_MAX_LINE_LEN) == 0) {
+	line = MR_trace_getline(stdin);
+
+	if (line == NULL) {
 		/*
-		** We got a line without even a newline character,
-		** which must mean that the user typed EOF.
+		** We got an EOF.
 		** We arrange things so we don't have to treat this case
 		** specially in the command interpreter below.
 		*/
 
-		(void) strcpy(line, "a\n");
+		line = checked_malloc(sizeof("quit\n") + 1);
+		(void) strcpy(line, "quit\n");
 	}
 
-	/*
-	** Handle a possible number prefix on the first word on the line,
-	** separating it out into a word on its own.
-	*/
-
-	raw_word_count = MR_trace_break_into_words(line, raw_words + 1);
-
-	if (raw_word_count > 0 && MR_isdigit(*raw_words[1])) {
-		i = 0;
-		s = raw_words[1];
-		while (MR_isdigit(*s)) {
-			count_buf[i] = *s;
-			i++;
-			s++;
-		}
-
-		count_buf[i] = '\0';
-
-		if (*s == '\0') {
-			/* all of the first word constitutes a number */
-			/* exchange it with the command, if it exists */
-
-			if (raw_word_count > 1) {
-				s = raw_words[1];
-				raw_words[1] = raw_words[2];
-				raw_words[2] = s;
-			}
-
-			words = raw_words + 1;
-			word_count = raw_word_count;
-		} else {
-			/* only part of the first word constitutes a number */
-			/* put it in an extra word at the start */
-
-			raw_words[0] = count_buf;
-			raw_words[1] = s;
-			words = raw_words;
-			word_count = raw_word_count + 1;
-		}
-	} else {
-		words = raw_words + 1;
-		word_count = raw_word_count;
+	if (MR_echo_commands) {
+		fputs(line, stdout);
 	}
-
-	/*
-	** If the first word is a number, try to exchange it
-	** with the command word, to put the command word first.
-	*/
 
-	if (word_count > 1 && MR_trace_is_number(words[0], &n)
-			&& ! MR_trace_is_number(words[1], &n)) {
-		s = words[0];
-		words[0] = words[1];
-		words[1] = s;
+	problem = MR_trace_parse_line(line, &words, &word_count);
+	if (problem != NULL) {
+		printf("%s\n", problem);
+		goto return_keep_interacting;
 	}
 
 	/*
 	** At this point, the first word_count members of the words
-	** array contain the command.
+	** array contain the command. We save the value of words for
+	** freeing just before return, since the variable words itself
+	** can be overwritten by option processing.
 	*/
-
-	cmd->MR_trace_print_intermediate = FALSE;
 
+	orig_words = words;
 	if (word_count == 0) {
 		cmd->MR_trace_cmd = MR_CMD_GOTO;
-		cmd->MR_trace_print_intermediate = FALSE;
 		cmd->MR_trace_stop_event = MR_trace_event_number + 1;
-		return STOP_INTERACTING;
+		cmd->MR_trace_strict = FALSE;
+		cmd->MR_trace_print_level = MR_default_print_level;
+		goto return_stop_interacting;
 	} else if (MR_trace_is_number(words[0], &n)) {
 		if (word_count == 1) {
 			cmd->MR_trace_cmd = MR_CMD_GOTO;
-			cmd->MR_trace_print_intermediate = FALSE;
 			cmd->MR_trace_stop_event = MR_trace_event_number + n;
-			return STOP_INTERACTING;
+			cmd->MR_trace_strict = FALSE;
+			cmd->MR_trace_print_level = MR_default_print_level;
+			goto return_stop_interacting;
 		} else {
 			printf("One of the first two words "
 				"must be a command.\n");
 		}
-	} else if (streq(words[0], "S") || streq(words[0], "s")) {
-		if (word_count == 1) {
+	} else if (streq(words[0], "step")) {
+		cmd->MR_trace_strict = FALSE;
+		cmd->MR_trace_print_level = MR_default_print_level;
+		if (! MR_trace_options_strict_print(cmd, &words, &word_count,
+				step_usage)) {
+			; /* the usage message has already been printed */
+		} else if (word_count == 1) {
 			cmd->MR_trace_cmd = MR_CMD_GOTO;
-			cmd->MR_trace_print_intermediate = streq(words[0], "S");
 			cmd->MR_trace_stop_event = MR_trace_event_number + 1;
-			return STOP_INTERACTING;
+			goto return_stop_interacting;
 		} else if (word_count == 2
 				&& MR_trace_is_number(words[1], &n)) {
 			cmd->MR_trace_cmd = MR_CMD_GOTO;
-			cmd->MR_trace_print_intermediate = streq(words[0], "S");
 			cmd->MR_trace_stop_event = MR_trace_event_number + n;
-			return STOP_INTERACTING;
+			goto return_stop_interacting;
 		} else {
-			printf("This command expects at most one argument,\n"
-				"which must be a number.\n");
+			printf("Usage: %s\n", step_usage);
 		}
-	} else if (streq(words[0], "g") || streq(words[0], "G")) {
-		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
+	} else if (streq(words[0], "goto")) {
+		cmd->MR_trace_strict = FALSE;
+		cmd->MR_trace_print_level = MR_default_print_level;
+		if (! MR_trace_options_strict_print(cmd, &words, &word_count,
+				goto_usage)) {
+			; /* the usage message has already been printed */
+		} else if (word_count == 2 && MR_trace_is_number(words[1], &n))
+				{
 			if (MR_trace_event_number < n) {
 				cmd->MR_trace_cmd = MR_CMD_GOTO;
-				cmd->MR_trace_print_intermediate =
-					streq(words[0], "G");
 				cmd->MR_trace_stop_event = n;
-				return STOP_INTERACTING;
+				goto return_stop_interacting;
 			} else {
 				printf("The debugger cannot go "
 					"to a past event.\n");
 			}
 		} else {
-			printf("This command expects exactly one argument,\n");
-			printf("which must be a number.\n");
+			printf("Usage: %s\n", goto_usage);
 		}
-	} else if (streq(words[0], "f") || streq(words[0], "F")) {
-		if (word_count == 1) {
+	} else if (streq(words[0], "finish")) {
+		cmd->MR_trace_strict = TRUE;
+		cmd->MR_trace_print_level = MR_default_print_level;
+		if (! MR_trace_options_strict_print(cmd, &words, &word_count,
+				finish_usage)) {
+			; /* the usage message has already been printed */
+		} else if (word_count == 1) {
 			if (MR_port_is_final(port)) {
 				printf("This command is a no-op "
 					"from this port.\n");
 			} else {
 				cmd->MR_trace_cmd = MR_CMD_FINISH;
-				cmd->MR_trace_print_intermediate =
-					streq(words[0], "F");
 				cmd->MR_trace_stop_seqno = seqno;
-				return STOP_INTERACTING;
+				cmd->MR_trace_strict = TRUE;
+				goto return_stop_interacting;
 			}
 		} else {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", finish_usage);
 		}
-	} else if (streq(words[0], "c") || streq(words[0], "C")) {
-		if (word_count == 1) {
+	} else if (streq(words[0], "forward")) {
+		cmd->MR_trace_strict = TRUE;
+		cmd->MR_trace_print_level = MR_default_print_level;
+		if (! MR_trace_options_strict_print(cmd, &words, &word_count,
+				forward_usage)) {
+			; /* the usage message has already been printed */
+		} else if (word_count == 1) {
+			cmd->MR_trace_cmd = MR_CMD_RESUME_FORWARD;
+			goto return_stop_interacting;
+		} else {
+			printf("Usage: %s\n", forward_usage);
+		}
+	} else if (streq(words[0], "continue")) {
+		cmd->MR_trace_strict = FALSE;
+		cmd->MR_trace_print_level = (MR_Trace_Cmd_Type) -1;
+		if (! MR_trace_options_strict_print(cmd, &words, &word_count,
+				continue_usage)) {
+			; /* the usage message has already been printed */
+		} else if (word_count == 1) {
 			cmd->MR_trace_cmd = MR_CMD_TO_END;
-			cmd->MR_trace_print_intermediate =
-				streq(words[0], "C");
-			return STOP_INTERACTING;
+			if (cmd->MR_trace_print_level ==
+					(MR_Trace_Cmd_Type) -1) {
+				/*
+				** The user did not specify the print level;
+				** select the intelligent default.
+				*/
+				if (cmd->MR_trace_strict) {
+					cmd->MR_trace_print_level =
+						MR_PRINT_LEVEL_NONE;
+				} else {
+					cmd->MR_trace_print_level =
+						MR_PRINT_LEVEL_SOME;
+				}
+			}
+			goto return_stop_interacting;
 		} else {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", continue_usage);
 		}
-	} else if (streq(words[0], "r") || streq(words[0], "R")) {
+	} else if (streq(words[0], "restart")) {
 		if (word_count == 1) {
-			cmd->MR_trace_cmd = MR_CMD_RESUME_FORWARD;
-			cmd->MR_trace_print_intermediate =
-				streq(words[0], "R");
-			return STOP_INTERACTING;
+			if (! MR_port_is_final(port)) {
+				printf("For technical reasons, "
+					"it is not yet possible to "
+					"restart from a non-final port.\n");
+			}
+
+			MR_trace_restart(layout, seqno, depth);
+
+			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_default_print_level;
+			goto return_stop_interacting;
 		} else {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", restart_usage);
 		}
-	} else if (streq(words[0], "l")) {
+	} else if (streq(words[0], "level")) {
 		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
 			*ancestor_level = n;
 			printf("Ancestor level set to %d\n", n);
 		} else {
-			printf("This command expects one argument,\n");
-			printf("a number denoting an ancestor level.\n");
+			printf("Usage: %s\n", level_usage);
 		}
-	} else if (streq(words[0], "v")) {
+	} else if (streq(words[0], "up")) {
+		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
+			*ancestor_level += n;
+			printf("Ancestor level set to %d\n", n);
+		} else {
+			printf("Usage: %s\n", up_usage);
+		}
+	} else if (streq(words[0], "down")) {
+		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
+			*ancestor_level -= n;
+			printf("Ancestor level set to %d\n", n);
+		} else {
+			printf("Usage: %s\n", down_usage);
+		}
+	} else if (streq(words[0], "vars")) {
 		if (word_count == 1) {
 			MR_trace_list_vars(layout, *ancestor_level);
 		} else {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", vars_usage);
 		}
-	} else if (streq(words[0], "p")) {
+	} else if (streq(words[0], "print")) {
 		if (word_count == 2) {
 			if (MR_trace_is_number(words[1], &n)) {
 				MR_trace_browse_one(layout, *ancestor_level, n);
 			} else if streq(words[1], "*") {
 				MR_trace_browse_all(layout, *ancestor_level);
 			} else {
-				printf("The argument of this command should be,\n");
-				printf("a variable number or a '*' indicating all variables.\n");
+				printf("Usage: %s\n", print_usage);
 			}
 		} else {
-			printf("This command expects one argument,\n");
-			printf("a variable number or a '*' indicating all variables.\n");
+			printf("Usage: %s\n", print_usage);
 		}
-	} else if (streq(words[0], "d")) {
+	} else if (streq(words[0], "stack")) {
 		if (word_count == 1) {
 			const char	*result;
 
@@ -310,110 +405,299 @@
 				printf("%s\n", result);
 			}
 		} else {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", stack_usage);
 		}
-	} else if (streq(words[0], "X")) {
-		printf("sp = %p, curfr = %p, maxfr = %p\n",
-			MR_saved_sp(MR_saved_regs),
-			MR_saved_curfr(MR_saved_regs),
-			MR_saved_maxfr(MR_saved_regs));
-	} else if (streq(words[0], "b")) {
-		if (word_count != 3) {
-			printf("This command expects two arguments,\n");
-			printf("a module name and a predicate name.\n");
-		} else {
-			if (MR_next_spy_point >= MR_MAX_SPY_POINTS) {
-				printf("There is no room "
-					"for any more spy points.\n");
-			} else {
-				printf("%2d: %s %s:%s\n", MR_next_spy_point,
-					"+", words[1], words[2]);
-				strcpy(MR_spy_points[MR_next_spy_point]
-					.module_name, words[1]);
-				strcpy(MR_spy_points[MR_next_spy_point]
-					.pred_name, words[2]);
-				MR_spy_points[MR_next_spy_point].enabled
-					= TRUE;
-				MR_next_spy_point++;
-			}
-		}
-	} else if (streq(words[0], "?")) {
-		for (i = 0; i < MR_next_spy_point; i++) {
-			printf("%2d: %s %s:%s\n", i,
-				MR_spy_points[i].enabled ? "+" : "-",
-				MR_spy_points[i].module_name,
-				MR_spy_points[i].pred_name);
+	} else if (streq(words[0], "stack_regs")) {
+		if (word_count == 1) {
+			printf("sp = %p, curfr = %p, maxfr = %p\n",
+				MR_saved_sp(MR_saved_regs),
+				MR_saved_curfr(MR_saved_regs),
+				MR_saved_maxfr(MR_saved_regs));
+		} else {
+			printf("Usage: %s\n", stack_regs_usage);
 		}
-	} else if (streq(words[0], "+")) {
-		if (word_count == 2) {
-			if (MR_trace_is_number(words[1], &n)) {
-				if (0 <= n && n < MR_next_spy_point) {
-					MR_spy_points[n].enabled = TRUE;
-					printf("%2d: %s %s:%s\n", n,
-						"+",
-						MR_spy_points[n].module_name,
-						MR_spy_points[n].pred_name);
+	} else if (streq(words[0], "break")) {
+		MR_Spy_When	when;
+		MR_Spy_Action	action;
+		int		arity;
+		int		mode;
+
+		if (word_count == 2 && streq(words[1], "info")) {
+			for (i = 0; i < MR_spy_point_next; i++) {
+				MR_print_spy_point(i);
+			}
+
+			goto return_keep_interacting;
+		}
+
+		when = MR_SPY_INTERFACE;
+		action = MR_SPY_STOP;
+		if (! MR_trace_options_when_action(&when, &action,
+				&words, &word_count, break_usage)) {
+			; /* the usage message has already been printed */
+		} else if (word_count == 2 && streq(words[1], "here")) {
+			MR_register_all_modules_and_procs(stdout);
+			MR_ensure_room_for_spy_point();
+			MR_spy_points[MR_spy_point_next] = MR_add_spy_point(
+				MR_SPY_SPECIFIC, action,
+				layout->MR_sll_entry, layout,
+				path);
+			MR_print_spy_point(MR_spy_point_next);
+			MR_spy_point_next++;
+		} else if (word_count == 3) {
+			const MR_Stack_Layout_Entry	*spy_proc;
+			bool				unique;
+
+			MR_register_all_modules_and_procs(stdout);
+			spy_proc = MR_search_for_module_proc(words[1], words[2],
+						&unique);
+			if (spy_proc != NULL) {
+				if (unique) {
+					MR_ensure_room_for_spy_point();
+					MR_spy_points[MR_spy_point_next] =
+							MR_add_spy_point(
+								when, action,
+								spy_proc, NULL,
+								path);
+					MR_print_spy_point(MR_spy_point_next);
+					MR_spy_point_next++;
 				} else {
-					printf("Break point #%d "
-						"does not exist.\n", n);
+					printf("Ambiguous procedure "
+						"specification. "
+						"The matches are:\n");
+					MR_process_all_module_proc(
+						MR_print_proc_id_to_stdout,
+						words[1], words[2]);
 				}
-			} else if (streq(words[1], "*")) {
-				for (i = 0; i < MR_next_spy_point; i++) {
-					MR_spy_points[i].enabled = TRUE;
-					printf("%2d: %s %s:%s\n", i,
-						"+",
-						MR_spy_points[i].module_name,
-						MR_spy_points[i].pred_name);
+			} else {
+				printf("There is no such procedure.\n");
+			}
+		} else if (word_count == 4 &&
+				MR_trace_is_number(words[3], &arity)) {
+			const MR_Stack_Layout_Entry	*spy_proc;
+			bool				unique;
+
+			MR_register_all_modules_and_procs(stdout);
+			spy_proc = MR_search_for_module_proc_arity(words[1],
+					words[2], arity, &unique);
+			if (spy_proc != NULL) {
+				if (unique) {
+					MR_ensure_room_for_spy_point();
+					MR_spy_points[MR_spy_point_next] =
+							MR_add_spy_point(
+								when, action,
+								spy_proc, NULL,
+								path);
+					MR_print_spy_point(MR_spy_point_next);
+					MR_spy_point_next++;
+				} else {
+					printf("Ambiguous procedure "
+						"specification. "
+						"The matches are:\n");
+					MR_process_all_module_proc_arity(
+						MR_print_proc_id_to_stdout,
+						words[1], words[2], arity);
 				}
 			} else {
-				printf("The argument of this command must be "
-					"a break point number or a `*'.\n");
+				printf("There is no such procedure.\n");
 			}
+		} else if (word_count == 5 &&
+				MR_trace_is_number(words[3], &arity) &&
+				MR_trace_is_number(words[4], &mode)) {
+			const MR_Stack_Layout_Entry	*spy_proc;
+			bool				unique;
+
+			MR_register_all_modules_and_procs(stdout);
+			spy_proc = MR_search_for_module_proc_arity_mode(
+					words[1], words[2], arity, mode,
+					&unique);
+			if (spy_proc != NULL) {
+				if (unique) {
+					MR_ensure_room_for_spy_point();
+					MR_spy_points[MR_spy_point_next] =
+							MR_add_spy_point(
+								when, action,
+								spy_proc, NULL,
+								path);
+					MR_print_spy_point(MR_spy_point_next);
+					MR_spy_point_next++;
+				} else {
+					printf("Ambiguous procedure "
+						"specification. "
+						"The matches are:\n");
+					MR_process_all_module_proc_arity_mode(
+						MR_print_proc_id_to_stdout,
+						words[1], words[2],
+						arity, mode);
+				}
+			} else {
+				printf("There is no such procedure.\n");
+			}
+		} else {
+			printf("Usage: %s\n", break_usage);
+		}
+	} else if (streq(words[0], "enable")) {
+		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
+			if (0 <= n && n < MR_spy_point_next) {
+				MR_spy_points[n]->spy_enabled = TRUE;
+				MR_print_spy_point(n);
+			} else {
+				printf("Break point #%d does not exist.\n", n);
+			}
+		} else if (word_count == 2 && streq(words[1], "*")) {
+			for (i = 0; i < MR_spy_point_next; i++) {
+				MR_spy_points[i]->spy_enabled = TRUE;
+				MR_print_spy_point(n);
+			}
+
+			if (MR_spy_point_next == 0) {
+				printf("There no break points yet.\n");
+			}
+		} else {
+			printf("Usage: %s\n", enable_usage);
+		}
+	} else if (streq(words[0], "disable")) {
+		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
+			if (0 <= n && n < MR_spy_point_next) {
+				MR_spy_points[n]->spy_enabled = FALSE;
+				MR_print_spy_point(n);
+			} else {
+				printf("Break point #%d does not exist.\n", n);
+			}
+		} else if (word_count == 2 && streq(words[1], "*")) {
+			for (i = 0; i < MR_spy_point_next; i++) {
+				MR_spy_points[i]->spy_enabled = FALSE;
+				MR_print_spy_point(n);
+			}
+
+			if (MR_spy_point_next == 0) {
+				printf("There no break points yet.\n");
+			}
 		} else {
-			printf("This command expects one argument,\n");
-			printf("which must be a break point number "
-				"or a `*'.\n");
+			printf("Usage: %s\n", disable_usage);
 		}
-	} else if (streq(words[0], "-")) {
+	} else if (streq(words[0], "register")) {
+		if (word_count == 1) {
+			MR_register_all_modules_and_procs(stdout);
+		} else {
+			printf("Usage: %s\n", register_usage);
+		}
+	} else if (streq(words[0], "module_table")) {
+		if (word_count == 1) {
+			MR_register_all_modules_and_procs(stdout);
+			MR_dump_module_tables(stdout);
+		} else {
+			printf("Usage: %s\n", module_table_usage);
+		}
+#ifdef	MR_TRACE_HISTOGRAM
+	} else if (streq(words[0], "histogram_all")) {
+		if (word_count == 1) {
+			MR_trace_print_histogram(stdout, "All-inclusive",
+				MR_trace_histogram_all, MR_trace_histogram_hwm);
+		} else {
+			printf("Usage: %s\n", histogram_all_usage);
+		}
+	} else if (streq(words[0], "histogram_exp")) {
+		if (word_count == 1) {
+			MR_trace_print_histogram(stdout, "Experimental",
+				MR_trace_histogram_exp, MR_trace_histogram_hwm);
+		} else {
+			printf("Usage: %s\n", histogram_exp_usage);
+		}
+	} else if (streq(words[0], "clear_histogram")) {
+		if (word_count == 1) {
+			for (i = 0; i <= MR_trace_histogram_hwm; i++) {
+				MR_trace_histogram_exp[i] = 0;
+			}
+		} else {
+			printf("Usage: %s\n", clear_histogram_usage);
+		}
+#endif
+	} else if (streq(words[0], "printlevel")) {
 		if (word_count == 2) {
-			if (MR_trace_is_number(words[1], &n)) {
-				if (0 <= n && n < MR_next_spy_point) {
-					MR_spy_points[n].enabled = FALSE;
-					printf("%2d: %s %s:%s\n", n,
-						"-",
-						MR_spy_points[n].module_name,
-						MR_spy_points[n].pred_name);
-				} else {
-					printf("Break point #%d "
-						"does not exist.\n", n);
-				}
-			} else if (streq(words[1], "*")) {
-				for (i = 0; i < MR_next_spy_point; i++) {
-					MR_spy_points[i].enabled = FALSE;
-					printf("%2d: %s %s:%s\n", i,
-						"-",
-						MR_spy_points[i].module_name,
-						MR_spy_points[i].pred_name);
-				}
+			if (streq(words[1], "none")) {
+				MR_default_print_level = MR_PRINT_LEVEL_NONE;
+				printf("Default print level set to none.\n");
+			} else if (streq(words[1], "some")) {
+				MR_default_print_level = MR_PRINT_LEVEL_SOME;
+				printf("Default print level set to some.\n");
+			} else if (streq(words[1], "all")) {
+				MR_default_print_level = MR_PRINT_LEVEL_ALL;
+				printf("Default print level set to all.\n");
 			} else {
-				printf("The argument of this command must be "
-					"a break point number or a `*'.\n");
+				printf("Usage: %s\n", printlevel_usage);
 			}
+		} else if (word_count == 1) {
+			printf("The default print level is ");
+			switch (MR_default_print_level) {
+				case MR_PRINT_LEVEL_NONE:
+					printf("none.\n");
+					break;
+				case MR_PRINT_LEVEL_SOME:
+					printf("some.\n");
+					break;
+				case MR_PRINT_LEVEL_ALL:
+					printf("all.\n");
+					break;
+				default:
+					printf("something weird.\n");
+					break;
+			}
 		} else {
-			printf("This command expects one argument,\n");
-			printf("which must be a break point number "
-				"or a `*'.\n");
+			printf("Usage: %s\n", printlevel_usage);
 		}
-	} else if (streq(words[0], "h")) {
+	} else if (streq(words[0], "scroll")) {
+		if (word_count == 2) {
+			if (streq(words[1], "off")) {
+				MR_scroll_control = FALSE;
+				printf("Scroll control disabled\n");
+			} else if (streq(words[1], "on")) {
+				MR_scroll_control = TRUE;
+				printf("Scroll control enabled\n");
+			} else {
+				printf("Usage: %s\n", scroll_usage);
+			}
+		} else if (word_count == 1) {
+			printf("Scroll control is ");
+			if (MR_scroll_control) {
+				printf("on.\n");
+			} else {
+				printf("off.\n");
+			}
+		} else {
+			printf("Usage: %s\n", scroll_usage);
+		}
+	} else if (streq(words[0], "echo")) {
+		if (word_count == 2) {
+			if (streq(words[1], "off")) {
+				MR_echo_commands = FALSE;
+				printf("Command echo disabled\n");
+			} else if (streq(words[1], "on")) {
+				MR_echo_commands = TRUE;
+				printf("Command echo enabled\n");
+			} else {
+				printf("Usage: %s\n", echo_usage);
+			}
+		} else if (word_count == 1) {
+			printf("Command echo is ");
+			if (MR_echo_commands) {
+				printf("on.\n");
+			} else {
+				printf("off.\n");
+			}
+		} else {
+			printf("Usage: %s\n", echo_usage);
+		}
+	} else if (streq(words[0], "help")) {
 		if (word_count != 1) {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", help_usage);
 		}
 		MR_trace_help();
-	} else if (streq(words[0], "a")) {
+	} else if (streq(words[0], "quit")) {
 		if (word_count == 1) {
-			printf("mtrace: are you sure you want to abort? ");
-			if (MR_trace_getline(stdin, line, MR_MAX_LINE_LEN)
-					== 0) {
+			printf("mdb: are you sure you want to quit? ");
+			line = MR_trace_getline(stdin);
+			if (line == NULL) {
 				/* This means the user input EOF. */
 				exit(0);
 			} else {
@@ -423,19 +707,302 @@
 				if (line[i] == 'y' || line[i] == 'Y') {
 					exit(0);
 				}
+
+				free(line);
 			}
 		} else {
-			printf("This command expects no argument.\n");
+			printf("Usage: %s\n", quit_usage);
 		}
 	} else {
-		printf("Command not recognized. "
-			"Give the command `h' for help.\n");
+		printf("Unknown command. Give the command `help' for help.\n");
 	}
 
+	/* fall through */
+return_keep_interacting:
+	free(line);
+	free(orig_words);
 	return KEEP_INTERACTING;
+
+return_stop_interacting:
+	free(line);
+	free(orig_words);
+	return STOP_INTERACTING;
+}
+
+static bool
+MR_trace_options_strict_print(MR_Trace_Cmd_Info *cmd,
+	char ***words, int *word_count, const char *usage)
+{
+	int	c;
+
+	optind = 0;
+	while ((c = getopt(*word_count, *words, "NSans")) != EOF) {
+		switch (c) {
+
+			case 'N':
+				cmd->MR_trace_strict = FALSE;
+				break;
+
+			case 'S':
+				cmd->MR_trace_strict = TRUE;
+				break;
+
+			case 'a':
+				cmd->MR_trace_print_level = MR_PRINT_LEVEL_ALL;
+				break;
+
+			case 'n':
+				cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
+				break;
+
+			case 's':
+				cmd->MR_trace_print_level = MR_PRINT_LEVEL_SOME;
+				break;
+
+			default:
+				printf("Usage: %s\n", usage);
+				return FALSE;
+		}
+
+#if 0
+		printf("option %c recognized\n", c);
+#endif
+	}
+
+#if 0
+	printf("optind = %d, word_count = %d\n", optind, *word_count);
+	for (c = 1; c < *word_count; c++) {
+		printf("argv[%d] = <%s>\n", c, (*words)[c]);
+	}
+#endif
+
+	*words = *words + optind - 1;
+	*word_count = *word_count - optind + 1;
+	return TRUE;
 }
 
+static bool
+MR_trace_options_when_action(MR_Spy_When *when, MR_Spy_Action *action,
+	char ***words, int *word_count, const char *usage)
+{
+	int	c;
+
+	optind = 0;
+	while ((c = getopt(*word_count, *words, "PSaei")) != EOF) {
+		switch (c) {
+
+			case 'a':
+				*when = MR_SPY_ALL;
+				break;
+
+			case 'e':
+				*when = MR_SPY_ENTRY;
+				break;
+
+			case 'i':
+				*when = MR_SPY_INTERFACE;
+				break;
+
+			case 'P':
+				*action = MR_SPY_PRINT;
+				break;
+
+			case 'S':
+				*action = MR_SPY_STOP;
+				break;
+
+			default:
+				printf("Usage: %s\n", usage);
+				return FALSE;
+		}
+
+#if 0
+		printf("option %c recognized\n", c);
+#endif
+	}
+
+#if 0
+	printf("optind = %d, word_count = %d\n", optind, *word_count);
+	for (c = 1; c < *word_count; c++) {
+		printf("argv[%d] = <%s>\n", c, (*words)[c]);
+	}
+#endif
+
+	*words = *words + optind - 1;
+	*word_count = *word_count - optind + 1;
+	return TRUE;
+}
+
+#define	MR_INIT_ARG_COUNT	20
+
 static void
+MR_trace_restart(const MR_Stack_Layout_Label *this_label, int seqno, int depth)
+{
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Label	*call_label;
+	const MR_Stack_Layout_Vars	*input_args;
+	Word				*args;
+	int				arg_max;
+	int				arg_num;
+	Word				arg_value;
+	int				i;
+	bool				succeeded;
+
+	entry = this_label->MR_sll_entry;
+	call_label = entry->MR_sle_call_label;
+
+	if (call_label->MR_sll_var_count < 0) {
+		printf("Cannot perform restart because information about "
+			"the input arguments is not available.\n");
+		return;
+	}
+
+	input_args = &call_label->MR_sll_var_info;
+
+	arg_max = MR_INIT_ARG_COUNT;
+	args = checked_malloc(arg_max * sizeof(Word));
+
+	for (i = 0; i < call_label->MR_sll_var_count; i++) {
+		arg_value = MR_trace_find_input_arg(this_label,
+				input_args->MR_slvs_names[i], &succeeded);
+
+		if (! succeeded) {
+			printf("Cannot perform restart because the values of "
+				"some input arguments are missing.\n");
+			return;
+		}
+
+		arg_num = MR_trace_get_register_number(
+			input_args->MR_slvs_pairs[i].MR_slv_locn);
+		if (arg_num > 0) {
+			if (arg_num >= arg_max) {
+				arg_max *= 2;
+				args = checked_realloc(args,
+						arg_max * sizeof(Word));
+			}
+
+			args[arg_num] = arg_value;
+		} else {
+			fatal_error("illegal location for input argument");
+		}
+	}
+
+	MR_trace_saved_call_seqno = seqno - 1;
+	MR_trace_saved_call_depth = depth - 1;
+
+	if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
+		MR_Live_Lval	location;
+		Word		*this_frame;
+
+		/*
+		** We are at a final port, so both curfr and maxfr
+		** must already have been reset to their original values.
+		** We only need to set up the succip register for the "call",
+		** and then remove this frame from the det stack.
+		*/
+
+		location = entry->MR_sle_succip_locn;
+		if (MR_LIVE_LVAL_TYPE(location) != MR_LVAL_TYPE_STACKVAR) {
+			fatal_error("illegal location for stored succip");
+		}
+
+		this_frame = MR_saved_sp(MR_saved_regs);
+		MR_saved_succip(MR_saved_regs) = based_detstackvar(this_frame,
+						MR_LIVE_LVAL_NUMBER(location));
+		MR_saved_sp(MR_saved_regs) -= entry->MR_sle_stack_slots;
+		MR_trace_saved_event_number = based_detstackvar(this_frame,
+						entry->MR_sle_event_slot);
+	} else {
+		Word	*this_frame;
+
+		/*
+		** We are at a final port, so sp must already have been reset
+		** to its original value. We only need to set up the succip
+		** and curfr registers for the "call", and remove this frame,
+		** and any other frames above it, from the nondet stack.
+		*/
+
+		this_frame = MR_saved_curfr(MR_saved_regs);
+
+		MR_saved_succip(MR_saved_regs) = bt_succip(this_frame);
+		MR_saved_curfr(MR_saved_regs) = bt_succfr(this_frame);
+		MR_saved_maxfr(MR_saved_regs) = bt_prevfr(this_frame);
+		MR_trace_saved_event_number = based_framevar(this_frame,
+						entry->MR_sle_event_slot);
+	}
+
+	for (i = 1; i < arg_max; i++) {
+		saved_reg(MR_saved_regs, i) = args[i];
+	}
+
+	free(args);
+
+	MR_trace_goto_reg_count = max(MR_trace_goto_reg_count, arg_max);
+	MR_trace_goto = entry->MR_sle_code_addr;
+
+	MR_trace_call_seqno = MR_trace_saved_call_seqno;
+	MR_trace_call_depth = MR_trace_saved_call_depth;
+	MR_trace_event_number = MR_trace_saved_event_number;
+}
+
+static Word
+MR_trace_find_input_arg(const MR_Stack_Layout_Label *label,
+	const char *name, bool *succeeded)
+{
+	const MR_Stack_Layout_Vars	*vars;
+	int				i;
+
+	vars = &label->MR_sll_var_info;
+	if (vars->MR_slvs_names == NULL) {
+		*succeeded = FALSE;
+		return 0;
+	}
+
+	for (i = 0; i < label->MR_sll_var_count; i++) {
+		if (streq(vars->MR_slvs_names[i], name)) {
+			return MR_trace_lookup_live_lval_base(
+				vars->MR_slvs_pairs[i].MR_slv_locn,
+				TRUE, MR_saved_sp(MR_saved_regs), MR_saved_curfr(MR_saved_regs), succeeded);
+		}
+	}
+
+	*succeeded = FALSE;
+	return 0;
+}
+
+static void
+MR_ensure_room_for_spy_point(void)
+{
+	if (MR_spy_point_next >= MR_spy_point_max) {
+		if (MR_spy_point_max == 0) {
+			MR_spy_point_max = MR_INIT_SPY_POINTS;
+			MR_spy_points = checked_malloc(
+					MR_spy_point_max *
+					sizeof(MR_Spy_Point *));
+		} else {
+			MR_spy_point_max *= 2;
+			MR_spy_points = checked_realloc(MR_spy_points,
+					MR_spy_point_max *
+					sizeof(MR_Spy_Point *));
+		}
+	}
+}
+
+static void
+MR_print_spy_point(int i)
+{
+	printf("%2d: %1s %5s %9s %s:%s/%ld-%ld\n",
+		i,
+		MR_spy_points[i]->spy_enabled ? "+" : "-",
+		MR_spy_action_string(MR_spy_points[i]->spy_action),
+		MR_spy_when_string(MR_spy_points[i]->spy_when),
+		MR_spy_points[i]->spy_proc->MR_sle_def_module,
+		MR_spy_points[i]->spy_proc->MR_sle_name,
+		(long) MR_spy_points[i]->spy_proc->MR_sle_arity,
+		(long) MR_spy_points[i]->spy_proc->MR_sle_mode);
+}
+
+static void
 MR_trace_list_vars(const MR_Stack_Layout_Label *top_layout, int ancestor_level)
 {
 	const MR_Stack_Layout_Label	*level_layout;
@@ -459,10 +1026,10 @@
 
 	var_count = (int) level_layout->MR_sll_var_count;
 	if (var_count < 0) {
-		printf("mtrace: there is no information about live variables\n");
+		printf("mdb: there is no information about live variables\n");
 		return;
 	} else if (var_count == 0) {
-		printf("mtrace: there are no live variables\n");
+		printf("mdb: there are no live variables\n");
 		return;
 	}
 
@@ -497,10 +1064,10 @@
 
 	var_count = (int) level_layout->MR_sll_var_count;
 	if (var_count < 0) {
-		printf("mtrace: there is no information about live variables\n");
+		printf("mdb: there is no information about live variables\n");
 		return;
 	} else if (which_var >= var_count) {
-		printf("mtrace: there is no such variable\n");
+		printf("mdb: there is no such variable\n");
 		return;
 	}
 
@@ -541,10 +1108,10 @@
 
 	var_count = (int) level_layout->MR_sll_var_count;
 	if (var_count < 0) {
-		printf("mtrace: there is no information about live variables\n");
+		printf("mdb: there is no information about live variables\n");
 		return;
 	} else if (var_count == 0) {
-		printf("mtrace: there are no live variables\n");
+		printf("mdb: there are no live variables\n");
 		return;
 	}
 
@@ -590,9 +1157,9 @@
 	/* the variable names from the prompt. */
 
 	if (name != NULL) {
-		printf("%10s%-21s\t", "", name);
+		printf("%7s%-21s\t", "", name);
 	} else {
-		printf("%10s%-21s\t", "", "anonymous variable");
+		printf("%7s%-21s\t", "", "anonymous variable");
 	}
 
 	fflush(stdout);
@@ -637,27 +1204,6 @@
 	printf("\n");
 }
 
-bool
-MR_event_matches_spy_point(const MR_Stack_Layout_Label *layout)
-{
-	const	MR_Stack_Layout_Entry	*entry;
-	int				i;
-
-	entry = layout->MR_sll_entry;
-
-	for (i = 0; i < MR_next_spy_point; i++) {
-		if (MR_spy_points[i].enabled
-		&& streq(MR_spy_points[i].pred_name,
-				entry->MR_sle_name)
-		&& streq(MR_spy_points[i].module_name,
-				entry->MR_sle_def_module)) {
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
 /*
 ** Is the string pointed to by word an integer?
 ** If yes, return its value in *value.
@@ -684,22 +1230,109 @@
 
 /*
 ** Given a text line, break it up into words composed of non-space characters
-** separated by space characters. Make each word a NULL-terminated string
-** (overwriting some spaces in the line array in the process), return pointers
-** to them in the words array, and return the number of words in the return
-** value of the function.
+** separated by space characters. Make each word a NULL-terminated string,
+** overwriting some spaces in the line array in the process.
+**
+** If the first word is a number but the second is not, swap the two.
+** If the first word has a number prefix, separate it out.
 **
-** This function assumes that the words array is as long as necessary.
-** This can be (and is) ensured by making the words array have one element
-** for every two characters in the line array (since you need at least one
-** non-space and one space or newline character per word).
+** On return *words_ptr will point to an array of strings, with space for
+** *words_max strings. The number of strings (words) filled in will be
+** given by the return value.
+**
+** The lifetime of the elements of the *words_ptr array expires when
+** the line array is freed or further modified or when MR_trace_parse_line
+** is called again, whichever comes first.
+*/
+
+/* If a number is more than 80 chars long, the user is in trouble. */
+#define	MR_NUMBER_LEN	80
+
+static const char *
+MR_trace_parse_line(char *line, char ***words_ptr, int *word_count_ptr)
+{
+	char		**raw_words;
+	int		raw_words_max;
+	char		raw_words_count;
+	static char	count_buf[MR_NUMBER_LEN];
+	char		*s;
+	int		i;
+
+	/*
+	** Handle a possible number prefix on the first word on the line,
+	** separating it out into a word on its own.
+	*/
+
+	raw_words_count = MR_trace_break_into_words(line,
+				&raw_words, &raw_words_max);
+
+	if (raw_words_count > 0 && MR_isdigit(*raw_words[0])) {
+		i = 0;
+		s = raw_words[0];
+		while (MR_isdigit(*s)) {
+			if (i >= MR_NUMBER_LEN) {
+				return "too large a number";
+			}
+
+			count_buf[i] = *s;
+			i++;
+			s++;
+		}
+
+		count_buf[i] = '\0';
+
+		if (*s != '\0') {
+			/* Only part of the first word constitutes a number. */
+			/* Put it in an extra word at the start. */
+
+			if (raw_words_count + 1 >= raw_words_max) {
+				raw_words_max += 1;
+				raw_words = checked_realloc(raw_words,
+						raw_words_max
+						* sizeof(char **));
+			}
+
+			for (i = raw_words_count; i > 0; i--) {
+				raw_words[i] = raw_words[i-1];
+			}
+
+			raw_words[0] = count_buf;
+			raw_words[1] = s;
+			raw_words_count++;
+		}
+	}
+
+	/*
+	** If the first word is a number, try to exchange it
+	** with the command word, to put the command word first.
+	*/
+
+	if (raw_words_count > 1 && MR_trace_is_number(raw_words[0], &i)
+			&& ! MR_trace_is_number(raw_words[1], &i)) {
+		s = raw_words[0];
+		raw_words[0] = raw_words[1];
+		raw_words[1] = s;
+	}
+
+	*words_ptr = raw_words;
+	*word_count_ptr = raw_words_count;
+	return NULL;
+}
+
+/*
+** Given a text line, break it up into words composed of non-space characters
+** separated by space characters. Make each word a NULL-terminated string,
+** overwriting some spaces in the line array in the process.
 **
-** This function also assumes that line[] is guaranteed to have a white space
-** character (which will usually be a newline) just before the null character.
+** On return *words_ptr will point to an array of strings, with space for
+** *words_max strings. The number of strings (words) filled in will be
+** given by the return value.
 */
 
+#define	INIT_WORD_COUNT	20
+
 static int
-MR_trace_break_into_words(char line[], char *words[])
+MR_trace_break_into_words(char *line, char ***words_ptr, int *words_max)
 {
 	int	token_number;
 	int	char_pos;
@@ -708,6 +1341,9 @@
 	token_number = 0;
 	char_pos = 0;
 
+	*words_max = INIT_WORD_COUNT;
+	*words_ptr = checked_malloc(*words_max * sizeof(char **));
+
 	/* each iteration of this loop processes one token, or end of line */
 	for (;;) {
 		while (line[char_pos] != '\0' && MR_isspace(line[char_pos])) {
@@ -718,56 +1354,134 @@
 			return token_number;
 		}
 
-		words[token_number] = line + char_pos;
+		if (token_number >= *words_max) {
+			*words_max *= 2;
+			*words_ptr = checked_realloc(*words_ptr,
+					*words_max * sizeof(char **));
+		}
+
+		(*words_ptr)[token_number] = line + char_pos;
+
 		while (line[char_pos] != '\0' && !MR_isspace(line[char_pos])) {
 			char_pos++;
 		}
 
-		line[char_pos] = '\0';
-		char_pos++;
+		if (line[char_pos] != '\0') {
+			line[char_pos] = '\0';
+			char_pos++;
+		}
+
 		token_number++;
 	}
 }
 
 /*
-**	Read a line from a file. If the line does not fit in the array,
-**	read the whole line anyway but store only the first part.
-**	If the last line ends without a newline, insert it.
-**	Return the length of the (possibly truncated) line.
-**	This will be zero only if getline is called at EOF;
-**	it will be one only if line contains a single newline;
-**	otherwise it will contain a newline terminated string.
+**	Read a line from a file, and return a pointer to a malloc'd buffer
+**	holding the line (without the final newline). If EOF occurs on a
+**	nonempty line, treat the EOF as a newline; if EOF occurs on an empty
+**	line, return NULL.
 */
 
-static int
-MR_trace_getline(FILE *file, char line[], int line_max)
+#define	INIT_BUF_LEN	80
+
+static char *
+MR_trace_getline(FILE *file)
 {
-	int	c, i;
+	char	*buf;
+	int	max;
+	int	c;
+	int	i;
+
+	max = INIT_BUF_LEN;
+	buf = checked_malloc(max * sizeof(char));
 
 	i = 0;
 	while ((c = getc(file)) != EOF && c != '\n') {
-		if (i < line_max-1) {
-			line[i++] = c;
+		if (i >= max) {
+			max *= 2;
+			buf = checked_realloc(buf, max * sizeof(char));
 		}
+
+		buf[i++] = c;
 	}
 
 	if (c == '\n' || i > 0) {
-		line[i++] = '\n';
+		buf[i] = '\0';
+		return buf;
+	} else {
+		free(buf);
+		return NULL;
 	}
+}
 
-	line[i] = '\0';
-	return i;
+void
+MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
+	const MR_Stack_Layout_Label *layout, MR_Trace_Port port,
+	int seqno, int depth, const char *path)
+{
+	char	*buf;
+	int	i;
+
+	if (MR_scroll_control && MR_scroll_next >= MR_scroll_limit) {
+		printf("--more--");
+		fflush(stdout);
+
+	try_again:
+		buf = MR_trace_getline(stdin);
+		if (buf != NULL) {
+			for (i = 0; buf[i] != '\0' && MR_isspace(buf[i]); i++)
+				;
+			
+			if (buf[i] != '\0' && !MR_isspace(buf[i])) {
+				switch (buf[i]) {
+					case 'a':
+						cmd->MR_trace_print_level =
+							MR_PRINT_LEVEL_ALL;
+						break;
+
+					case 'n':
+						cmd->MR_trace_print_level =
+							MR_PRINT_LEVEL_NONE;
+						break;
+
+					case 's':
+						cmd->MR_trace_print_level =
+							MR_PRINT_LEVEL_SOME;
+						break;
+
+					case 'q':
+						free(buf);
+						MR_trace_event_internal(cmd,
+							layout, port, seqno,
+							depth, path);
+						break;
+
+					default:
+						printf("unknown command, "
+							"try again\n");
+						free(buf);
+						goto try_again;
+				}
+			}
+
+			free(buf);
+		}
+
+		MR_scroll_next = 1;
+	}
+
+	MR_trace_event_print_internal_report(layout, port, seqno, depth, path);
+	MR_scroll_next++;
 }
 
 void
-MR_trace_event_internal_report(const MR_Stack_Layout_Label *layout,
-	MR_trace_port port, int seqno, int depth, const char *path)
+MR_trace_event_print_internal_report(const MR_Stack_Layout_Label *layout,
+	MR_Trace_Port port, int seqno, int depth, const char *path)
 {
 	printf("%8ld: %6ld %2ld ",
 		(long) MR_trace_event_number, (long) seqno, (long) depth);
 
 	MR_trace_print_port(port);
-	MR_trace_print_detism(layout->MR_sll_entry->MR_sle_detism);
 
 	/*
 	** The following should be a full identification of the procedure
@@ -775,16 +1489,11 @@
 	** not interested in tracing compiler-generated procedures.
 	*/
 
-	printf("%s:%s/%ld-%ld %s\n",
-		layout->MR_sll_entry->MR_sle_def_module,
-		layout->MR_sll_entry->MR_sle_name,
-		(long) layout->MR_sll_entry->MR_sle_arity,
-		(long) layout->MR_sll_entry->MR_sle_mode,
-		path);
+	MR_print_proc_id(stdout, layout->MR_sll_entry, path);
 }
 
 static void
-MR_trace_print_port(MR_trace_port port)
+MR_trace_print_port(MR_Trace_Port port)
 {
 	switch (port) {
 		case MR_PORT_CALL:
@@ -830,85 +1539,35 @@
 }
 
 static void
-MR_trace_print_detism(Word detism)
-{
-	switch ((int) detism) {
-		case MR_DETISM_DET:
-			printf("DET   ");
-			break;
-
-		case MR_DETISM_SEMI:
-			printf("SEMI  ");
-			break;
-
-		case MR_DETISM_NON:
-			printf("NON   ");
-			break;
-
-		case MR_DETISM_MULTI:
-			printf("MUL   ");
-			break;
-
-		case MR_DETISM_ERRONEOUS:
-			printf("ERR   ");
-			break;
-
-		case MR_DETISM_FAILURE:
-			printf("FAIL  ");
-			break;
-
-		case MR_DETISM_CCNON:
-			printf("CCNON ");
-			break;
-
-		case MR_DETISM_CCMULTI:
-			printf("CCMUL ");
-			break;
-		
-		default:
-			printf("BAD DETERMINISM\n");
-			break;
-	}
-}
-
-static void
 MR_trace_help(void)
 {
-	printf("valid commands are:\n"
-		"a, EOF:\t\t"
-		"\tabort the current execution.\n"
-		"b <module> <name>:"
-		"\tset a breakpoint on the predicate\n"
-		"\t\t\tor function <module>:<name>.\n"
-		"c:\t\t"
-		"\tcontinue to end of program, not printing the trace.\n"
-		"C:\t\t"
-		"\tcontinue to end of program, printing the trace.\n"
-		"f:\t\t"
-		"\tfinish this call, not printing the trace.\n"
-		"F:\t\t"
-		"\tfinish this call, printing the trace.\n"
-		"<N> g:\t\t"
-		"\tgo to event #N, not printing the trace.\n"
-		"<N> G:\t\t"
-		"\tgo to event #N, printing the trace.\n"
-		"v:\t\t"
-		"\tlist the names of the variables live at this point.\n"
-		"l <n>:\t\t"
-		"\tset ancestor level to <n>\n"
-		"p <n>:\t\t"
-		"\tprint variable #n (or all vars if <n> is '*')\n"
-		"r:\t\t"
-		"\tcontinue until forward execution is resumed.\n"
-		"[<N>] [s]:\t"
-		"\tskip N events, not printing the trace (default: N=1).\n"
-		"[<N>] S:\t"
-		"\tskip N events, printing the trace (default: N=1).\n"
-		"?:\t\t"
-		"\tlist all the breakpoints.\n"
-		"+ <N>:\t\t"
-		"\tenable breakpoint #N.\n"
-		"- <N>:\t\t"
-		"\tdisable breakpoint #N.\n"
-	);
+	printf("valid commands are:\n");
+	printf("   %s\n", step_usage);
+	printf("   %s\n", goto_usage);
+	printf("   %s\n", finish_usage);
+	printf("   %s\n", forward_usage);
+	printf("   %s\n", continue_usage);
+	printf("   %s\n", restart_usage);
+	printf("   %s\n", level_usage);
+	printf("   %s\n", up_usage);
+	printf("   %s\n", down_usage);
+	printf("   %s\n", vars_usage);
+	printf("   %s\n", print_usage);
+	printf("   %s\n", stack_usage);
+	printf("   %s\n", stack_regs_usage);
+	printf("   %s\n", break_usage);
+	printf("   %s\n", enable_usage);
+	printf("   %s\n", disable_usage);
+	printf("   %s\n", register_usage);
+	printf("   %s\n", module_table_usage);
+#ifdef	MR_TRACE_HISTOGRAM
+	printf("   %s\n", histogram_all_usage);
+	printf("   %s\n", histogram_exp_usage);
+	printf("   %s\n", clear_histogram_usage);
+#endif
+	printf("   %s\n", printlevel_usage);
+	printf("   %s\n", scroll_usage);
+	printf("   %s\n", echo_usage);
+	printf("   %s\n", help_usage);
+	printf("   %s\n", quit_usage);
 }
Index: runtime/mercury_trace_internal.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_internal.h,v
retrieving revision 1.1
diff -u -u -r1.1 mercury_trace_internal.h
--- mercury_trace_internal.h	1998/05/16 07:28:28	1.1
+++ mercury_trace_internal.h	1998/07/06 10:01:13
@@ -7,16 +7,14 @@
 #ifndef	MERCURY_TRACE_INTERNAL_H
 #define	MERCURY_TRACE_INTERNAL_H
 
-extern	void	MR_trace_event_internal(MR_trace_cmd_info *cmd,
+extern	void	MR_trace_event_internal(MR_Trace_Cmd_Info *cmd,
 			const MR_Stack_Layout_Label *layout,
-			MR_trace_port port, int seqno, int depth,
+			MR_Trace_Port port, int seqno, int depth,
 			const char *path);
 
-extern	void	MR_trace_event_internal_report(
+extern	void	MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
 			const MR_Stack_Layout_Label *layout,
-			MR_trace_port port, int seqno, int depth,
+			MR_Trace_Port port, int seqno, int depth,
 			const char *path);
-
-extern	bool	MR_event_matches_spy_point(const MR_Stack_Layout_Label *layout);
 
 #endif	/* MERCURY_TRACE_INTERNAL_H */
Index: runtime/mercury_trace_spy.c
===================================================================
RCS file: mercury_trace_spy.c
diff -N mercury_trace_spy.c
--- /dev/null	Wed May 28 10:49:58 1997
+++ mercury_trace_spy.c	Sat Jul  4 20:43:51 1998
@@ -0,0 +1,204 @@
+/*
+** 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 manage spy points for both
+** the internal and external debuggers.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#include "mercury_imp.h"
+#include "mercury_trace_base.h"
+#include "mercury_trace.h"
+#include "mercury_trace_spy.h"
+
+typedef struct {
+	const MR_Stack_Layout_Entry	*spy_proc;
+	MR_Spy_Point			*spy_points;
+} MR_Spied_Proc;
+
+static	MR_Spied_Proc	*MR_spied_procs;
+static	int		MR_spied_procs_next = 0;
+static	int		MR_spied_procs_max = 0;
+
+#define	INIT_SPY_TABLE_SIZE	10
+
+bool
+MR_event_matches_spy_point(const MR_Stack_Layout_Label *layout,
+	MR_Trace_Port port, MR_Spy_Action *action_ptr)
+{
+	const	MR_Stack_Layout_Entry	*entry;
+	int				lo;
+	int				hi;
+	int				mid;
+	int				i;
+	bool				found;
+	bool				enabled;
+	MR_Spy_Point			*point;
+	MR_Spy_Action			action;
+
+	entry = layout->MR_sll_entry;
+
+	lo = 0;
+	hi = MR_spied_procs_next-1;
+	found = FALSE;
+	while (lo <= hi) {
+		mid = (lo + hi) / 2;
+		if (MR_spied_procs[mid].spy_proc == entry) {
+			found = TRUE;
+			break;
+		} else if (MR_spied_procs[mid].spy_proc < entry) {
+			lo = mid + 1;
+		} else {
+			hi = mid - 1;
+		}
+	}
+
+	if (! found) {
+		return FALSE;
+	}
+
+	enabled = FALSE;
+	action = MR_SPY_PRINT;
+	for (point = MR_spied_procs[mid].spy_points; point != NULL;
+			point = point->spy_next) {
+		if (! point->spy_enabled) {
+			continue;
+		}
+
+		switch (point->spy_when) {
+
+			case MR_SPY_ALL:
+				enabled = TRUE;
+				action = max(action, point->spy_action);
+
+			case MR_SPY_ENTRY:
+				if (MR_port_is_entry(port)) {
+					enabled = TRUE;
+					action = max(action, point->spy_action);
+				} else {
+					continue;
+				}
+
+			case MR_SPY_INTERFACE:
+				if (MR_port_is_interface(port)) {
+					enabled = TRUE;
+					action = max(action, point->spy_action);
+				} else {
+					continue;
+				}
+
+			case MR_SPY_SPECIFIC:
+				if (layout == point->spy_label) {
+					enabled = TRUE;
+					action = max(action, point->spy_action);
+				} else {
+					continue;
+				}
+
+			default:
+				fatal_error("bad spy point when in "
+						"MR_event_matches_spy_point");
+		}
+	}
+
+	if (enabled) {
+		*action_ptr = action;
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+static bool MR_need_move(int i, const MR_Stack_Layout_Entry *entry);
+
+MR_Spy_Point *
+MR_add_spy_point(MR_Spy_When when, MR_Spy_Action action,
+	const MR_Stack_Layout_Entry *entry, const MR_Stack_Layout_Label *label,
+	const char *path)
+{
+	MR_Spy_Point	*point;
+	int		lo;
+	int		hi;
+	int		mid;
+	bool		found;
+
+	lo = 0;
+	hi = MR_spied_procs_next-1;
+	found = FALSE;
+	while (lo <= hi) {
+		mid = (lo + hi) / 2;
+		if (MR_spied_procs[mid].spy_proc == entry) {
+			found = TRUE;
+			break;
+		} else if (MR_spied_procs[mid].spy_proc < entry) {
+			lo = mid + 1;
+		} else {
+			hi = mid - 1;
+		}
+	}
+
+	if (! found) {
+		int	i;
+
+		/* make sure the MR_spied_procs array is big enough */
+		if (MR_spied_procs_next >= MR_spied_procs_max) {
+			if (MR_spied_procs_max == 0) {
+				MR_spied_procs_max = INIT_SPY_TABLE_SIZE;
+				MR_spied_procs = checked_malloc(
+							MR_spied_procs_max *
+							sizeof(MR_Spied_Proc));
+			} else {
+				MR_spied_procs_max *= 2;
+				MR_spied_procs = checked_realloc(
+							MR_spied_procs,
+							MR_spied_procs_max *
+							sizeof(MR_Spied_Proc));
+			}
+		}
+
+		/* move all the spied procs above the one to be inserted */
+		for (i = MR_spied_procs_next - 1;
+				i >= 0 && MR_need_move(i, entry); i--) {
+			MR_spied_procs[i+1] = MR_spied_procs[i];
+		}
+
+		MR_spied_procs_next++;
+		mid = i + 1;
+
+		/* insert the newly spied proc */
+		MR_spied_procs[mid].spy_proc = entry;
+		MR_spied_procs[mid].spy_points = NULL;
+	}
+
+	/* insert the spy point at the head of the list for the proc */
+	point = checked_malloc(sizeof(MR_Spy_Point));
+	point->spy_when    = when;
+	point->spy_enabled = TRUE;
+	point->spy_action  = action;
+	point->spy_proc    = entry;
+	point->spy_label   = label;
+	point->spy_next    = MR_spied_procs[mid].spy_points;
+	MR_spied_procs[mid].spy_points = point;
+
+	return point;
+}
+
+/*
+** The only reason why MR_need_move is function is that
+** gcc gets an internal error ("fixed or forbidden register was spilled")
+** if it isn't a function.
+**/
+
+static bool
+MR_need_move(int i, const MR_Stack_Layout_Entry *entry)
+{
+	if (MR_spied_procs[i].spy_proc > entry)
+		return TRUE;
+	else
+		return FALSE;
+}
Index: runtime/mercury_trace_spy.h
===================================================================
RCS file: mercury_trace_spy.h
diff -N mercury_trace_spy.h
--- /dev/null	Wed May 28 10:49:58 1997
+++ mercury_trace_spy.h	Sun Jul  5 14:02:53 1998
@@ -0,0 +1,56 @@
+/*
+** 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 the declarations of the types and functions that
+** the internal and external debuggers can use to manipulate spy points.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#ifndef	MERCURY_TRACE_SPY_H
+#define	MERCURY_TRACE_SPY_H
+
+typedef enum {
+	MR_SPY_PRINT, MR_SPY_STOP
+} MR_Spy_Action;
+
+#define	MR_spy_action_string(a)		((a == MR_SPY_STOP) ? "stop" :      \
+					(a == MR_SPY_PRINT) ? "print" :     \
+					"weird spy action")
+
+typedef enum {
+	MR_SPY_ALL, MR_SPY_INTERFACE, MR_SPY_ENTRY, MR_SPY_SPECIFIC
+} MR_Spy_When;
+
+#define	MR_spy_when_string(w)		((w == MR_SPY_ALL) ? "all" :          \
+					(w == MR_SPY_INTERFACE) ? "interface":\
+					(w == MR_SPY_ENTRY) ? "entry" : \
+					(w == MR_SPY_SPECIFIC) ? "specific" : \
+					"weird spy when")
+
+typedef struct struct_mr_spy_point MR_Spy_Point;
+
+struct struct_mr_spy_point {
+	MR_Spy_When			spy_when;
+	bool				spy_enabled;
+	MR_Spy_Action			spy_action;
+	const MR_Stack_Layout_Entry	*spy_proc;
+	const MR_Stack_Layout_Label	*spy_label; /* if MR_SPY_SPECIFIC */
+	MR_Spy_Point			*spy_next;
+};
+
+extern	bool		MR_event_matches_spy_point(const MR_Stack_Layout_Label
+				*layout, MR_Trace_Port port,
+				MR_Spy_Action *action);
+
+extern	MR_Spy_Point	*MR_add_spy_point(MR_Spy_When when,
+				MR_Spy_Action action,
+				const MR_Stack_Layout_Entry *entry,
+				const MR_Stack_Layout_Label *label,
+				const char *path);
+
+#endif	/* not MERCURY_TRACE_SPY_H */
Index: runtime/mercury_trace_tables.c
===================================================================
RCS file: mercury_trace_tables.c
diff -N mercury_trace_tables.c
--- /dev/null	Wed May 28 10:49:58 1997
+++ mercury_trace_tables.c	Mon Jul  6 17:32:09 1998
@@ -0,0 +1,420 @@
+/*
+** 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 manages a table listing the debuggable modules of the program,
+** and subsidiary tables listing the procedures of each of those modules.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#include "mercury_imp.h"
+#include "mercury_label.h"
+#include "mercury_trace_tables.h"
+#include <stdio.h>
+
+static	MR_Module_Info	*MR_module_infos;
+static	int		MR_module_info_next = 0;
+static	int		MR_module_info_max  = 0;
+
+#define	INIT_MODULE_TABLE_SIZE	10
+
+static	void		MR_register_from_internal_label(const void *info);
+static	void		MR_ensure_proc_node_is_present(MR_Module_Info *module,
+				const MR_Stack_Layout_Entry *entry);
+static	MR_Module_Info	*MR_search_module_info(const char *name);
+static	MR_Module_Info	*MR_insert_module_info(const char *name);
+static	MR_Module_Info	*MR_ensure_module_info_is_present(const char *name);
+
+void
+MR_register_all_modules_and_procs(FILE *fp)
+{
+	static	bool	done = FALSE;
+
+	if (! done) {
+		fprintf(fp, "Registering all debuggable procedures... ");
+		fflush(fp);
+		do_init_modules();
+		MR_process_all_internal_labels(MR_register_from_internal_label);
+		done = TRUE;
+		fprintf(fp, "done\n");
+	}
+}
+
+static void
+MR_register_from_internal_label(const void *info)
+{
+	const MR_Stack_Layout_Label	*label;
+	const MR_Stack_Layout_Entry	*entry;
+	MR_Module_Info			*module;
+
+	label = ((const MR_Internal *) info)->i_layout;
+
+	if (label == NULL) {
+		/* some labels have no layout structure */
+		return;
+	}
+
+	if (label->MR_sll_entry == NULL) {
+		/* some hand-crafted label structures have no entry */
+		return;
+	}
+
+	entry = label->MR_sll_entry;
+	module = MR_ensure_module_info_is_present(entry->MR_sle_def_module);
+	MR_ensure_proc_node_is_present(module, entry);
+}
+
+static void
+MR_ensure_proc_node_is_present(MR_Module_Info *module,
+	const MR_Stack_Layout_Entry *entry)
+{
+	MR_Proc_Node	*cur;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		if (entry == cur->MR_proc_layout) {
+			return;
+		}
+	}
+
+	cur = checked_malloc(sizeof(MR_Proc_Node));
+	cur->MR_proc_layout = entry;
+	cur->MR_proc_next   = module->MR_module_procs;
+	module->MR_module_procs = cur;
+}
+
+static MR_Module_Info *
+MR_search_module_info(const char *name)
+{
+	int	lo;
+	int	hi;
+	int	mid;
+	int	diff;
+
+	lo = 0;
+	hi = MR_module_info_next-1;
+	while (lo <= hi) {
+		mid = (lo + hi) / 2;
+		diff = strcmp(MR_module_infos[mid].MR_module_name, name);
+		if (diff == 0) {
+			return &MR_module_infos[mid];
+		} else if (diff < 0) {
+			lo = mid + 1;
+		} else {
+			hi = mid - 1;
+		}
+	}
+
+	return NULL;
+}
+
+static MR_Module_Info *
+MR_insert_module_info(const char *name)
+{
+	int	i;
+
+	/* make sure the MR_module_infos array is big enough */
+	if (MR_module_info_next >= MR_module_info_max) {
+		if (MR_module_info_max == 0) {
+			MR_module_info_max = INIT_MODULE_TABLE_SIZE;
+			MR_module_infos = checked_malloc(
+						MR_module_info_max *
+						sizeof(MR_Module_Info));
+		} else {
+			MR_module_info_max *= 2;
+			MR_module_infos = checked_realloc(
+						MR_module_infos,
+						MR_module_info_max *
+						sizeof(MR_Module_Info));
+		}
+	}
+
+	/* move all the spied procs above the one to be inserted */
+	for (i = MR_module_info_next - 1;
+			i >= 0 &&
+			(strcmp(name, MR_module_infos[i].MR_module_name) < 0);
+			i--) {
+		MR_module_infos[i+1] = MR_module_infos[i];
+	}
+
+	MR_module_info_next++;
+	MR_module_infos[i + 1].MR_module_name = name;
+	MR_module_infos[i + 1].MR_module_procs = NULL;
+	return &MR_module_infos[i + 1];
+}
+
+static MR_Module_Info *
+MR_ensure_module_info_is_present(const char *name)
+{
+	MR_Module_Info	*module;
+
+	module = MR_search_module_info(name);
+	if (module != NULL) {
+		return module;
+	} else {
+		return MR_insert_module_info(name);
+	}
+}
+
+void
+MR_dump_module_tables(FILE *fp)
+{
+	const MR_Proc_Node	*cur;
+	int			i;
+
+	for (i = 0; i < MR_module_info_next; i++) {
+		fprintf(fp, "====================\n");
+		fprintf(fp, "module %s\n", MR_module_infos[i].MR_module_name);
+		fprintf(fp, "====================\n");
+		for (cur = MR_module_infos[i].MR_module_procs; cur != NULL;
+				cur = cur->MR_proc_next) {
+			MR_print_proc_id(fp, cur->MR_proc_layout, NULL);
+		}
+	}
+}
+
+const MR_Stack_Layout_Entry *
+MR_search_for_module_proc(const char *module_name, const char *pred_name,
+	bool *unique)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return NULL;
+	}
+
+	entry = NULL;
+	*unique = TRUE;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name)) {
+			if (entry == NULL) {
+				entry = cur_entry;
+			} else {
+				*unique = FALSE;
+			}
+		}
+	}
+
+	return entry;
+}
+
+const MR_Stack_Layout_Entry *
+MR_search_for_module_proc_arity(const char *module_name, const char *pred_name,
+	int arity, bool *unique)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return NULL;
+	}
+
+	entry = NULL;
+	*unique = TRUE;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name) &&
+				arity == cur_entry->MR_sle_arity) {
+			if (entry == NULL) {
+				entry = cur_entry;
+			} else {
+				*unique = FALSE;
+			}
+		}
+	}
+
+	return entry;
+}
+
+const MR_Stack_Layout_Entry *
+MR_search_for_module_proc_arity_mode(const char *module_name,
+	const char *pred_name, int arity, int mode, bool *unique)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return NULL;
+	}
+
+	entry = NULL;
+	*unique = TRUE;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name) &&
+				arity == cur_entry->MR_sle_arity &&
+				mode == cur_entry->MR_sle_mode) {
+			if (entry == NULL) {
+				entry = cur_entry;
+			} else {
+				*unique = FALSE;
+			}
+		}
+	}
+
+	return entry;
+}
+
+const MR_Stack_Layout_Entry *
+MR_search_for_module_proc_arity_mode_pf(const char *module_name,
+	const char *pred_name, int arity, int mode, MR_PredFunc predfunc,
+	bool *unique)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return NULL;
+	}
+
+	entry = NULL;
+	*unique = TRUE;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name) &&
+				arity == cur_entry->MR_sle_arity &&
+				mode == cur_entry->MR_sle_mode &&
+				predfunc == cur_entry->MR_sle_pred_or_func) {
+			if (entry == NULL) {
+				entry = cur_entry;
+			} else {
+				*unique = FALSE;
+			}
+		}
+	}
+
+	return entry;
+}
+
+void
+MR_process_all_module_proc(void f(const MR_Stack_Layout_Entry *),
+	const char *module_name, const char *pred_name)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return;
+	}
+
+	entry = NULL;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name)) {
+			f(cur_entry);
+		}
+	}
+}
+
+void
+MR_process_all_module_proc_arity(void f(const MR_Stack_Layout_Entry *),
+	const char *module_name, const char *pred_name, int arity)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return;
+	}
+
+	entry = NULL;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name) &&
+				arity == cur_entry->MR_sle_arity) {
+			f(cur_entry);
+		}
+	}
+}
+
+void
+MR_process_all_module_proc_arity_mode(void f(const MR_Stack_Layout_Entry *),
+	const char *module_name, const char *pred_name, int arity, int mode)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return;
+	}
+
+	entry = NULL;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name) &&
+				arity == cur_entry->MR_sle_arity &&
+				mode == cur_entry->MR_sle_mode) {
+			f(cur_entry);
+		}
+	}
+}
+
+void
+MR_process_all_module_proc_arity_mode_pf(void f(const MR_Stack_Layout_Entry *),
+	const char *module_name, const char *pred_name, int arity, int mode,
+	MR_PredFunc predfunc)
+{
+	MR_Module_Info			*module;
+	MR_Proc_Node			*cur;
+	const MR_Stack_Layout_Entry	*entry;
+	const MR_Stack_Layout_Entry	*cur_entry;
+
+	module = MR_search_module_info(module_name);
+	if (module == NULL) {
+		return;
+	}
+
+	entry = NULL;
+
+	for (cur = module->MR_module_procs; cur != NULL;
+			cur = cur->MR_proc_next) {
+		cur_entry = cur->MR_proc_layout;
+		if (streq(pred_name, cur_entry->MR_sle_name) &&
+				arity == cur_entry->MR_sle_arity &&
+				mode == cur_entry->MR_sle_mode &&
+				predfunc == cur_entry->MR_sle_pred_or_func) {
+			f(cur_entry);
+		}
+	}
+}
Index: runtime/mercury_trace_tables.h
===================================================================
RCS file: mercury_trace_tables.h
diff -N mercury_trace_tables.h
--- /dev/null	Wed May 28 10:49:58 1997
+++ mercury_trace_tables.h	Mon Jul  6 14:47:30 1998
@@ -0,0 +1,67 @@
+/*
+** 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 the declarations of the tables that contain
+** the identities of the debuggable modules and their procedures.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#ifndef	MERCURY_TRACE_TABLES_H
+#define	MERCURY_TRACE_TABLES_H
+
+#include	"mercury_stack_layout.h"
+#include	<stdio.h>
+
+typedef struct struct_mr_proc_node MR_Proc_Node;
+
+struct struct_mr_proc_node {
+	const MR_Stack_Layout_Entry	*MR_proc_layout;
+	MR_Proc_Node			*MR_proc_next;
+};
+
+typedef struct {
+	const char 			*MR_module_name;
+	MR_Proc_Node			*MR_module_procs;
+} MR_Module_Info;
+
+extern	void		MR_register_all_modules_and_procs(FILE *fp);
+extern	void		MR_dump_module_tables(FILE *fp);
+
+extern	const MR_Stack_Layout_Entry
+			*MR_search_for_module_proc(const char *module_name,
+				const char *pred_name, bool *unique);
+extern	const MR_Stack_Layout_Entry
+			*MR_search_for_module_proc_arity(const char
+				*module_name, const char *pred_name,
+				int arity, bool *unique);
+extern	const MR_Stack_Layout_Entry
+			*MR_search_for_module_proc_arity_mode(const char
+				*module_name, const char *pred_name,
+				int arity, int mode, bool *unique);
+extern	const MR_Stack_Layout_Entry
+			*MR_search_for_module_proc_arity_mode_pf(const char
+				*module_name, const char *pred_name,
+				int arity, int mode, MR_PredFunc predfunc,
+				bool *unique);
+extern	void		MR_process_all_module_proc(
+				void f(const MR_Stack_Layout_Entry *),
+				const char *module_name, const char *pred_name);
+extern	void		MR_process_all_module_proc_arity(
+				void f(const MR_Stack_Layout_Entry *),
+				const char *module_name, const char *pred_name,
+				int arity);
+extern	void		MR_process_all_module_proc_arity_mode(
+				void f(const MR_Stack_Layout_Entry *),
+				const char *module_name, const char *pred_name,
+				int arity, int mode);
+extern	void		MR_process_all_module_proc_arity_mode_pf(
+				void f(const MR_Stack_Layout_Entry *),
+				const char *module_name, const char *pred_name,
+				int arity, int mode, MR_PredFunc predfunc);
+
+#endif	/* not MERCURY_TRACE_TABLES_H */
Index: runtime/mercury_trace_util.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_util.c,v
retrieving revision 1.6
diff -u -u -r1.6 mercury_trace_util.c
--- mercury_trace_util.c	1998/06/18 06:08:14	1.6
+++ mercury_trace_util.c	1998/07/05 06:31:46
@@ -184,6 +184,19 @@
 	return univ_list;
 }
 
+int
+MR_trace_get_register_number(MR_Live_Lval locn)
+{
+	int	locn_num;
+	Word	value;
+
+	if (MR_LIVE_LVAL_TYPE(locn) == MR_LVAL_TYPE_R) {
+		return MR_LIVE_LVAL_NUMBER(locn);
+	} else {
+		return -1;
+	}
+}
+
 /* if you want to debug this code, you may want to set this var to TRUE */
 static	bool	MR_trace_print_locn = FALSE;
 
Index: runtime/mercury_trace_util.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_trace_util.h,v
retrieving revision 1.3
diff -u -u -r1.3 mercury_trace_util.h
--- mercury_trace_util.h	1998/06/18 06:08:16	1.3
+++ mercury_trace_util.h	1998/07/05 06:32:11
@@ -18,6 +18,7 @@
 			Word *base_sp, Word *base_curfr);
 
 extern	Word	MR_trace_make_var_list(const MR_Stack_Layout_Label *layout);
+extern	int	MR_trace_get_register_number(MR_Live_Lval locn);
 extern	Word	MR_trace_lookup_live_lval(MR_Live_Lval locn, bool *succeeded);
 extern	Word	MR_trace_lookup_live_lval_base(MR_Live_Lval locn,
 			bool saved_regs_valid, Word *base_sp, Word *base_curfr,
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.15
diff -u -u -r1.15 mercury_wrapper.c
--- mercury_wrapper.c	1998/07/03 02:35:41	1.15
+++ mercury_wrapper.c	1998/07/03 12:18:52
@@ -710,9 +710,11 @@
   #ifndef CONSERVATIVE_GC
 	heap_zone->max      = heap_zone->min;
   #endif
+#if 0
 	detstack_zone->max  = detstack_zone->min;
 	nondetstack_zone->max = nondetstack_zone->min;
 #endif
+#endif
 
 	time_at_start = MR_get_user_cpu_miliseconds();
 	time_at_last_stat = time_at_start;
@@ -747,10 +749,12 @@
 		printf("max heap used:      %6ld words\n",
 			(long) (heap_zone->max - heap_zone->min));
   #endif
+  #if 0
 		printf("max detstack used:  %6ld words\n",
 			(long)(detstack_zone->max - detstack_zone->min));
 		printf("max nondstack used: %6ld words\n",
 			(long) (nondetstack_zone->max - nondetstack_zone->min));
+  #endif
 	}
 #endif
 
Index: runtime/mercury_wrapper.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.h,v
retrieving revision 1.9
diff -u -u -r1.9 mercury_wrapper.h
--- mercury_wrapper.h	1998/07/03 05:51:26	1.9
+++ mercury_wrapper.h	1998/07/05 07:29:17
@@ -5,8 +5,8 @@
 */
 
 /*
-** mercury_wrapper.h - defines the interface to wrapper.c.
-** See wrapper.c for documentation.
+** mercury_wrapper.h - defines the interface to mercury_wrapper.c.
+** See mercury_wrapper.c for documentation.
 */
 
 #ifndef	MERCURY_WRAPPER_H
@@ -40,7 +40,7 @@
 ** The address_of_foo pointers are set to the address of
 ** the corresponding foo.
 */
-extern	Code *		program_entry_point; /* normally mercury__main_2_0; */
+extern	Code 		*program_entry_point; /* normally mercury__main_2_0; */
 
 extern	void		(*MR_library_initializer)(void);
 extern	void		(*MR_library_finalizer)(void);
@@ -69,9 +69,9 @@
 
 extern	void		do_init_modules(void);
 
-extern	const char *	progname;
+extern	const char	*progname;
 extern	int		mercury_argc;
-extern	char **		mercury_argv;
+extern	char		**mercury_argv;
 extern	int		mercury_exit_status;
 
 /* sizes of the data areas, *including* the red zone size */
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
Index: tests/debugger/debugger_regs.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/debugger_regs.inp,v
retrieving revision 1.2
diff -u -u -r1.2 debugger_regs.inp
--- debugger_regs.inp	1998/06/18 06:08:29	1.2
+++ debugger_regs.inp	1998/07/04 12:16:09
@@ -1,4 +1,5 @@
+toggle_echo
 
 
-p *
-c
+print *
+continue
Index: tests/debugger/debugger_regs_lib.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/debugger_regs_lib.inp,v
retrieving revision 1.2
diff -u -u -r1.2 debugger_regs_lib.inp
--- debugger_regs_lib.inp	1998/07/03 02:35:58	1.2
+++ debugger_regs_lib.inp	1998/07/04 12:16:29
@@ -1,4 +1,5 @@
+toggle_echo
 
 
-p *
-c
+print *
+continue
Index: tests/debugger/interpreter.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/interpreter.inp,v
retrieving revision 1.2
diff -u -u -r1.2 interpreter.inp
--- interpreter.inp	1998/06/18 06:08:32	1.2
+++ interpreter.inp	1998/07/05 02:53:42
@@ -1,13 +1,13 @@
-h
-10s
-v
-p *
-30 g
-p *
-F
-p *
+toggle_echo
+10 step
+vars
+print *
+goto 30
+print *
+finish -a
+print *
 
-f
+finish
 
 
-c
+continue
Index: tests/debugger/interpreter_lib.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/interpreter_lib.inp,v
retrieving revision 1.2
diff -u -u -r1.2 interpreter_lib.inp
--- interpreter_lib.inp	1998/07/03 02:36:01	1.2
+++ interpreter_lib.inp	1998/07/05 02:53:45
@@ -1,14 +1,14 @@
-h
-45s
-v
-p *
-b interpreter_lib database_assert_clause
-c
-p *
-F
-p *
+toggle_echo
+45step
+vars
+print *
+break interpreter_lib database_assert_clause
+continue
+print *
+finish -a
+print *
 
-f
+finish
 
 
-c
+continue -S
Index: tests/debugger/queens.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/queens.inp,v
retrieving revision 1.2
diff -u -u -r1.2 queens.inp
--- queens.inp	1998/06/18 06:08:35	1.2
+++ queens.inp	1998/07/04 12:19:19
@@ -1,87 +1,88 @@
-p *
+toggle_echo
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
-l 1
-p *
-l 2
-v
-p *
+print *
+level 1
+print *
+up 1
+vars
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
-C
+print *
+continue -a -N
Index: tests/debugger/queens_lib.inp
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/queens_lib.inp,v
retrieving revision 1.2
diff -u -u -r1.2 queens_lib.inp
--- queens_lib.inp	1998/06/18 06:08:37	1.2
+++ queens_lib.inp	1998/07/04 12:19:30
@@ -1,87 +1,88 @@
-p *
+toggle_echo
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
-l 1
-p *
-l 2
-v
-p *
+print *
+level 1
+print *
+up 1
+vars
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
+print *
 
-p *
-C
+print *
+continue -a -N
cvs diff: Diffing tests/general
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trial
cvs diff: Diffing util



More information about the developers mailing list