[m-dev.] for review: saving the debugger's state

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Aug 28 16:32:28 AEDT 2000


For review by anyone.

Make it possible to save the state of a debugger session wrt break points
and aliases in a file that can be sourced in another debugger session to
restore the state.

trace/mercury_trace_internal.c:
	Add a new mdb command, "save <filename>", to save mdb's state to the
	named file.

	Allow the "disable", "enable" and "delete" commands to be given without
	arguments; such invocations refer to the most recently created
	breakpoint. The extension to "disable" is required by the
	implementation of the "save" command; the others are for symmetry.

	Allow the user to speficy an option to the source command that tells
	mdb not to complain if the named file cannot be processed. This should
	allow people to put into .mdbrc files commands to source saved state
	files if they exist and not get complaints if they don't.

trace/mercury_trace_spy.[ch]:
	Add code to implement the part of the "save" command concerned with
	breakpoints. Unfortunately, there is no simple way to save the
	specification of breakpoints created with "break here", so for the time
	being they are not saved. This should not be too much of a problem,
	since such breakpoints are rarely used.

	Maintain a variable that identifies the most recently added breakpoint,
	if any.

	Also move the function to print out breakpoints here from
	mercury_trace_internal.c, in order to centralize knowledge
	about breakpoints here.

trace/mercury_trace_alias.[ch]:
	Add code to implement the part of the "save" command concerned with
	aliases.

	Fix some occurrences of an old bug: use MR_free, not free, to free
	strings allocated with MR_copy_string.

trace/mercury_stack_trace.[ch]:
	Add a version of MR_print_proc_id that prints proc ids in a form
	suitable for mdb procedure specifications.

Zoltan.

cvs diff: Diffing .
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing doc
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.216
diff -u -r1.216 user_guide.texi
--- doc/user_guide.texi	2000/08/25 09:53:24	1.216
+++ doc/user_guide.texi	2000/08/28 03:54:29
@@ -2158,6 +2158,10 @@
 @item disable *
 Disables all break points.
 @sp 1
+ at item disable
+Disables the most recently added breakpoint.
+Reports an error if the most recently added breakpoint has since been deleted.
+ at sp 1
 @item enable @var{num}
 Enables the break point with the given number.
 Reports an error if there is no break point with that number.
@@ -2165,6 +2169,10 @@
 @item enable *
 Enables all break points.
 @sp 1
+ at item enable
+Enables the most recently added breakpoint.
+Reports an error if the most recently added breakpoint has since been deleted.
+ at sp 1
 @item delete @var{num}
 Deletes the break point with the given number.
 Reports an error if there is no break point with that number.
@@ -2172,6 +2180,11 @@
 @item delete *
 Deletes all break points.
 @sp 1
+ at item delete
+Deletes the most recently added breakpoint.
+Reports an error if the most recently added breakpoint
+has already been deleted.
+ at sp 1
 @item modules
 Lists all the debuggable modules
 (i.e. modules that have debugging information).
@@ -2371,8 +2384,16 @@
 @subsection Miscellaneous commands
 @sp 1
 @table @code
- at item source @var{filename}
+ at item source [-i] @var{filename}
 Executes the commands in the file named @var{filename}.
+ at sp 1
+The option @samp{-i} or @samp{--ignore-errors} tells @samp{mdb}
+not to complain if the named file does not exist or is not readable.
+ at sp 1
+ at item save @var{filename}
+Saves current set of breakpoints and the current set of aliases
+in the named file as a set of @samp{break} and @samp{alias} commands.
+Sourcing the file will recreate the current breakpoints and aliases.
 @sp 1
 @item quit [-y]
 Quits the debugger and aborts the execution of the program.
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing library
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
Index: runtime/mercury_stack_trace.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.c,v
retrieving revision 1.35
diff -u -r1.35 mercury_stack_trace.c
--- runtime/mercury_stack_trace.c	2000/08/03 06:18:55	1.35
+++ runtime/mercury_stack_trace.c	2000/08/28 03:50:03
@@ -23,6 +23,9 @@
 static	void	MR_dump_stack_record_flush(FILE *fp, 
 			MR_Print_Stack_Record print_stack_record);
 
+static	void	MR_print_proc_id_internal(FILE *fp,
+			const MR_Stack_Layout_Entry *entry, bool spec);
+
 static	void	MR_maybe_print_context(FILE *fp,
 			const char *filename, int lineno);
 static	void	MR_maybe_print_parent_context(FILE *fp, bool print_parent,
@@ -502,11 +505,29 @@
 void
 MR_print_proc_id(FILE *fp, const MR_Stack_Layout_Entry *entry)
 {
+	MR_print_proc_id_internal(fp, entry, FALSE);
+}
+
+void
+MR_print_proc_spec(FILE *fp, const MR_Stack_Layout_Entry *entry)
+{
+	MR_print_proc_id_internal(fp, entry, TRUE);
+}
+
+static void
+MR_print_proc_id_internal(FILE *fp, const MR_Stack_Layout_Entry *entry,
+	bool spec)
+{
 	if (! MR_ENTRY_LAYOUT_HAS_PROC_ID(entry)) {
 		fatal_error("cannot print procedure id without layout");
 	}
 
 	if (MR_ENTRY_LAYOUT_COMPILER_GENERATED(entry)) {
+		if (spec) {
+			fatal_error("cannot generate specifications "
+				"for compiler generated procedures");
+		}
+
 		fprintf(fp, "%s for %s:%s/%ld-%ld",
 			entry->MR_sle_comp.MR_comp_pred_name,
 			entry->MR_sle_comp.MR_comp_type_module,
@@ -531,13 +552,19 @@
 			fatal_error("procedure is not pred or func");
 		}
 
-		fprintf(fp, " %s:%s/%ld-%ld",
+		if (spec) {
+			fprintf(fp, "*");
+		} else {
+			fprintf(fp, " ");
+		}
+
+		fprintf(fp, "%s:%s/%ld-%ld",
 			entry->MR_sle_user.MR_user_decl_module,
 			entry->MR_sle_user.MR_user_name,
 			(long) entry->MR_sle_user.MR_user_arity,
 			(long) entry->MR_sle_user.MR_user_mode);
 
-		if (strcmp(entry->MR_sle_user.MR_user_decl_module,
+		if (!spec && strcmp(entry->MR_sle_user.MR_user_decl_module,
 				entry->MR_sle_user.MR_user_def_module) != 0)
 		{
 			fprintf(fp, " {%s}",
@@ -545,7 +572,9 @@
 		}
 	}
 
-	fprintf(fp, " (%s)", MR_detism_names[entry->MR_sle_detism]);
+	if (! spec) {
+		fprintf(fp, " (%s)", MR_detism_names[entry->MR_sle_detism]);
+	}
 }
 
 void
Index: runtime/mercury_stack_trace.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_stack_trace.h,v
retrieving revision 1.21
diff -u -r1.21 mercury_stack_trace.h
--- runtime/mercury_stack_trace.h	2000/08/03 06:18:56	1.21
+++ runtime/mercury_stack_trace.h	2000/08/28 03:46:58
@@ -185,6 +185,14 @@
 extern	void	MR_print_proc_id(FILE *fp, const MR_Stack_Layout_Entry *entry);
 
 /*
+** MR_print_proc_spec prints a string that uniquely specifies the given
+** procedure to the debugger.
+*/
+
+extern	void	MR_print_proc_spec(FILE *fp,
+			const MR_Stack_Layout_Entry *entry);
+
+/*
 ** MR_print_proc_id_trace_and_context prints an identification of the given
 ** procedure, together with call trace information (if available), a context
 ** within the procedure, and possibly a context identifying the caller.
cvs diff: Diffing runtime/GETOPT
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 samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/mercury_trace_alias.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_alias.c,v
retrieving revision 1.3
diff -u -r1.3 mercury_trace_alias.c
--- trace/mercury_trace_alias.c	2000/05/15 16:37:40	1.3
+++ trace/mercury_trace_alias.c	2000/08/28 02:50:56
@@ -23,7 +23,8 @@
 /* The initial size of the alias table. */
 #define	INIT_ALIAS_COUNT	32
 
-static	void		MR_trace_print_alias_num(FILE *fp, int slot);
+static	void		MR_trace_print_alias_num(FILE *fp, int slot,
+				bool mdb_command_format);
 
 void
 MR_trace_add_alias(char *name, char **words, int word_count)
@@ -38,11 +39,11 @@
 	if (found) {
 		count = MR_alias_records[slot].MR_alias_word_count;
 		for (i = 0; i < count; i++) {
-			free(MR_alias_records[slot].MR_alias_words[i]);
+			MR_free(MR_alias_records[slot].MR_alias_words[i]);
 		}
 
-		free(MR_alias_records[slot].MR_alias_name);
-		free(MR_alias_records[slot].MR_alias_words);
+		MR_free(MR_alias_records[slot].MR_alias_name);
+		MR_free(MR_alias_records[slot].MR_alias_words);
 	} else {
 		MR_ensure_room_for_next(MR_alias_record, MR_Alias,
 			INIT_ALIAS_COUNT);
@@ -77,11 +78,11 @@
 	} else {
 		count = MR_alias_records[slot].MR_alias_word_count;
 		for (i = 0; i < count; i++) {
-			free(MR_alias_records[slot].MR_alias_words[i]);
+			MR_free(MR_alias_records[slot].MR_alias_words[i]);
 		}
 
-		free(MR_alias_records[slot].MR_alias_name);
-		free(MR_alias_records[slot].MR_alias_words);
+		MR_free(MR_alias_records[slot].MR_alias_name);
+		MR_free(MR_alias_records[slot].MR_alias_words);
 
 		for (i = slot; i < MR_alias_record_next - 1; i++) {
 			MR_alias_records[slot] = MR_alias_records[slot+1];
@@ -120,28 +121,33 @@
 	MR_bsearch(MR_alias_record_next, slot, found,
 		strcmp(MR_alias_records[slot].MR_alias_name, name));
 	if (found) {
-		MR_trace_print_alias_num(fp, slot);
+		MR_trace_print_alias_num(fp, slot, FALSE);
 	} else {
 		fprintf(fp, "There is no such alias.\n");
 	}
 }
 
 void
-MR_trace_print_all_aliases(FILE *fp)
+MR_trace_print_all_aliases(FILE *fp, bool mdb_command_format)
 {
 	int	slot;
 
 	for (slot = 0; slot < MR_alias_record_next; slot++) {
-		MR_trace_print_alias_num(fp, slot);
+		MR_trace_print_alias_num(fp, slot, mdb_command_format);
 	}
 }
 
 static void
-MR_trace_print_alias_num(FILE *fp, int slot)
+MR_trace_print_alias_num(FILE *fp, int slot, bool mdb_command_format)
 {
 	int	i;
 
-	fprintf(fp, "%-6s =>   ", MR_alias_records[slot].MR_alias_name);
+	if (mdb_command_format) {
+		fprintf(fp, "alias %s", MR_alias_records[slot].MR_alias_name);
+	} else {
+		fprintf(fp, "%-6s =>   ", MR_alias_records[slot].MR_alias_name);
+	}
+
 	for (i = 0; i < MR_alias_records[slot].MR_alias_word_count; i++) {
 		fprintf(fp, " %s", MR_alias_records[slot].MR_alias_words[i]);
 	}
Index: trace/mercury_trace_alias.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_alias.h,v
retrieving revision 1.1
diff -u -r1.1 mercury_trace_alias.h
--- trace/mercury_trace_alias.h	1998/10/16 06:20:12	1.1
+++ trace/mercury_trace_alias.h	2000/08/28 01:47:23
@@ -59,9 +59,13 @@
 extern	void		MR_trace_print_alias(FILE *fp, const char *name);
 
 /*
-** Print all the aliases to the given file.
+** Print all the aliases to the given file. If mdb_command_format is TRUE,
+** print them in a form that, when sourced from mdb , recreate the aliases.
+** Otherwise, print the aliases in a format that is nice for humans to read.
 */
 
-extern	void		MR_trace_print_all_aliases(FILE *fp);
+extern	void		MR_trace_print_all_aliases(FILE *fp,
+				bool mdb_command_format);
+
 
 #endif	/* MERCURY_TRACE_ALIAS_H */
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.77
diff -u -r1.77 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	2000/08/26 17:47:02	1.77
+++ trace/mercury_trace_internal.c	2000/08/28 03:33:41
@@ -161,15 +161,15 @@
 static	bool	MR_trace_options_when_action(MR_Spy_When *when,
 			MR_Spy_Action *action, char ***words, int *word_count,
 			const char *cat, const char *item);
-static	bool	MR_trace_options_quiet(bool *verbose,
-			char ***words, int *word_count,
-			const char *cat, const char *item);
+static	bool	MR_trace_options_quiet(bool *verbose, char ***words,
+			int *word_count, const char *cat, const char *item);
+static	bool	MR_trace_options_ignore(bool *ignore_errors, char ***words,
+			int *word_count, const char *cat, const char *item);
 static	bool	MR_trace_options_detailed(bool *detailed, char ***words,
 			int *word_count, const char *cat, const char *item);
 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_print_spy_point(int i);
 static	void	MR_trace_do_noop(void);
 
 static	void	MR_trace_set_level_and_report(int ancestor_level,
@@ -186,7 +186,7 @@
 			char ***words_ptr, int *word_max_ptr);
 static	void	MR_trace_expand_aliases(char ***words,
 			int *word_max, int *word_count);
-static	bool	MR_trace_source(const char *filename);
+static	bool	MR_trace_source(const char *filename, bool ignore_errors);
 static	void	MR_trace_source_from_open_file(FILE *fp);
 static	char	*MR_trace_getline_queue(void);
 static	void	MR_insert_line_at_head(const char *line);
@@ -332,7 +332,7 @@
 
 	init = getenv("MERCURY_DEBUGGER_INIT");
 	if (init != NULL) {
-		(void) MR_trace_source(init);
+		(void) MR_trace_source(init, FALSE);
 		/* If the source failed, the error message has been printed. */
 	}
 }
@@ -967,7 +967,7 @@
 			count = 0;
 			for (i = 0; i < MR_spy_point_next; i++) {
 				if (MR_spy_points[i]->spy_exists) {
-					MR_print_spy_point(i);
+					MR_print_spy_point(MR_mdb_out, i);
 					count++;
 				}
 			}
@@ -992,7 +992,7 @@
 			MR_register_all_modules_and_procs(MR_mdb_out, TRUE);
 			slot = MR_add_proc_spy_point(MR_SPY_SPECIFIC, action,
 					layout->MR_sll_entry, layout);
-			MR_print_spy_point(slot);
+			MR_print_spy_point(MR_mdb_out, slot);
 		} else if (word_count == 2 &&
 				MR_parse_proc_spec(words[1], &spec))
 		{
@@ -1004,11 +1004,11 @@
 			if (matches.match_proc_next == 0) {
 				fflush(MR_mdb_out);
 				fprintf(MR_mdb_err,
-					"There is no such procedure.\n");
+					"mdb: there is no such procedure.\n");
 			} else if (matches.match_proc_next == 1) {
 				slot = MR_add_proc_spy_point(when, action,
 					matches.match_procs[0], NULL);
-				MR_print_spy_point(slot);
+				MR_print_spy_point(MR_mdb_out, slot);
 			} else {
 				char	buf[80];
 				int	i;
@@ -1043,7 +1043,8 @@
 							when, action,
 							matches.match_procs[i],
 							NULL);
-						MR_print_spy_point(slot);
+						MR_print_spy_point(MR_mdb_out,
+							slot);
 					}
 
 					MR_free(line2);
@@ -1055,7 +1056,8 @@
 							when, action,
 							matches.match_procs[i],
 							NULL);
-						MR_print_spy_point(slot);
+						MR_print_spy_point(MR_mdb_out,
+							slot);
 					} else {
 						fprintf(MR_mdb_out,
 							"no such match\n");
@@ -1073,11 +1075,11 @@
 
 			slot = MR_add_line_spy_point(action, file, line);
 			if (slot >= 0) {
-				MR_print_spy_point(slot);
+				MR_print_spy_point(MR_mdb_out, slot);
 			} else {
 				fflush(MR_mdb_out);
 				fprintf(MR_mdb_err,
-					"There is no event at %s:%d.\n",
+					"mdb: there is no event at %s:%d.\n",
 					file, line);
 			}
 		} else if (word_count == 2 &&
@@ -1089,11 +1091,11 @@
 				slot = MR_add_line_spy_point(action, file,
 					breakline);
 				if (slot >= 0) {
-					MR_print_spy_point(slot);
+					MR_print_spy_point(MR_mdb_out, slot);
 				} else {
 					fflush(MR_mdb_out);
 					fprintf(MR_mdb_err,
-						"There is no event "
+						"mdb: there is no event "
 						"at %s:%d.\n",
 						file, breakline);
 				}
@@ -1110,11 +1112,11 @@
 					&& MR_spy_points[n]->spy_exists)
 			{
 				MR_spy_points[n]->spy_enabled = TRUE;
-				MR_print_spy_point(n);
+				MR_print_spy_point(MR_mdb_out, n);
 			} else {
 				fflush(MR_mdb_out);
-				fprintf(MR_mdb_err,
-					"Break point #%d does not exist.\n",
+				fprintf(MR_mdb_err, "mdb: break point #%d "
+					"does not exist.\n",
 					n);
 			}
 		} else if (word_count == 2 && streq(words[1], "*")) {
@@ -1125,7 +1127,7 @@
 			for (i = 0; i < MR_spy_point_next; i++) {
 				if (MR_spy_points[i]->spy_exists) {
 					MR_spy_points[i]->spy_enabled = TRUE;
-					MR_print_spy_point(i);
+					MR_print_spy_point(MR_mdb_out, i);
 					count++;
 				}
 			}
@@ -1134,21 +1136,37 @@
 				fprintf(MR_mdb_err,
 					"There are no break points.\n");
 			}
+		} else if (word_count == 1) {
+			if (0 <= MR_most_recent_spy_point
+				&& MR_most_recent_spy_point < MR_spy_point_next
+				&& MR_spy_points[MR_most_recent_spy_point]->
+					spy_exists)
+			{
+				MR_spy_points[MR_most_recent_spy_point]
+					->spy_enabled = TRUE;
+				MR_print_spy_point(MR_mdb_out,
+					MR_most_recent_spy_point);
+			} else {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err, "mdb: there is no "
+					"most recent break point.\n");
+			}
 		} else {
 			MR_trace_usage("breakpoint", "enable");
 		}
 	} else if (streq(words[0], "disable")) {
 		int	n;
+
 		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
 			if (0 <= n && n < MR_spy_point_next
 					&& MR_spy_points[n]->spy_exists)
 			{
 				MR_spy_points[n]->spy_enabled = FALSE;
-				MR_print_spy_point(n);
+				MR_print_spy_point(MR_mdb_out, n);
 			} else {
 				fflush(MR_mdb_out);
-				fprintf(MR_mdb_err,
-					"Break point #%d does not exist.\n",
+				fprintf(MR_mdb_err, "mdb: break point #%d "
+					"does not exist.\n",
 					n);
 			}
 		} else if (word_count == 2 && streq(words[1], "*")) {
@@ -1159,7 +1177,7 @@
 			for (i = 0; i < MR_spy_point_next; i++) {
 				if (MR_spy_points[i]->spy_exists) {
 					MR_spy_points[i]->spy_enabled = FALSE;
-					MR_print_spy_point(i);
+					MR_print_spy_point(MR_mdb_out, i);
 					count++;
 				}
 			}
@@ -1169,21 +1187,37 @@
 				fprintf(MR_mdb_err,
 					"There are no break points.\n");
 			}
+		} else if (word_count == 1) {
+			if (0 <= MR_most_recent_spy_point
+				&& MR_most_recent_spy_point < MR_spy_point_next
+				&& MR_spy_points[MR_most_recent_spy_point]->
+					spy_exists)
+			{
+				MR_spy_points[MR_most_recent_spy_point]
+					->spy_enabled = FALSE;
+				MR_print_spy_point(MR_mdb_out,
+					MR_most_recent_spy_point);
+			} else {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err, "There is no "
+					"most recent break point.\n");
+			}
 		} else {
 			MR_trace_usage("breakpoint", "disable");
 		}
 	} else if (streq(words[0], "delete")) {
 		int	n;
+
 		if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
 			if (0 <= n && n < MR_spy_point_next
 					&& MR_spy_points[n]->spy_exists)
 			{
 				MR_delete_spy_point(n);
-				MR_print_spy_point(n);
+				MR_print_spy_point(MR_mdb_out, n);
 			} else {
 				fflush(MR_mdb_out);
-				fprintf(MR_mdb_err,
-					"Break point #%d does not exist.\n",
+				fprintf(MR_mdb_err, "mdb: break point #%d "
+					"does not exist.\n",
 					n);
 			}
 		} else if (word_count == 2 && streq(words[1], "*")) {
@@ -1194,7 +1228,7 @@
 			for (i = 0; i < MR_spy_point_next; i++) {
 				if (MR_spy_points[i]->spy_exists) {
 					MR_delete_spy_point(i);
-					MR_print_spy_point(i);
+					MR_print_spy_point(MR_mdb_out, i);
 					count++;
 				}
 			}
@@ -1204,6 +1238,27 @@
 				fprintf(MR_mdb_err,
 					"There are no break points.\n");
 			}
+		} else if (word_count == 1) {
+			if (0 <= MR_most_recent_spy_point
+				&& MR_most_recent_spy_point < MR_spy_point_next
+				&& MR_spy_points[MR_most_recent_spy_point]->
+					spy_exists)
+			{
+				int	slot;
+
+				/*
+				** MR_delete_spy_point() will clobber
+				** MR_most_recent_spy_point.
+				*/
+
+				slot = MR_most_recent_spy_point;
+				MR_delete_spy_point(slot);
+				MR_print_spy_point(MR_mdb_out, slot);
+			} else {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err, "mdb: there is no "
+					"most recent break point.\n");
+			}
 		} else {
 			MR_trace_usage("breakpoint", "delete");
 		}
@@ -1441,7 +1496,7 @@
 		}
 	} else if (streq(words[0], "alias")) {
 		if (word_count == 1) {
-			MR_trace_print_all_aliases(MR_mdb_out);
+			MR_trace_print_all_aliases(MR_mdb_out, FALSE);
 		} else if (word_count == 2) {
 			MR_trace_print_alias(MR_mdb_out, words[1]);
 		} else {
@@ -1627,15 +1682,60 @@
 			MR_trace_usage("developer", "all_regs");
 		}
 	} else if (streq(words[0], "source")) {
-		if (word_count == 2) {
+		bool	ignore_errors;
+
+		ignore_errors = FALSE;
+		if (! MR_trace_options_ignore(&ignore_errors,
+			&words, &word_count, "misc", "source"))
+		{
+			; /* the usage message has already been printed */
+		} else if (word_count == 2)
+		{
 			/*
 			** If the source fails, the error message
-			** will have already been printed by MR_trace_source.
+			** will have already been printed by MR_trace_source
+			** (unless ignore_errors suppresses the message).
 			*/
-			(void) MR_trace_source(words[1]);
+			(void) MR_trace_source(words[1], ignore_errors);
 		} else {
 			MR_trace_usage("misc", "source");
 		}
+	} else if (streq(words[0], "save")) {
+		if (word_count == 2) {
+			FILE	*fp;
+			bool	found_error;
+
+			fp = fopen(words[1], "w");
+			if (fp == NULL) {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err,
+					"mdb: error opening `%s': %s.\n",
+					words[1], strerror(errno));
+				return KEEP_INTERACTING;
+			}
+
+			MR_trace_print_all_aliases(fp, TRUE);
+			found_error = MR_save_spy_points(fp, MR_mdb_err);
+
+			if (found_error) {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err, "mdb: could not save "
+					"debugger state to %s.\n",
+					words[1]);
+				(void) fclose(fp);
+			} else if (fclose(fp) != 0) {
+				fflush(MR_mdb_out);
+				fprintf(MR_mdb_err,
+					"mdb: error closing `%s': %s.\n",
+					words[1], strerror(errno));
+			} else {
+				fprintf(MR_mdb_out,
+					"Debugger state saved to %s.\n",
+					words[1]);
+			}
+		} else {
+			MR_trace_usage("misc", "save");
+		}
 	} else if (streq(words[0], "quit")) {
 		bool	confirmed;
 
@@ -2008,6 +2108,39 @@
 	return TRUE;
 }
 
+static struct MR_option MR_trace_ignore_opts[] =
+{
+	{ "ignore-errors",	FALSE,	NULL,	'i' },
+	{ NULL,			FALSE,	NULL,	0 }
+};
+
+static bool
+MR_trace_options_ignore(bool *ignore_errors, char ***words, int *word_count,
+	const char *cat, const char *item)
+{
+	int	c;
+
+	MR_optind = 0;
+	while ((c = MR_getopt_long(*word_count, *words, "i",
+			MR_trace_ignore_opts, NULL)) != EOF)
+	{
+		switch (c) {
+
+			case 'i':
+				*ignore_errors = TRUE;
+				break;
+
+			default:
+				MR_trace_usage(cat, item);
+				return FALSE;
+		}
+	}
+
+	*words = *words + MR_optind - 1;
+	*word_count = *word_count - MR_optind + 1;
+	return TRUE;
+}
+
 static void
 MR_trace_usage(const char *cat, const char *item)
 /* cat is unused now, but could be used later */
@@ -2018,28 +2151,6 @@
 		item, item);
 }
 
-static void
-MR_print_spy_point(int spy_point_num)
-{
-	MR_Spy_Point	*point;
-
-	point = MR_spy_points[spy_point_num];
-	fprintf(MR_mdb_out, "%2d: %1s %-5s %9s ",
-		spy_point_num,
-		point->spy_exists ?
-			(point->spy_enabled ? "+" : "-") :
-			(point->spy_enabled ? "E" : "D"),
-		MR_spy_action_string(point->spy_action),
-		MR_spy_when_names[point->spy_when]);
-	if (point->spy_when == MR_SPY_LINENO) {
-		fprintf(MR_mdb_out, "%s:%d\n",
-			point->spy_filename, point->spy_linenumber);
-	} else {
-		MR_print_proc_id(MR_mdb_out, point->spy_proc);
-		fprintf(MR_mdb_out, "\n");
-	}
-}
-
 /*
 ** Read lines until we find one that contains only "end".
 ** Return the lines concatenated together.
@@ -2262,7 +2373,7 @@
 }
 
 static bool
-MR_trace_source(const char *filename)
+MR_trace_source(const char *filename, bool ignore_errors)
 {
 	FILE	*fp;
 
Index: trace/mercury_trace_spy.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_spy.c,v
retrieving revision 1.11
diff -u -r1.11 mercury_trace_spy.c
--- trace/mercury_trace_spy.c	2000/08/28 02:31:45	1.11
+++ trace/mercury_trace_spy.c	2000/08/28 03:52:33
@@ -40,6 +40,8 @@
 int			MR_spy_point_next = 0;
 int			MR_spy_point_max  = 0;
 
+int			MR_most_recent_spy_point = -1;
+
 /* The initial size of the spy points table. */
 #define	MR_INIT_SPY_POINTS	10
 
@@ -331,6 +333,7 @@
 	MR_spy_points[point_slot] = point;
 	MR_spy_point_next++;
 
+	MR_most_recent_spy_point = point_slot;
 	return point_slot;
 }
 
@@ -382,6 +385,7 @@
 	MR_spy_points[point_slot] = point;
 	MR_spy_point_next++;
 
+	MR_most_recent_spy_point = point_slot;
 	return point_slot;
 }
 
@@ -423,6 +427,10 @@
 
 	point = MR_spy_points[point_table_slot];
 
+	if (MR_most_recent_spy_point == point_table_slot) {
+		MR_most_recent_spy_point = -1;
+	}
+
 	/* this effectively removes the point from the spypoint table */
 	point->spy_exists = FALSE;
 
@@ -474,4 +482,98 @@
 
 		*cur_addr = point->spy_next;
 	}
+}
+
+void
+MR_print_spy_point(FILE *fp, int spy_point_num)
+{
+	MR_Spy_Point	*point;
+
+	point = MR_spy_points[spy_point_num];
+	fprintf(fp, "%2d: %1s %-5s %9s ",
+		spy_point_num,
+		point->spy_exists ?
+			(point->spy_enabled ? "+" : "-") :
+			(point->spy_enabled ? "E" : "D"),
+		MR_spy_action_string(point->spy_action),
+		MR_spy_when_names[point->spy_when]);
+	if (point->spy_when == MR_SPY_LINENO) {
+		fprintf(fp, "%s:%d\n",
+			point->spy_filename, point->spy_linenumber);
+	} else {
+		MR_print_proc_id(fp, point->spy_proc);
+		fprintf(fp, "\n");
+	}
+}
+
+bool
+MR_save_spy_points(FILE *fp, FILE *err_fp)
+{
+	MR_Spy_Point	*point;
+	int		i;
+
+	for (i = 0; i < MR_spy_point_next; i++) {
+		if (! MR_spy_points[i]->spy_exists) {
+			continue;
+		}
+
+		point = MR_spy_points[i];
+
+		switch (point->spy_action) {
+			case MR_SPY_STOP:
+				fprintf(fp, "break ");
+				break;
+
+			case MR_SPY_PRINT:
+				fprintf(fp, "break -P ");
+				break;
+
+			default:
+				fprintf(err_fp, "internal error: "
+					"unknown spy action\n");
+				return TRUE;
+		}
+
+		switch (point->spy_when) {
+			case MR_SPY_LINENO:
+				fprintf(fp, "%s:%d\n",
+					point->spy_filename,
+					point->spy_linenumber);
+				break;
+
+			case MR_SPY_ALL:
+				fprintf(fp, "-a ");
+				MR_print_proc_spec(fp, point->spy_proc);
+				fprintf(fp, "\n");
+				break;
+
+			case MR_SPY_INTERFACE:
+				MR_print_proc_spec(fp, point->spy_proc);
+				fprintf(fp, "\n");
+				break;
+
+			case MR_SPY_ENTRY:
+				fprintf(fp, "-e ");
+				MR_print_proc_spec(fp, point->spy_proc);
+				fprintf(fp, "\n");
+				break;
+
+			case MR_SPY_SPECIFIC:
+				fprintf(err_fp, "mdb: cannot save "
+					"breakpoint on specific "
+					"internal label\n");
+				break;
+
+			default:
+				fprintf(err_fp, "mdb: internal error: "
+					"unknown spy when\n");
+				return TRUE;
+		}
+
+		if (!point->spy_enabled) {
+			fprintf(fp, "disable\n");
+		}
+	}
+
+	return FALSE;
 }
Index: trace/mercury_trace_spy.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_spy.h,v
retrieving revision 1.3
diff -u -r1.3 mercury_trace_spy.h
--- trace/mercury_trace_spy.h	1999/11/15 00:43:58	1.3
+++ trace/mercury_trace_spy.h	2000/08/28 03:25:37
@@ -55,6 +55,8 @@
 extern	int		MR_spy_point_next;
 extern	int		MR_spy_point_max;
 
+extern	int		MR_most_recent_spy_point;
+
 /*
 ** Check whether the event described by the given label layout and port
 ** matches any spy points. If yes, return TRUE and set *action to say what
@@ -88,5 +90,22 @@
 */
 
 extern	void		MR_delete_spy_point(int point_table_slot);
+
+/*
+** Print the spy point with the given number in a nice format for humans to
+** read to the given file.
+*/
+
+extern	void		MR_print_spy_point(FILE *fp, int i);
+
+/*
+** Print the set of current spy points (including those that are currently
+** disabled) to fp in a format that, when sourced by mdb, recreates those
+** spy points. Any internal errors encountered while trying to do this
+** should be reported to err_fp. Return TRUE iff the debugger's data structures
+** are inconsistent, and the spy points could not be saved.
+*/
+
+extern	bool		MR_save_spy_points(FILE *fp, FILE *err_fp);
 
 #endif	/* not MERCURY_TRACE_SPY_H */
cvs diff: Diffing trax
cvs diff: Diffing trial
cvs diff: Diffing util
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list