for review: add mdb support for interactive queries

Fergus Henderson fjh at cs.mu.OZ.AU
Thu Mar 4 10:50:57 AEDT 1999


Anyone care to review this?

Estimated hours taken: 14

Add support for invoking interactive queries to mdb.

browser/interactive_query.m:
	New module, to implement interactive queries.

browser/dl.m:
browser/name_mangle.m:
	Copy these files from extras/dynamic_linking, since
	they are needed by browser/interactive_query.m.

configure.in:
runtime/mercury_conf.h.in:
	Autodetect the presence of support for dlopen() etc.

browser/dl.m:
	Add #ifdefs so that the code will compile (but report
	an error at runtime) if dlopen() etc. are not supported.

browser/browser_library.m:
	Add interface_query, dl, and name_mangle to the list of
	modules in this library.

trace/mercury_trace_browse.h:
trace/mercury_trace_browse.c:
	Add a new function MR_trace_query() to interface to the ML_query()
	function defined by browser/interfactive_query.m.

trace/mercury_trace_internal.c:
	Add code to implement new commands `query', `cc_query', `io_query',
	and `mmc_options', using the MR_trace_query() function defined by
	trace/mercury_trace_browse.h.

runtime/mercury_grade.h:
	Add code to define MR_GRADE_OPT, so that browser/interactive_query.m
	can use this to invoke mmc with the same grade that the executable
	being debugged was built with.

doc/mdb_categories:
doc/user_guide.texi:
	Document the new commands `query', `cc_query', `io_query',
	and `mmc_options'.

Index: browser/browser_library.m
===================================================================
RCS file: /home/mercury1/repository/mercury/browser/browser_library.m,v
retrieving revision 1.2
diff -u -r1.2 browser_library.m
--- browser_library.m	1998/10/25 07:16:39	1.2
+++ browser_library.m	1999/03/03 14:50:16
@@ -14,10 +14,8 @@
 
 :- import_module help.
 :- import_module debugger_interface.
-:- import_module browse.
-:- import_module frame.
-:- import_module parse.
-:- import_module util.
+:- import_module browse, frame, parse, util.
+:- import_module interactive_query, dl, name_mangle.
 
 % See library/library.m for why we implement this predicate this way.
 
cvs diff: browser/dl.m is a new entry, no comparison available
cvs diff: browser/interactive_query.m is a new entry, no comparison available
cvs diff: browser/name_mangle.m is a new entry, no comparison available
Index: configure.in
===================================================================
RCS file: /home/mercury1/repository/mercury/configure.in,v
retrieving revision 1.148
diff -u -r1.148 configure.in
--- configure.in	1999/02/01 02:02:26	1.148
+++ configure.in	1999/03/03 17:54:42
@@ -279,6 +279,12 @@
 	AC_DEFINE(HAVE_SYS_TIME)
 fi
 #-----------------------------------------------------------------------------#
+AC_CHECK_HEADER(dlfcn.h, HAVE_DLFCN_H=1)
+if test "$HAVE_DLFCN_H" = 1; then
+	AC_DEFINE(HAVE_DLFCN_H)
+fi
+AC_HAVE_FUNCS(dlopen dlclose dlsym dlerror)
+#-----------------------------------------------------------------------------#
 #
 # check the basics of sigaction
 #
Index: doc/mdb_categories
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/mdb_categories,v
retrieving revision 1.3
diff -u -r1.3 mdb_categories
--- mdb_categories	1998/11/15 14:00:23	1.3
+++ mdb_categories	1999/03/03 23:44:22
@@ -2,6 +2,11 @@
 concepts   - The concepts on which the Mercury debugger is based.
 
 end
+document_category 150 queries
+queries    - Commands for invoking goals interactively.
+             The commands for queries are
+	     `query', `cc_query', and `io_query'.
+end
 document_category 200 forward
 forward    - Commands that move execution forward.
              The forward commands are `step', `goto', `finish', `forward',
@@ -28,7 +33,7 @@
 document_category 600 parameter
 parameter  - Commands that let users access debugger parameters.
              The parameter commands are `printlevel', `echo', `scroll',
-	     `alias' and `unalias'.
+	     `mmc_options', `alias' and `unalias'.
 
 end
 document_category 700 help
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.157
diff -u -r1.157 user_guide.texi
--- user_guide.texi	1999/02/21 10:09:43	1.157
+++ user_guide.texi	1999/03/03 23:27:34
@@ -1327,6 +1327,7 @@
 even if the number and the command are not separated by white space.
 
 @menu
+* Interactive query commands::
 * Forward movement commands::
 * Backward movement commands::
 * Browsing commands::
@@ -1338,6 +1339,53 @@
 * Miscellaneous commands::
 @end menu
 
+ at node Interactive query commands
+ at subsection Interactive query commands
+
+ at table @code
+ at item query @var{module1} @var{module2} @dots{}
+ at itemx cc_query @var{module1} @var{module2} @dots{}
+ at itemx io_query @var{module1} @var{module2} @dots{}
+These commands allow you to type in queries (goals) interactively
+in the debugger.  When you use one of these commands, the debugger
+will respond with a query prompt (@samp{?-} or @samp{run <--}),
+at which you can type in a goal; the debugger will the compile
+and execute the goal and display the answer(s).
+You can return from the query prompt to the @samp{mdb>} prompt
+by typing the end-of-file indicator (typically control-D or control-Z),
+or by typing @samp{quit.}.
+
+The module names @var{module1}, @var{module2}, @dots{} specify
+which modules will be imported.  You need to import all the modules
+that define symbols used in your query.  Note that you can also
+add new modules to the list of imports directly at the query prompt,
+by using a command of the form @samp{["@var{module}"]}, e.g. @samp{["int"]}.
+
+The three variants differ in what kind of goals they allow. 
+For goals which perform I/O, you need to use @samp{io_query};
+this lets you type in the goal using DCG syntax.
+For goals which don't do I/O, but which have determinism
+ at samp{cc_nondet} or @samp{cc_multi}, you you need to use @samp{cc_query};
+this finds only one solution to the specified goal.
+For all other goals, you can use plain @samp{query}, which
+finds all the solutions to the goal.
+
+For @samp{query} and @samp{cc_query}, the debugger will print
+out all the variables in the goal using @samp{io__write}.
+The goal must bind all of its variables to ground terms,
+otherwise you will get a mode error.
+
+The current implementation works by compiling the queries on-the-fly
+and then dynamically linking them into the program being debugged.
+Thus it make take a little while for your query to be executed.
+Each query will be written to a file named @file{query.m} in the current
+directory, so make sure you don't name your source file @file{query.m}.
+Note that dynamic linking may not be supported on some systems;
+if your using a system for which dynamic linking is not supported,
+you will get an error message when you try to run these commands.
+
+ at end table
+
 @node Forward movement commands
 @subsection Forward movement commands
 
@@ -1673,6 +1721,13 @@
 @subsection Parameter commands
 @sp 1
 @table @code
+ at item mmc_options @var{option1} @var{option2} @dots{}
+This command sets the options that will be passed to @samp{mmc}
+to compile your query when you use one of the query commands
+(@samp{query}, @samp{cc_query}, or @samp{io_query}.
+For example, if a query results in a compile error,
+it may sometimes be helpful to use @samp{mmc_options --verbose-errors}.
+ at sp 1
 @item printlevel none
 Sets the default print level to @samp{none}.
 @sp 1
Index: runtime/mercury_conf.h.in
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf.h.in,v
retrieving revision 1.9
diff -u -r1.9 mercury_conf.h.in
--- mercury_conf.h.in	1998/12/15 00:22:11	1.9
+++ mercury_conf.h.in	1999/03/03 17:54:55
@@ -72,6 +72,7 @@
 **	HAVE_SYS_TIME		we have <sys/time.h>
 **	HAVE_SYS_PARAM		we have <sys/param.h>
 **	HAVE_SYS_WAIT		we have <sys/wait.h>
+**	HAVE_DLFCN_H		we have <dlfcn.h>
 */
 #undef	HAVE_SYS_SIGINFO
 #undef	HAVE_UCONTEXT
@@ -80,19 +81,24 @@
 #undef	HAVE_SYS_TIME
 #undef	HAVE_SYS_PARAM
 #undef	HAVE_SYS_WAIT
+#undef	HAVE_DLFCN_H
 
 /*
 ** The following macros are defined iff the corresponding function or
 ** system call is available:
 **
 **	HAVE_SYSCONF     	we have the sysconf() system call.
-**	HAVE_SIGACTION		we have the sigaction() sysstem call.
+**	HAVE_SIGACTION		we have the sigaction() system call.
 **	HAVE_GETPAGESIZE 	we have the getpagesize() system call.
 **	HAVE_MPROTECT    	we have the mprotect() system call.
 **	HAVE_MEMALIGN    	we have the memalign() function.
 **	HAVE_STRERROR    	we have the strerror() function.
 **	HAVE_SETITIMER   	we have the setitimer() function.
 **	HAVE_MEMMOVE   		we have the memmove() function.
+**	HAVE_DLOPEN   		we have the dlopen() function.
+**	HAVE_DLCLOSE   		we have the dlclose() function.
+**	HAVE_DLSYM   		we have the dlsym() function.
+**	HAVE_DLERROR   		we have the dlerror() function.
 */
 #undef	HAVE_SYSCONF
 #undef	HAVE_SIGACTION
@@ -102,6 +108,10 @@
 #undef	HAVE_STRERROR
 #undef	HAVE_SETITIMER
 #undef	HAVE_MEMMOVE
+#undef	HAVE_DLOPEN
+#undef	HAVE_DLCLOSE
+#undef	HAVE_DLSYM
+#undef	HAVE_DLERROR
 
 /*
 ** RETSIGTYPE: the return type of signal handlers.
Index: runtime/mercury_grade.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_grade.h,v
retrieving revision 1.15
diff -u -r1.15 mercury_grade.h
--- mercury_grade.h	1998/11/11 01:53:06	1.15
+++ mercury_grade.h	1999/03/03 15:26:06
@@ -191,4 +191,123 @@
 
 extern const char MR_GRADE_VAR;
 
+/*
+** Here we do the same thing as above, but this time we build up a string
+** containing the options to pass to the compiler to select this grade.
+*/
+
+#ifdef USE_ASM_LABELS
+  #define MR_GRADE_OPT_PART_1	"asm_"
+#else
+  #define MR_GRADE_OPT_PART_1	""
+#endif
+
+#ifdef USE_GCC_NONLOCAL_GOTOS
+  #ifdef USE_GCC_GLOBAL_REGISTERS
+    #define MR_GRADE_OPT_PART_2	MR_GRADE_OPT_PART_1 "fast"
+  #else
+    #define MR_GRADE_OPT_PART_2	MR_GRADE_OPT_PART_1 "jump"
+  #endif
+#else
+  #ifdef USE_GCC_GLOBAL_REGISTERS
+    #define MR_GRADE_OPT_PART_2	MR_GRADE_OPT_PART_1 "reg"
+  #else
+    #define MR_GRADE_OPT_PART_2	MR_GRADE_OPT_PART_1 "none"
+  #endif
+#endif
+
+#ifdef MR_THREAD_SAFE
+  #define MR_GRADE_OPT_PART_3	MR_GRADE_OPT_PART_2 ".par"
+#else
+  #define MR_GRADE_OPT_PART_3	MR_GRADE_OPT_PART_2
+#endif
+#ifdef CONSERVATIVE_GC
+  #define MR_GRADE_OPT_PART_4	MR_GRADE_OPT_PART_3 ".gc"
+#elif defined(NATIVE_GC)
+  #define MR_GRADE_OPT_PART_4	MR_GRADE_OPT_PART_3 ".agc"
+#else
+  #define MR_GRADE_OPT_PART_4	MR_GRADE_OPT_PART_3
+#endif
+
+#ifdef PROFILE_TIME
+  #ifdef PROFILE_CALLS
+    #ifdef PROFILE_MEMORY
+      #define MR_GRADE_OPT_PART_5	MR_GRADE_OPT_PART_4 ".profall"
+    #else
+      #define MR_GRADE_OPT_PART_5	MR_GRADE_OPT_PART_4 ".prof"
+    #endif
+  #else
+    #ifdef PROFILE_MEMORY
+      /*
+      ** Memory profiling interferes with time profiling,
+      ** so there's no point in allowing this.
+      */
+      #error "Invalid combination of profiling options"
+    #else
+      /* Currently useless "but... */
+      #define MR_GRADE_OPT_PART_5	MR_GRADE_OPT_PART_4 ".proftime"
+    #endif
+  #endif
+#else
+  #ifdef PROFILE_CALLS
+    #ifdef PROFILE_MEMORY
+      #define MR_GRADE_OPT_PART_5	MR_GRADE_OPT_PART_4 ".memprof"
+    #else
+      #define MR_GRADE_OPT_PART_5	MR_GRADE_OPT_PART_4 ".profcalls"
+    #endif
+  #else
+    #ifdef PROFILE_MEMORY
+      /*
+      ** Call-graph memory profiling requires call profiling,
+      ** and call profiling is reasonably cheap "so there's
+      ** no point in allowing this.
+      */
+      #error "Invalid combination of profiling options"
+    #else
+      #define MR_GRADE_OPT_PART_5	MR_GRADE_OPT_PART_4
+    #endif
+  #endif
+#endif
+
+#ifdef MR_USE_TRAIL
+  #define MR_GRADE_OPT_PART_6	MR_GRADE_OPT_PART_5 ".tr"
+#else
+  #define MR_GRADE_OPT_PART_6	MR_GRADE_OPT_PART_5
+#endif
+
+/*
+** Parts 7-10 above (i.e. tag bits, compact args, (un)boxed float, and
+** debugging of the nondet stack) are documented as "not for general use",
+** and can't be set via the `--grade' option; we don't bother to pass them on.
+*/
+
+#if defined(PIC_REG) && defined(USE_GCC_GLOBAL_REGISTERS) && defined(__i386__)
+  #define MR_GRADE_OPT_PART_11	MR_GRADE_OPT_PART_6 ".picreg"
+#else
+  #define MR_GRADE_OPT_PART_11	MR_GRADE_OPT_PART_6
+#endif
+
+/*
+** Stack traces aren't strictly binary incompatible - but if you
+** try to do a stack trace you might find it doesn't work very
+** well unless all modules are compiled in with --stack-trace.
+** Hence we consider it effectively binary incompatible.
+** Similar considerations apply to procedure call tracing.
+*/
+#if defined(MR_STACK_TRACE)
+  #if defined(MR_REQUIRE_TRACING)
+    #define MR_GRADE_OPT_PART_12	MR_GRADE_OPT_PART_11 ".debug"
+  #else
+    #define MR_GRADE_OPT_PART_12	MR_GRADE_OPT_PART_11 ".strce"
+  #endif
+#else
+  #if defined(MR_REQUIRE_TRACING)
+    #define MR_GRADE_OPT_PART_12	MR_GRADE_OPT_PART_11 ".trace"
+  #else
+    #define MR_GRADE_OPT_PART_12	MR_GRADE_OPT_PART_11
+  #endif
+#endif
+
+#define MR_GRADE_OPT		MR_GRADE_OPT_PART_12
+
 #endif /* MERCURY_GRADES_H */
Index: trace/mercury_trace_browse.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_browse.c,v
retrieving revision 1.2
diff -u -r1.2 mercury_trace_browse.c
--- mercury_trace_browse.c	1998/12/28 03:38:53	1.2
+++ mercury_trace_browse.c	1999/03/03 18:01:27
@@ -9,7 +9,8 @@
 **
 ** Main author: fjh
 **
-** This file provides the C interface to browser/browse.m.
+** This file provides the C interface to browser/browse.m
+** and browser/interactive_query.m.
 */
 
 /*
@@ -26,6 +27,7 @@
 #include "mercury_trace_internal.h"
 #include "mercury_deep_copy.h"
 #include "browse.h"
+#include "interactive_query.h"
 #include "std_util.h"
 #include <stdio.h>
 
@@ -97,4 +99,35 @@
 					(Word *) MR_trace_browser_state_type);
 		done = TRUE;
 	}
+}
+
+void
+MR_trace_query(MR_Query_Type type, const char *options, int num_imports,
+	char *imports[])
+{
+	ConstString options_on_heap;
+	Word imports_list;
+	MercuryFile mdb_in, mdb_out;
+	int i;
+
+	MR_c_file_to_mercury_file(MR_mdb_in, &mdb_in);
+	MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
+
+	if (options == NULL) options = "";
+
+        MR_TRACE_USE_HP(
+		make_aligned_string(options_on_heap, options);
+
+		imports_list = list_empty();
+		for (i = num_imports; i > 0; i--) {
+			ConstString this_import;
+			make_aligned_string(this_import, imports[i - 1]);
+			imports_list = list_cons(this_import, imports_list);
+		}
+	);
+
+	MR_TRACE_CALL_MERCURY(
+		ML_query(type, imports_list, (String) options_on_heap,
+			(Word) &mdb_in, (Word) &mdb_out);
+	);
 }
Index: trace/mercury_trace_browse.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_browse.h,v
retrieving revision 1.1
diff -u -r1.1 mercury_trace_browse.h
--- mercury_trace_browse.h	1998/11/15 16:47:51	1.1
+++ mercury_trace_browse.h	1999/03/03 19:18:22
@@ -7,7 +7,8 @@
 /*
 ** mercury_trace_browse.h
 **
-** Defines the interface of the term browser for the internal debugger.
+** Defines the interface of the term browser and the interactive query
+** facility for the internal debugger.
 */
 
 #ifndef	MERCURY_TRACE_BROWSE_H
@@ -22,5 +23,16 @@
 ** Display a term (non-interactively).
 */
 extern	void	MR_trace_print(Word type_info, Word value);
+
+
+/*
+** Invoke an interactive query.
+*/
+
+/* This must kept in sync with query_type in browser/interactive.m. */
+typedef enum { MR_NORMAL_QUERY, MR_CC_QUERY, MR_IO_QUERY } MR_Query_Type;
+
+extern	void	MR_trace_query(MR_Query_Type type, const char *options,
+			int num_imports, /* const */ char *imports[]);
 
 #endif	/* MERCURY_TRACE_BROWSE_H */
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.29
diff -u -r1.29 mercury_trace_internal.c
--- mercury_trace_internal.c	1999/02/23 08:06:50	1.29
+++ mercury_trace_internal.c	1999/03/03 19:18:55
@@ -403,6 +403,8 @@
 	MR_print_proc_id_for_debugger(fp, entry_layout);
 }
 
+/* Options to pass to mmc when compiling queries. */
+static char *MR_mmc_options = NULL;
 
 static MR_Next
 MR_trace_debug_cmd(char *line, MR_Trace_Cmd_Info *cmd,
@@ -976,6 +978,33 @@
 		} else {
 			MR_trace_usage("parameter", "printlevel");
 		}
+	} else if (streq(words[0], "query")) {
+		MR_trace_query(MR_NORMAL_QUERY, MR_mmc_options,
+			word_count - 1, words + 1);
+	} else if (streq(words[0], "cc_query")) {
+		MR_trace_query(MR_CC_QUERY, MR_mmc_options,
+			word_count - 1, words + 1);
+	} else if (streq(words[0], "io_query")) {
+		MR_trace_query(MR_IO_QUERY, MR_mmc_options,
+			word_count - 1, words + 1);
+	} else if (streq(words[0], "mmc_options")) {
+		size_t len;
+
+		/* allocate the right amount of space */
+		len = 0;
+		for (i = 1; i < word_count; i++) {
+			len += strlen(words[i]) + 1;
+		}
+		MR_mmc_options = realloc(MR_mmc_options, len);
+
+		/* copy the arguments to MR_mmc_options */
+		MR_mmc_options[0] = '\0';
+		for (i = 1; i < word_count; i++) {
+			strcat(MR_mmc_options, words[i]);
+			strcat(MR_mmc_options, " ");
+		}
+		MR_mmc_options[len] = '\0';
+
 	} else if (streq(words[0], "scroll")) {
 		if (word_count == 2) {
 			if (streq(words[1], "off")) {

--- ../extras/dynamic_linking/dl.m	Thu Mar  4 02:51:40 1999
+++ ./dl.m	Thu Mar  4 10:47:40 1999
@@ -55,8 +55,13 @@
 :- implementation.
 :- import_module std_util, require, string, list.
 
-:- pragma c_header_code("#include <stdio.h>").
-:- pragma c_header_code("#include <dlfcn.h>").
+:- pragma c_header_code("
+	#include <stdio.h>
+	#include ""mercury_conf.h""
+#ifdef HAVE_DLFCN_H
+	#include <dlfcn.h>
+#endif
+").
 
 :- type handle ---> handle(c_pointer).
 
@@ -79,17 +84,23 @@
 ** variables in C++) which may end up calling Mercury, so it's not safe
 ** to declare this as `will_not_call_mercury'.
 */
+
 :- pred dlopen(string::in, (mode)::in, scope::in, c_pointer::out,
 	io__state::di, io__state::uo) is det.
 :- pragma c_code(dlopen(FileName::in, Mode::in, Scope::in, Result::out,
 		_IO0::di, _IO::uo), [], "
 {
+#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) \
+ && defined(RTLD_NOW) && defined(RTLD_LAZY)
 	int mode = (Mode ? RTLD_NOW : RTLD_LAZY);
 	/* not all systems have RTLD_GLOBAL */
 	#ifdef RTLD_GLOBAL
 	  if (Scope) mode |= RTLD_GLOBAL;
 	#endif
 	Result = (Word) dlopen(FileName, mode);
+#else
+	Result = (Word) NULL;
+#endif
 }").
 
 :- type closure ---> closure(int, c_pointer).
@@ -175,15 +186,27 @@
 :- pragma c_code(dlsym(Handle::in, Name::in, Pointer::out,
 	_IO0::di, _IO::uo), [will_not_call_mercury], "
 {
+#if defined(HAVE_DLFCN_H) && defined(HAVE_DLSYM)
 	Pointer = (Word) dlsym((void *) Handle, Name);
+#else
+	Pointer = (Word) NULL;
+#endif
 }").
 
 :- pred dlerror(string::out, io__state::di, io__state::uo) is det.
 :- pragma c_code(dlerror(ErrorMsg::out, _IO0::di, _IO::uo),
 	[will_not_call_mercury], "
 {
-	const char *msg = dlerror();
+	const char *msg;
+
+#if defined(HAVE_DLFCN_H) && defined(HAVE_DLERROR)
+	msg = dlerror();
 	if (msg == NULL) msg = """";
+#else
+	make_aligned_string(msg, ""sorry, not implemented: ""
+		""dynamic linking not supported on this platform"");
+#endif
+
 	make_aligned_string_copy(ErrorMsg, msg);
 }").
 
@@ -198,5 +221,8 @@
 ** to declare this as `will_not_call_mercury'.
 */
 :- pred dlclose(c_pointer::in, io__state::di, io__state::uo) is det.
-:- pragma c_code(dlclose(Handle::in, _IO0::di, _IO::uo),
-	[], "dlclose((void *)Handle)").
+:- pragma c_code(dlclose(Handle::in, _IO0::di, _IO::uo), [], "
+#if defined(HAVE_DLFCN_H) && defined(HAVE_DLCLOSE)
+	dlclose((void *)Handle)
+#endif
+").
-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh>  |   but source code lives forever"
PGP: finger fjh at 128.250.37.3        |     -- leaked Microsoft memo.



More information about the developers mailing list