[m-rev.] for review: breakpoints on user events

Zoltan Somogyi zs at csse.unimelb.edu.au
Fri Jan 19 15:41:15 AEDT 2007


On 15-Jan-2007, Zoltan Somogyi <zs at csse.unimelb.edu.au> wrote:
> Implement breakpoints on user events. Users may specify an event set,
> an event name, both, or neither. Four forms of the mdb "break" command
> create such breakpoints:

In the absence of a review, I am committing this updated diff, which also
contains a fix for a bug in the implementation of the "break_print" mdb
command.

Zoltan.

Implement breakpoints on user events. Users may specify an event set,
an event name, both, or neither. Four forms of the mdb "break" command
create such breakpoints:

	break [the usual options] user_event <event_name>
	break [the usual options] user_event <event_set_name> <event_name>
	break [the usual options] user_event_set
	break [the usual options] user_event_set <event_set_name>

In addition, the command

	break [the usual options] user_event

is also accepted, as a synonym for

	break [the usual options] user_event_set

Since user events are not interface events or entry events, add a new, simple
ignore specification, which decrements the ignore count on every match of the
event.

Make the "break_print" mdb command consistent with the other command that
operates on existing breakpoints ("condition") by making it apply by default
to the most recently created breakpoint.

Make "condition" and "break_print" use the same option letter (-b) to introduce
the breakpoint number.

Fix a bug in the implementation of "break_print" that led to printing out
the selected variable, but not the selected *path* within the selected
variable. The reason was that we recorded what to print (variable spec plus
path) in a string, but that the process of using that record to print out
what was wanted destroyed the string (by putting a NULL between the variable
specification and the path), so that *later* uses of that string would find
an empty path. The fix is to record a var_spec/path pair in the print list.

Fix some slightly misleading output: when printing part of a variable, we
printed the name of the variable without any indication that the value printed
wasn't the whole value of the variable. We now print the path as well.

doc/user_guide.texi:
	Document the changes above.

	Document the usage "break_print [options] none", which we have always
	supported, but which was not documented.

runtime/mercury_stack_layout.h:
	Add a utility macro.

trace/mercury_trace.c:
	Fix a bug which left a variable uninitialized.

trace/mercury_trace_cmd_breakpoint.c:
	Implement the new command forms and options described above.

trace/mercury_trace_spy.[ch]:
	Implement data structures for keeping track of the new forms of
	breakpoints, and add the necessary functions for manipulating them.
	Update the function that checks whether the current event matches.
	Factor some common code out of that function, as well as out of the
	functions for adding new breakpoints.

	Change the print list data structure as described above.

	Add some utility functions.

	Add MR_ prefixes to the names of structure fields that previously
	lacked them.

trace/mercury_trace_cmd_misc.c:
	Handle the new breakpoint types.

trace/mercury_trace_tables.c:
trace/mercury_trace_internal.c:
	We used to parse the event set descriptions in module layout structures
	when the debugger was initialized (in mercury_trace_internal.c).
	However, we delay registering all the modules until this is needed,
	so at that time we don't yet *have* the list of module layout
	structures, so we used to parse nothing. This diff moves the code
	for doing the parsing to the time when the module layout structures
	are registered (in mercury_trace_tables.c).

	Don't test whether the module layout structure contains the fields
	for user event descriptions, since that diff has been installed on
	all our systems weeks ago.

trace/mercury_trace_internal.c:
	Conform to the new print list structure.

trace/mercury_trace_vars.[ch]:
	Print any selected path together with a variable name when printing a
	value. (This is the last bug fix mentioned at the top.)

	Export a function for use in mercury_trace_internal.c.

	Add some utility functions.

	Improve some error messages.

trace/mercury_trace_tables.h:
	Add a const qualifier.

tests/debugger/user_event.{inp,exp}:
	Extend this test case to test the new functionality.

tests/debugger/breakpoints.{inp,exp,exp2}:
	Conform to the change to the break_print command.

tests/queens.{inp,exp}:
	Change the input to test the bug fix to the break_print command,
	and the expected output.

tests/browser_test.exp:
tests/field_names.exp:
	Conform to the fact that we now print paths after variables names.

cvs diff: Diffing .
cvs diff: Diffing analysis
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/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/libatomic_ops-1.2
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/doc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/tests
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing boehm_gc/windows-untested
cvs diff: Diffing boehm_gc/windows-untested/vc60
cvs diff: Diffing boehm_gc/windows-untested/vc70
cvs diff: Diffing boehm_gc/windows-untested/vc71
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing debian/patches
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.507
diff -u -b -r1.507 user_guide.texi
--- doc/user_guide.texi	15 Jan 2007 07:47:55 -0000	1.507
+++ doc/user_guide.texi	16 Jan 2007 00:46:56 -0000
@@ -3186,13 +3186,69 @@
 By default, the action of the break point is @samp{stop},
 the ignore count is zero, and the print list is empty.
 @sp 1
+ at item break [-PS] [-X at var{ignore-count}] [-n] [-p at var{print-spec}]* user_event [@var{user-event-set}] @var{user-event-name}
+Puts a break point on all user events named @var{user-event-name},
+or, if @var{user-event-set} is specified as well,
+on the user event named @var{user-event-name} in that event set.
+ at sp 1
+The options @samp{-P} or @samp{--print}, and @samp{-S} or @samp{--stop}
+specify the action to be taken at the break point.
+ at sp 1
+The options @samp{-X at var{ignore-count}}
+and @samp{--ignore @var{ignore-count}}
+tell the debugger to ignore the breakpoint
+until after @var{ignore-count} occurrences of an event
+that matches the breakpoint.
+ at sp 1
+Each occurrence of the options
+ at samp{-p at var{printspec}} and @samp{--print-list @var{printspec}}
+tells the debugger to include the specified entity
+in the breakpoint's print list.
+ at sp 1
+Normally, if a variable with the given name or number doesn't exist
+when execution reaches the breakpoint, mdb will issue a warning.
+The option @samp{-n} or @samp{--no-warn}, if present, suppresses this warning.
+This can be useful if e.g. the name is the name of an output variable,
+which of course won't be present at call events.
+ at sp 1
+By default, the action of the break point is @samp{stop},
+the ignore count is zero, and the print list is empty.
+ at sp 1
+ at item break [-PS] [-X at var{ignore-count}] [-n] [-p at var{print-spec}]* user_event_set [@var{user-event-set}]
+Puts a break point either on all user events in all event sets,
+or, if @var{user-event-set} is specified,
+on all user events in the event set of the given name.
+ at sp 1
+The options @samp{-P} or @samp{--print}, and @samp{-S} or @samp{--stop}
+specify the action to be taken at the break point.
+ at sp 1
+The options @samp{-X at var{ignore-count}}
+and @samp{--ignore @var{ignore-count}}
+tell the debugger to ignore the breakpoint
+until after @var{ignore-count} occurrences of an event
+that matches the breakpoint.
+ at sp 1
+Each occurrence of the options
+ at samp{-p at var{printspec}} and @samp{--print-list @var{printspec}}
+tells the debugger to include the specified entity
+in the breakpoint's print list.
+ at sp 1
+Normally, if a variable with the given name or number doesn't exist
+when execution reaches the breakpoint, mdb will issue a warning.
+The option @samp{-n} or @samp{--no-warn}, if present, suppresses this warning.
+This can be useful if e.g. the name is the name of an output variable,
+which of course won't be present at call events.
+ at sp 1
+By default, the action of the break point is @samp{stop},
+the ignore count is zero, and the print list is empty.
+ at sp 1
 @item break info
 Lists the details, status and print lists of all break points.
 @sp 1
- at item condition [-n at var{break-num}] [-p] [-v] @var{varname}[@var{pathspec}] @var{op} @var{term}
+ at item condition [-b at var{break-num}] [-p] [-v] @var{varname}[@var{pathspec}] @var{op} @var{term}
 @kindex condition (mdb command)
 Attaches a condition to the most recent breakpoint,
-or, if the @samp{-n} or @samp{--break-num} is given,
+or, if the @samp{-b} or @samp{--break-num} is given,
 to the breakpoint whose number is given as the argument.
 Execution won't stop at the breakpoint if the condition is false.
 @sp 1
@@ -3227,6 +3283,8 @@
 If the @samp{-v} or @samp{--dont-require-var} option is given,
 execution won't stop at breakpoints at which
 the specified variable itself doesn't exist.
+The @samp{-v} or @samp{--dont-require-var} option is implicitly assumed
+if the specified breakpoint is on all user events.
 @sp 1
 @item ignore [-E at var{ignore-count}] [-I at var{ignore-count}] @var{num}
 @kindex ignore (mdb command)
@@ -3261,10 +3319,12 @@
 that matches the most recently added breakpoint.
 Reports an error if the most recently added breakpoint has since been deleted.
 @sp 1
- at item break_print [-fpv] [-e] [-n] @var{num} @var{print-spec}*
+ at item break_print [-fpv] [-e] [-n] [-b @var{num}] @var{print-spec}*
 @kindex break_print (mdb command)
 Adds the specified print list elements (there may be more than one)
-to the print list of the breakpoint numbered @var{num}.
+to the print list of the breakpoint numbered @var{num}
+(if the @samp{-b} or @samp{--break-num} option is given),
+or to the print list of the most recent breakpoint (if it is not given).
 @sp 1
 Normally, if a variable with the given name or number doesn't exist
 when execution reaches the breakpoint, mdb will issue a warning.
@@ -3282,6 +3342,12 @@
 and @samp{-v} or @samp{--verbose}, if given,
 explicitly specify the format to use.
 @sp 1
+ at item break_print [-b @var{num}] none
+ at kindex break_print (mdb command)
+Clears the print list of the breakpoint numbered @var{num}
+(if the @samp{-b} or @samp{--break-num} option is given),
+or the print list of the most recent breakpoint (if it is not given).
+ at sp 1
 @item disable @var{num}
 @kindex disable (mdb command)
 Disables the break point with the given number.
cvs diff: Diffing extras
cvs diff: Diffing extras/base64
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/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/fixed
cvs diff: Diffing extras/gator
cvs diff: Diffing extras/gator/generations
cvs diff: Diffing extras/gator/generations/1
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
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/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/log4m
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/mopenssl
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/net
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/solver_types
cvs diff: Diffing extras/solver_types/library
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/stream/tests
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/windows_installer_generator
cvs diff: Diffing extras/windows_installer_generator/sample
cvs diff: Diffing extras/windows_installer_generator/sample/images
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
Index: runtime/mercury_stack_layout.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_stack_layout.h,v
retrieving revision 1.109
diff -u -b -r1.109 mercury_stack_layout.h
--- runtime/mercury_stack_layout.h	10 Jan 2007 16:08:20 -0000	1.109
+++ runtime/mercury_stack_layout.h	11 Jan 2007 15:21:29 -0000
@@ -344,6 +344,10 @@
 	MR_ml_user_event_specs[label_layout->MR_sll_user_event->	\
 		MR_ue_event_number]
 
+#define	MR_user_event_set_name(label_layout)	\
+	label_layout->MR_sll_entry->MR_sle_module_layout->		\
+	MR_ml_user_event_set_name
+
 /*-------------------------------------------------------------------------*/
 /*
 ** Definitions for MR_LabelLayout
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 slice
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
Index: tests/debugger/breakpoints.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/breakpoints.exp,v
retrieving revision 1.16
diff -u -b -r1.16 breakpoints.exp
--- tests/debugger/breakpoints.exp	6 Jan 2007 10:56:25 -0000	1.16
+++ tests/debugger/breakpoints.exp	12 Jan 2007 14:11:03 -0000
@@ -90,7 +90,7 @@
  3: - stop      entry pred breakpoints.qperm/2-0 (nondet)
 mdb> break nodiag
  0: + stop  interface pred breakpoints.nodiag/3-0 (semidet)
-mdb> break_print -v -n 1 HeadVar__1 HeadVar__2
+mdb> break_print -v -n -b1 HeadVar__1 HeadVar__2
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (verbose, nowarn), HeadVar__2 (verbose, nowarn)
 mdb> continue
@@ -104,11 +104,11 @@
     1-3
     2-[|]/2
 
-mdb> break_print 1 none
+mdb> break_print -b1 none
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
 mdb> format_param -p depth 10
 mdb> format_param -p size 20
-mdb> break_print -p -n 1 HeadVar__1 HeadVar__2
+mdb> break_print -p -n -b1 HeadVar__1 HeadVar__2
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (pretty, nowarn), HeadVar__2 (pretty, nowarn)
 mdb> continue
@@ -123,12 +123,12 @@
 [2, 3, 4, 5]
        HeadVar__2             	
 [2, 3, 4, 5]
-mdb> break_print 1 none
+mdb> break_print -b1 none
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
-mdb> break_print -f -n 1 HeadVar__1
+mdb> break_print -f -n -b1 HeadVar__1
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (flat, nowarn)
-mdb> break_print -f -e -n 1 HeadVar__2
+mdb> break_print -f -e -n -b1 HeadVar__2
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (flat, nowarn), HeadVar__2 (flat, nowarn)
 mdb> continue
@@ -240,9 +240,9 @@
 [1, 3, 5, 2, 4]
      E14:     C9 CALL func breakpoints.a.testmod.test_in_a/0-0 (det) breakpoints.a.testmod.m:10 (breakpoints.m:27)
 test_in_a = '_'
-mdb> break_print 0 none
+mdb> break_print -b0 none
  0: + stop  interface func breakpoints.a.testmod.test_in_a/0-0 (det)
-mdb> break_print 0 *
+mdb> break_print -b0 *
  0: + stop  interface func breakpoints.a.testmod.test_in_a/0-0 (det)
             all (flat)
 mdb> continue
Index: tests/debugger/breakpoints.exp2
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/breakpoints.exp2,v
retrieving revision 1.12
diff -u -b -r1.12 breakpoints.exp2
--- tests/debugger/breakpoints.exp2	8 Jan 2007 09:13:11 -0000	1.12
+++ tests/debugger/breakpoints.exp2	12 Jan 2007 15:40:21 -0000
@@ -98,7 +98,7 @@
  3: - stop      entry pred breakpoints.qperm/2-0 (nondet)
 mdb> break nodiag
  0: + stop  interface pred breakpoints.nodiag/3-0 (semidet)
-mdb> break_print -v -n 1 HeadVar__1 HeadVar__2
+mdb> break_print -v -n -b1 HeadVar__1 HeadVar__2
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (verbose, nowarn), HeadVar__2 (verbose, nowarn)
 mdb> continue
@@ -112,11 +112,11 @@
     1-3
     2-[|]/2
 
-mdb> break_print 1 none
+mdb> break_print -b1 none
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
 mdb> format_param -p depth 10
 mdb> format_param -p size 20
-mdb> break_print -p -n 1 HeadVar__1 HeadVar__2
+mdb> break_print -p -n -b1 HeadVar__1 HeadVar__2
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (pretty, nowarn), HeadVar__2 (pretty, nowarn)
 mdb> continue
@@ -131,12 +131,12 @@
 [2, 3, 4, 5]
        HeadVar__2             	
 [2, 3, 4, 5]
-mdb> break_print 1 none
+mdb> break_print -b1 none
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
-mdb> break_print -f -n 1 HeadVar__1
+mdb> break_print -f -n -b1 HeadVar__1
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (flat, nowarn)
-mdb> break_print -f -e -n 1 HeadVar__2
+mdb> break_print -f -e -n -b1 HeadVar__2
  1: + stop  interface pred breakpoints.qperm/2-0 (nondet)
             HeadVar__1 (flat, nowarn), HeadVar__2 (flat, nowarn)
 mdb> continue
@@ -248,9 +248,9 @@
 [1, 3, 5, 2, 4]
      E14:     C9 CALL func breakpoints.a.testmod.test_in_a/0-0 (det) breakpoints.a.testmod.m:10 (breakpoints.m:27)
 test_in_a = '_'
-mdb> break_print 0 none
+mdb> break_print -b0 none
  0: + stop  interface func breakpoints.a.testmod.test_in_a/0-0 (det)
-mdb> break_print 0 *
+mdb> break_print -b0 *
  0: + stop  interface func breakpoints.a.testmod.test_in_a/0-0 (det)
             all (flat)
 mdb> continue
Index: tests/debugger/breakpoints.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/breakpoints.inp,v
retrieving revision 1.9
diff -u -b -r1.9 breakpoints.inp
--- tests/debugger/breakpoints.inp	4 Apr 2006 07:37:16 -0000	1.9
+++ tests/debugger/breakpoints.inp	18 Jan 2007 04:30:49 -0000
@@ -27,18 +27,18 @@
 break info
 disable 3
 break nodiag
-break_print -v -n 1 HeadVar__1 HeadVar__2
+break_print -v -n -b1 HeadVar__1 HeadVar__2
 continue
-break_print 1 none
+break_print -b1 none
 format_param -p depth 10
 format_param -p size 20
-break_print -p -n 1 HeadVar__1 HeadVar__2
+break_print -p -n -b1 HeadVar__1 HeadVar__2
 continue
 finish -N
 finish -n
-break_print 1 none
-break_print -f -n 1 HeadVar__1
-break_print -f -e -n 1 HeadVar__2
+break_print -b1 none
+break_print -f -n -b1 HeadVar__1
+break_print -f -e -n -b1 HeadVar__2
 continue
 continue
 finish
@@ -73,7 +73,7 @@
 break -O -P -p HeadVar__1 test_in_b
 break info
 continue
-break_print 0 none
-break_print 0 *
+break_print -b0 none
+break_print -b0 *
 continue
 continue
Index: tests/debugger/browser_test.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/browser_test.exp,v
retrieving revision 1.27
diff -u -b -r1.27 browser_test.exp
--- tests/debugger/browser_test.exp	18 Aug 2006 07:19:48 -0000	1.27
+++ tests/debugger/browser_test.exp	18 Jan 2007 11:56:19 -0000
@@ -171,14 +171,14 @@
 mdb> print *
        Data (arg 1)           	big(big/3, 3, big/3)
 mdb> print Data/1
-       Data (arg 1)           	big(big(small, 1, small), 2, small)
+       Data (arg 1)^1         	big(big(small, 1, small), 2, small)
 mdb> format_param -f depth 3
 mdb> print 1
        Data (arg 1)           	big(big(big(small, 1, small), 2, small), 3, big(big(small, 4, big/3), 6, small))
 mdb> print Data/1/2
-       Data (arg 1)           	2
+       Data (arg 1)/1/2       	2
 mdb> print 1^1^2^3
-mdb: the path 3 does not exist.
+mdb: the path 3 does not exist in variable 1.
 mdb> retry
       E2:     C2 CALL pred browser_test.big_data/1-0 (det) browser_test.m:37 (browser_test.m:20)
 mdb> break list_data
Index: tests/debugger/field_names.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/field_names.exp,v
retrieving revision 1.7
diff -u -b -r1.7 field_names.exp
--- tests/debugger/field_names.exp	5 Oct 2005 06:34:24 -0000	1.7
+++ tests/debugger/field_names.exp	18 Jan 2007 10:55:45 -0000
@@ -13,27 +13,27 @@
 mdb> p 5^1x
 mdb: bad component selector.
 mdb> p 5^1^x
-mdb: the path x does not exist.
+mdb: the path x does not exist in variable 5.
 mdb> p 5^x
-mdb: the path x does not exist.
+mdb: the path x does not exist in variable 5.
 mdb> p 5^1
-       HeadVar__5             	41
+       HeadVar__5^1           	41
 mdb> p 5^2
-       HeadVar__5             	42
+       HeadVar__5^2           	42
 mdb> p 5^3
-       HeadVar__5             	43
+       HeadVar__5^3           	43
 mdb> p 5^4
-       HeadVar__5             	44
+       HeadVar__5^4           	44
 mdb> p 5^t1a
-       HeadVar__5             	41
+       HeadVar__5^t1a         	41
 mdb> p 5^t1b
-       HeadVar__5             	42
+       HeadVar__5^t1b         	42
 mdb> p 5^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 5.
 mdb> p 5^t1d
-       HeadVar__5             	44
+       HeadVar__5^t1d         	44
 mdb> p 5^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 5.
 mdb> browse 5
 browser> ^1x
 error: in subdir 1: there is no subterm x
@@ -71,19 +71,19 @@
 mdb> p 4
        HeadVar__4             	t1f2(51, 52, 53)
 mdb> p 4^1
-       HeadVar__4             	51
+       HeadVar__4^1           	51
 mdb> p 4^2
-       HeadVar__4             	52
+       HeadVar__4^2           	52
 mdb> p 4^3
-       HeadVar__4             	53
+       HeadVar__4^3           	53
 mdb> p 4^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 4.
 mdb> p 4^t1e
-       HeadVar__4             	51
+       HeadVar__4^t1e         	51
 mdb> p 4^t1f
-mdb: the path t1f does not exist.
+mdb: the path t1f does not exist in variable 4.
 mdb> p 4^t1g
-       HeadVar__4             	53
+       HeadVar__4^t1g         	53
 mdb> browse 4
 browser> ^t1a
 error: there is no subterm t1a
@@ -103,55 +103,55 @@
 mdb> p 5
        HeadVar__5             	t2f(0.600000000000000, 61, t1f1(41, 42, 43, 44), t1f2(51, 52, 53))
 mdb> p 5^1
-       HeadVar__5             	0.600000000000000
+       HeadVar__5^1           	0.600000000000000
 mdb> p 5^2
-       HeadVar__5             	61
+       HeadVar__5^2           	61
 mdb> p 5^3
-       HeadVar__5             	t1f1(41, 42, 43, 44)
+       HeadVar__5^3           	t1f1(41, 42, 43, 44)
 mdb> p 5^3^t1a
-       HeadVar__5             	41
+       HeadVar__5^3^t1a       	41
 mdb> p 5^3^t1b
-       HeadVar__5             	42
+       HeadVar__5^3^t1b       	42
 mdb> p 5^3^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 5.
 mdb> p 5^3^t1d
-       HeadVar__5             	44
+       HeadVar__5^3^t1d       	44
 mdb> p 5^3^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 5.
 mdb> p 5^4
-       HeadVar__5             	t1f2(51, 52, 53)
+       HeadVar__5^4           	t1f2(51, 52, 53)
 mdb> p 5^4^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 5.
 mdb> p 5^4^t1e
-       HeadVar__5             	51
+       HeadVar__5^4^t1e       	51
 mdb> p 5^4^t1f
-mdb: the path t1f does not exist.
+mdb: the path t1f does not exist in variable 5.
 mdb> p 5^4^t1g
-       HeadVar__5             	53
+       HeadVar__5^4^t1g       	53
 mdb> p 5^t2a
-       HeadVar__5             	0.600000000000000
+       HeadVar__5^t2a         	0.600000000000000
 mdb> p 5^t2b
-       HeadVar__5             	t1f1(41, 42, 43, 44)
+       HeadVar__5^t2b         	t1f1(41, 42, 43, 44)
 mdb> p 5^t2b^t1a
-       HeadVar__5             	41
+       HeadVar__5^t2b^t1a     	41
 mdb> p 5^t2b^t1b
-       HeadVar__5             	42
+       HeadVar__5^t2b^t1b     	42
 mdb> p 5^t2b^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 5.
 mdb> p 5^t2b^t1d
-       HeadVar__5             	44
+       HeadVar__5^t2b^t1d     	44
 mdb> p 5^t2b^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 5.
 mdb> p 5^t2c
-       HeadVar__5             	t1f2(51, 52, 53)
+       HeadVar__5^t2c         	t1f2(51, 52, 53)
 mdb> p 5^t2c^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 5.
 mdb> p 5^t2c^t1e
-       HeadVar__5             	51
+       HeadVar__5^t2c^t1e     	51
 mdb> p 5^t2c^t1f
-mdb: the path t1f does not exist.
+mdb: the path t1f does not exist in variable 5.
 mdb> p 5^t2c^t1g
-       HeadVar__5             	53
+       HeadVar__5^t2c^t1g     	53
 mdb> browse 5
 browser> ^3^t1a
 browser> p
@@ -178,63 +178,63 @@
 mdb> p 4
        HeadVar__4             	t3f(t1f2(51, 52, 53), 72, "xyzzy", t1f1(41, 42, 43, 44))
 mdb> p 4^1
-       HeadVar__4             	t1f2(51, 52, 53)
+       HeadVar__4^1           	t1f2(51, 52, 53)
 mdb> p 4^1^1
-       HeadVar__4             	51
+       HeadVar__4^1^1         	51
 mdb> p 4^1^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 4.
 mdb> p 4^1^t1e
-       HeadVar__4             	51
+       HeadVar__4^1^t1e       	51
 mdb> p 4^1^t1g
-       HeadVar__4             	53
+       HeadVar__4^1^t1g       	53
 mdb> p 4^2
-       HeadVar__4             	72
+       HeadVar__4^2           	72
 mdb> p 4^3
-       HeadVar__4             	"xyzzy"
+       HeadVar__4^3           	"xyzzy"
 mdb> p 4^3^1
-mdb: the path 1 does not exist.
+mdb: the path 1 does not exist in variable 4.
 mdb> p 4^3^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 4.
 mdb> p 4^4
-       HeadVar__4             	t1f1(41, 42, 43, 44)
+       HeadVar__4^4           	t1f1(41, 42, 43, 44)
 mdb> p 4^4^t1a
-       HeadVar__4             	41
+       HeadVar__4^4^t1a       	41
 mdb> p 4^4^t1b
-       HeadVar__4             	42
+       HeadVar__4^4^t1b       	42
 mdb> p 4^4^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 4.
 mdb> p 4^4^t1d
-       HeadVar__4             	44
+       HeadVar__4^4^t1d       	44
 mdb> p 4^4^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 4.
 mdb> p 4^t3a
-       HeadVar__4             	t1f2(51, 52, 53)
+       HeadVar__4^t3a         	t1f2(51, 52, 53)
 mdb> p 4^t3a^1
-       HeadVar__4             	51
+       HeadVar__4^t3a^1       	51
 mdb> p 4^t3a^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 4.
 mdb> p 4^t3a^t1e
-       HeadVar__4             	51
+       HeadVar__4^t3a^t1e     	51
 mdb> p 4^t3a^t1g
-       HeadVar__4             	53
+       HeadVar__4^t3a^t1g     	53
 mdb> p 4^t3b
-       HeadVar__4             	72
+       HeadVar__4^t3b         	72
 mdb> p 4^t3c
-       HeadVar__4             	"xyzzy"
+       HeadVar__4^t3c         	"xyzzy"
 mdb> p 4^t3d
-       HeadVar__4             	t1f1(41, 42, 43, 44)
+       HeadVar__4^t3d         	t1f1(41, 42, 43, 44)
 mdb> p 4^t3d^t1a
-       HeadVar__4             	41
+       HeadVar__4^t3d^t1a     	41
 mdb> p 4^t3d^t1b
-       HeadVar__4             	42
+       HeadVar__4^t3d^t1b     	42
 mdb> p 4^t3d^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 4.
 mdb> p 4^t3d^t1d
-       HeadVar__4             	44
+       HeadVar__4^t3d^t1d     	44
 mdb> p 4^t3d^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 4.
 mdb> p 4^t3e^t1a
-mdb: the path t3e^t1a does not exist.
+mdb: the path t3e^t1a does not exist in variable 4.
 mdb> step
       10:      6  2 CALL pred field_names.make_t4/2-0 (det)
 mdb> finish
@@ -242,53 +242,53 @@
 mdb> p 2
        A(1) (arg 2)           	t2f(0.600000000000000, 61, t1f1(41, 42, 43, 44), t1f2(51, 52, 53))
 mdb> p 2^1
-       A(1) (arg 2)           	0.600000000000000
+       A(1) (arg 2)^1         	0.600000000000000
 mdb> p 2^2
-       A(1) (arg 2)           	61
+       A(1) (arg 2)^2         	61
 mdb> p 2^3^t1a
-       A(1) (arg 2)           	41
+       A(1) (arg 2)^3^t1a     	41
 mdb> p 2^3^t1b
-       A(1) (arg 2)           	42
+       A(1) (arg 2)^3^t1b     	42
 mdb> p 2^3^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 2.
 mdb> p 2^3^t1d
-       A(1) (arg 2)           	44
+       A(1) (arg 2)^3^t1d     	44
 mdb> p 2^3^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 2.
 mdb> p 2^4
-       A(1) (arg 2)           	t1f2(51, 52, 53)
+       A(1) (arg 2)^4         	t1f2(51, 52, 53)
 mdb> p 2^4^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 2.
 mdb> p 2^4^t1e
-       A(1) (arg 2)           	51
+       A(1) (arg 2)^4^t1e     	51
 mdb> p 2^4^t1f
-mdb: the path t1f does not exist.
+mdb: the path t1f does not exist in variable 2.
 mdb> p 2^4^t1g
-       A(1) (arg 2)           	53
+       A(1) (arg 2)^4^t1g     	53
 mdb> p 2^t2a
-       A(1) (arg 2)           	0.600000000000000
+       A(1) (arg 2)^t2a       	0.600000000000000
 mdb> p 2^t2b
-       A(1) (arg 2)           	t1f1(41, 42, 43, 44)
+       A(1) (arg 2)^t2b       	t1f1(41, 42, 43, 44)
 mdb> p 2^t2b^t1a
-       A(1) (arg 2)           	41
+       A(1) (arg 2)^t2b^t1a   	41
 mdb> p 2^t2b^t1b
-       A(1) (arg 2)           	42
+       A(1) (arg 2)^t2b^t1b   	42
 mdb> p 2^t2b^t1c
-mdb: the path t1c does not exist.
+mdb: the path t1c does not exist in variable 2.
 mdb> p 2^t2b^t1d
-       A(1) (arg 2)           	44
+       A(1) (arg 2)^t2b^t1d   	44
 mdb> p 2^t2b^t1e
-mdb: the path t1e does not exist.
+mdb: the path t1e does not exist in variable 2.
 mdb> p 2^t2c
-       A(1) (arg 2)           	t1f2(51, 52, 53)
+       A(1) (arg 2)^t2c       	t1f2(51, 52, 53)
 mdb> p 2^t2c^t1a
-mdb: the path t1a does not exist.
+mdb: the path t1a does not exist in variable 2.
 mdb> p 2^t2c^t1e
-       A(1) (arg 2)           	51
+       A(1) (arg 2)^t2c^t1e   	51
 mdb> p 2^t2c^t1f
-mdb: the path t1f does not exist.
+mdb: the path t1f does not exist in variable 2.
 mdb> p 2^t2c^t1g
-       A(1) (arg 2)           	53
+       A(1) (arg 2)^t2c^t1g   	53
 mdb> step
       12:      7  2 CALL pred field_names.make_t5/2-0 (det)
 mdb> finish
@@ -296,19 +296,19 @@
 mdb> p 2
        HeadVar__2             	t5f(t1f1(41, 42, 43, 44))
 mdb> p 2/1
-       HeadVar__2             	t1f1(41, 42, 43, 44)
+       HeadVar__2^1           	t1f1(41, 42, 43, 44)
 mdb> p 2/1/1
-       HeadVar__2             	41
+       HeadVar__2/1/1         	41
 mdb> p 2/1/t1a
-       HeadVar__2             	41
+       HeadVar__2/1/t1a       	41
 mdb> p 2/t5a
-       HeadVar__2             	t1f1(41, 42, 43, 44)
+       HeadVar__2^t5a         	t1f1(41, 42, 43, 44)
 mdb> p 2/t5a/1
-       HeadVar__2             	41
+       HeadVar__2/t5a/1       	41
 mdb> p 2/t5a/t1a
-       HeadVar__2             	41
+       HeadVar__2/t5a/t1a     	41
 mdb> p 2/t6a
-mdb: the path t6a does not exist.
+mdb: the path t6a does not exist in variable 2.
 mdb> step
       14:      8  2 CALL pred field_names.make_t6/2-0 (det)
 mdb> finish
@@ -316,11 +316,11 @@
 mdb> p 2
        HeadVar__2             	t6f(0.900000000000000)
 mdb> p 2/1
-       HeadVar__2             	0.900000000000000
+       HeadVar__2^1           	0.900000000000000
 mdb> p 2/t5a
-mdb: the path t5a does not exist.
+mdb: the path t5a does not exist in variable 2.
 mdb> p 2/t6a
-mdb: the path t6a does not exist.
+mdb: the path t6a does not exist in variable 2.
 mdb> browse 2
 browser> p
 t6f(0.900000000000000)
Index: tests/debugger/queens.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/queens.exp,v
retrieving revision 1.33
diff -u -b -r1.33 queens.exp
--- tests/debugger/queens.exp	6 Jan 2007 10:56:26 -0000	1.33
+++ tests/debugger/queens.exp	18 Jan 2007 08:44:01 -0000
@@ -233,6 +233,9 @@
  0: + stop  interface pred queens.print_list/3-0 (det)
 mdb> break qdelete
  1: + stop  interface pred queens.qdelete/3-0 (nondet)
+mdb> break_print HeadVar__2^2
+ 1: + stop  interface pred queens.qdelete/3-0 (nondet)
+            HeadVar__2^2 (flat)
 mdb> continue -a
      E35:     C8 EXIT queens.m:36 (from queens.m:40)
                          pred queens.qperm/2-0 (nondet)
@@ -272,9 +275,11 @@
                          pred queens.qperm/2-0 (nondet)
      E53:    C13 REDO queens.m:45 (from queens.m:38)
                          pred queens.qdelete/3-0 (nondet)
+       HeadVar__2^2           	[]
 mdb> break info
  0: + stop  interface pred queens.print_list/3-0 (det)
  1: + stop  interface pred queens.qdelete/3-0 (nondet)
+            HeadVar__2^2 (flat)
 mdb> enable *
  0: + stop  interface pred queens.print_list/3-0 (det)
  1: + stop  interface pred queens.qdelete/3-0 (nondet)
@@ -283,10 +288,13 @@
                          pred queens.qdelete/3-0 (nondet) c2;d2;
      E55:    C17 CALL queens.m:45 (from queens.m:47)
                          pred queens.qdelete/3-0 (nondet)
+mdb: the path 2 does not exist in variable HeadVar__2.
      E56:    C17 FAIL queens.m:45 (from queens.m:47)
                          pred queens.qdelete/3-0 (nondet)
+mdb: the path 2 does not exist in variable HeadVar__2.
      E57:    C13 FAIL queens.m:45 (from queens.m:38)
                          pred queens.qdelete/3-0 (nondet)
+       HeadVar__2^2           	[]
      E58:    C12 FAIL queens.m:36 (from queens.m:40)
                          pred queens.qperm/2-0 (nondet)
 mdb> disable 1
Index: tests/debugger/queens.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/queens.inp,v
retrieving revision 1.15
diff -u -b -r1.15 queens.inp
--- tests/debugger/queens.inp	11 Jul 2005 07:30:28 -0000	1.15
+++ tests/debugger/queens.inp	18 Jan 2007 08:11:45 -0000
@@ -76,6 +76,7 @@
 register --quiet
 break print_list
 break qdelete
+break_print HeadVar__2^2
 continue -a
 break info
 enable *
Index: tests/debugger/user_event.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/user_event.exp,v
retrieving revision 1.3
diff -u -b -r1.3 user_event.exp
--- tests/debugger/user_event.exp	6 Jan 2007 10:56:26 -0000	1.3
+++ tests/debugger/user_event.exp	12 Jan 2007 12:54:35 -0000
@@ -2,6 +2,15 @@
 mdb> echo on
 Command echo enabled.
 mdb> register --quiet
+mdb> break user_event nonexistent_event_name
+There is no user event named `nonexistent_event_name'.
+mdb> break user_event nonexistent_set_name nodiag_fail
+There is no user event set named `nonexistent_set_name'.
+mdb> break user_event nodiag_fail
+ 0: + stop  user_event nodiag_fail
+mdb> break_print -b0 !arg_b
+ 0: + stop  user_event nodiag_fail
+            !arg_b (flat)
 mdb> user
       E2:     C2 USER <safe_test> pred user_event.queen/2-0 (nondet) c3; user_event.m:32
 mdb> print *
@@ -16,6 +25,7 @@
 browser> quit
 mdb> user
       E3:     C3 USER <nodiag_fail> pred user_event.nodiag/3-0 (semidet) s2-2;c6;t;c2; user_event.m:64
+       arg_b (attr 1, B)      	1
 mdb> vars
         1 test_failed (attr 0)
         2 arg_b (attr 1, B)
@@ -48,5 +58,12 @@
 mdb> print *
        test_list (attr 0, Out)	[1, 2, 3, 5, 4]
        Data (arg 1)           	[1, 2, 3, 4, 5]
+mdb> condition -b0 !arg_b = 1
+ 0: + stop  user_event nodiag_fail
+            !arg_b = 1
+            !arg_b (flat)
 mdb> continue
+      E5:     C4 USER <nodiag_fail> pred user_event.nodiag/3-0 (semidet) s2-2;c6;t;c2; user_event.m:64
+       arg_b (attr 1, B)      	1
+mdb> continue -S
 [1, 3, 5, 2, 4]
Index: tests/debugger/user_event.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/user_event.inp,v
retrieving revision 1.1
diff -u -b -r1.1 user_event.inp
--- tests/debugger/user_event.inp	24 Nov 2006 03:48:23 -0000	1.1
+++ tests/debugger/user_event.inp	12 Jan 2007 04:49:16 -0000
@@ -1,5 +1,9 @@
 echo on
 register --quiet
+break user_event nonexistent_event_name
+break user_event nonexistent_set_name nodiag_fail
+break user_event nodiag_fail
+break_print -b0 !arg_b
 user
 print *
 browse !test_list
@@ -13,4 +17,6 @@
 print !arg_b
 user
 print *
+condition -b0 !arg_b = 1
 continue
+continue -S
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/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
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/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/par_conj
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/trailing
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/mercury_trace.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace.c,v
retrieving revision 1.104
diff -u -b -r1.104 mercury_trace.c
--- trace/mercury_trace.c	8 Jan 2007 09:15:22 -0000	1.104
+++ trace/mercury_trace.c	11 Jan 2007 18:46:33 -0000
@@ -559,6 +559,7 @@
                 MR_SpyAction        action;         /* ignored */
                 MR_SpyPrintList     print_list;
 
+                print_list = NULL;
                 (void) MR_event_matches_spy_point(layout, port, &action,
                     &print_list);
                 jumpaddr = MR_trace_event_internal(cmd, interactive,
Index: trace/mercury_trace_cmd_breakpoint.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_cmd_breakpoint.c,v
retrieving revision 1.2
diff -u -b -r1.2 mercury_trace_cmd_breakpoint.c
--- trace/mercury_trace_cmd_breakpoint.c	29 Nov 2006 05:18:34 -0000	1.2
+++ trace/mercury_trace_cmd_breakpoint.c	18 Jan 2007 07:11:09 -0000
@@ -37,9 +37,11 @@
         MR_MULTIMATCH_ASK, MR_MULTIMATCH_ALL, MR_MULTIMATCH_ONE
 } MR_MultiMatch;
 
+static  const char  *MR_parse_spy_print(MR_BrowseFormat format, MR_bool warn,
+                        char *word, MR_SpyPrint *sp_ptr);
 static  MR_SpyPrintList
-                    MR_add_to_print_list_end(MR_BrowseFormat format,
-                        char *word, MR_bool warn, MR_SpyPrintList print_list);
+                    MR_add_to_print_list_end(MR_SpyPrint sp,
+                        MR_SpyPrintList print_list);
 static  void        MR_maybe_print_spy_point(int slot, const char *problem);
 static  MR_bool     MR_parse_source_locn(char *word, const char **file,
                         int *line);
@@ -55,9 +57,9 @@
 static  MR_bool     MR_trace_options_ignore_count(
                         MR_SpyIgnore_When *ignore_when,
                         int *ignore_count, char ***words, int *word_count);
-static  MR_bool     MR_trace_options_break_print(MR_BrowseFormat *format,
-                        MR_bool *at_start, MR_bool *warn, char ***words,
-                        int *word_count);
+static  MR_bool     MR_trace_options_break_print(int *break_num,
+                        MR_BrowseFormat *format, MR_bool *at_start,
+                        MR_bool *warn, char ***words, int *word_count);
 static  MR_bool     MR_trace_options_register(MR_bool *verbose, char ***words,
                         int *word_count);
 
@@ -68,7 +70,7 @@
     MR_EventInfo *event_info, MR_Code **jumpaddr)
 {
     const MR_LabelLayout    *layout;
-    MR_ProcSpec             spec;
+    MR_ProcSpec             proc_spec;
     MR_SpyWhen              when;
     MR_SpyAction            action;
     MR_MultiMatch           multi_match;
@@ -88,7 +90,7 @@
 
         count = 0;
         for (i = 0; i < MR_spy_point_next; i++) {
-            if (MR_spy_points[i]->spy_exists) {
+            if (MR_spy_points[i]->MR_spy_exists) {
                 MR_print_spy_point(MR_mdb_out, i, MR_TRUE);
                 count++;
             }
@@ -116,6 +118,160 @@
         &words, &word_count))
     {
         ; /* the usage message has already been printed */
+    } else if (word_count >= 2 && MR_streq(words[1], "user_event")) {
+        const MR_UserEventSpec  *user_event_spec;
+        const char              *user_event_set;
+        const char              *user_event_name;
+        int                     slot;
+        int                     set;
+        int                     spec;
+        MR_bool                 found_event_set;
+        MR_bool                 found_event_name;
+
+        if (word_count == 2) {
+            user_event_set = NULL;
+            user_event_name = NULL;
+        } else if (word_count == 3) {
+            user_event_set = NULL;
+            user_event_name = words[2];
+        } else if (word_count == 4) {
+            user_event_set = words[2];
+            user_event_name = words[3];
+        } else {
+            MR_trace_usage_cur_cmd();
+            return KEEP_INTERACTING;
+        }
+
+        MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE);
+
+        if (user_event_name != NULL) {
+            found_event_set = MR_FALSE;
+            found_event_name = MR_FALSE;
+            for (set = 0; set < MR_trace_event_set_next; set++) {
+                if (user_event_set == NULL ||
+                    MR_streq(user_event_set,
+                        MR_trace_event_sets[set].MR_tes_name))
+                {
+                    if (user_event_set != NULL) {
+                        found_event_set = MR_TRUE;
+                    }
+
+                    for (spec = 0;
+                        spec < MR_trace_event_sets[set].MR_tes_num_specs;
+                        spec++)
+                    {
+                        if (MR_trace_event_sets[set].MR_tes_specs == NULL) {
+                            /*
+                            ** We couldn't parse the event set specification
+                            ** in the module. The error message has already
+                            ** been printed, so just ignore the event set.
+                            */
+                            continue;
+                        }
+
+                        user_event_spec =
+                            &MR_trace_event_sets[set].MR_tes_specs[spec];
+                        if (MR_streq(user_event_name,
+                            user_event_spec->MR_ues_event_name))
+                        {
+                            found_event_name = MR_TRUE;
+                        }
+                    }
+                }
+            }
+
+            if (user_event_set != NULL && ! found_event_set) {
+                fprintf(MR_mdb_out,
+                    "There is no user event set named `%s'.\n",
+                    user_event_set);
+                return KEEP_INTERACTING;
+            }
+
+            if (! found_event_name) {
+                if (user_event_set == NULL) {
+                    fprintf(MR_mdb_out,
+                        "There is no user event named `%s'.\n",
+                        user_event_name);
+                } else {
+                    fprintf(MR_mdb_out,
+                        "There is no user event named `%s' "
+                        "in event set `%s'.\n",
+                        user_event_set, user_event_name);
+                }
+
+                return KEEP_INTERACTING;
+            }
+        }
+
+        if (ignore_count > 0 && ignore_when == MR_SPY_IGNORE_ENTRY) {
+            fprintf(MR_mdb_out, "That breakpoint "
+                "would never become enabled.\n");
+            return KEEP_INTERACTING;
+        } else if (ignore_count > 0 &&
+            ignore_when == MR_SPY_IGNORE_INTERFACE)
+        {
+            fprintf(MR_mdb_out, "That breakpoint "
+                "would never become enabled.\n");
+            return KEEP_INTERACTING;
+        }
+
+        MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE);
+        slot = MR_add_user_event_spy_point(action, ignore_when, ignore_count,
+            user_event_set, user_event_name, print_list, &problem);
+        MR_maybe_print_spy_point(slot, problem);
+    } else if (word_count >= 2 && MR_streq(words[1], "user_event_set")) {
+        const MR_UserEventSpec  *user_event_spec;
+        const char              *user_event_set;
+        int                     slot;
+        int                     set;
+        int                     spec;
+        MR_bool                 found_event_set;
+
+        if (word_count == 2) {
+            user_event_set = NULL;
+        } else if (word_count == 3) {
+            user_event_set = words[2];
+        } else {
+            MR_trace_usage_cur_cmd();
+            return KEEP_INTERACTING;
+        }
+
+        MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE);
+
+        if (user_event_set != NULL) {
+            found_event_set = MR_FALSE;
+            for (set = 0; set < MR_trace_event_set_next; set++) {
+                if (MR_streq(user_event_set,
+                    MR_trace_event_sets[set].MR_tes_name))
+                {
+                    found_event_set = MR_TRUE;
+                }
+            }
+
+            if (! found_event_set) {
+                fprintf(MR_mdb_out,
+                    "There is no user event set named `%s'.\n",
+                    user_event_set);
+                return KEEP_INTERACTING;
+            }
+        }
+
+        if (ignore_count > 0 && ignore_when == MR_SPY_IGNORE_ENTRY) {
+            fprintf(MR_mdb_out, "That breakpoint "
+                "would never become enabled.\n");
+            return KEEP_INTERACTING;
+        } else if (ignore_count > 0 &&
+            ignore_when == MR_SPY_IGNORE_INTERFACE)
+        {
+            fprintf(MR_mdb_out, "That breakpoint "
+                "would never become enabled.\n");
+            return KEEP_INTERACTING;
+        }
+
+        MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE);
+        slot = MR_add_user_event_spy_point(action, ignore_when, ignore_count,
+            user_event_set, NULL, print_list, &problem);
+        MR_maybe_print_spy_point(slot, problem);
     } else if (word_count == 2 && MR_streq(words[1], "here")) {
         int             slot;
         MR_TracePort    port;
@@ -140,27 +296,27 @@
         slot = MR_add_proc_spy_point(MR_SPY_SPECIFIC, action, ignore_when,
             ignore_count, layout->MR_sll_entry, layout, print_list, &problem);
         MR_maybe_print_spy_point(slot, problem);
-    } else if (word_count == 2 && MR_parse_proc_spec(words[1], &spec)) {
+    } else if (word_count == 2 && MR_parse_proc_spec(words[1], &proc_spec)) {
         MR_MatchesInfo  matches;
         int             slot;
 
         MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE);
-        matches = MR_search_for_matching_procedures(&spec);
+        matches = MR_search_for_matching_procedures(&proc_spec);
         if (matches.match_proc_next == 0) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: there is no such procedure.\n");
         } else if (matches.match_proc_next == 1) {
             slot = MR_add_proc_spy_point(when, action, ignore_when,
-                ignore_count, matches.match_procs[0], NULL, print_list,
-                &problem);
+                ignore_count, matches.match_procs[0], NULL,
+                print_list, &problem);
             MR_maybe_print_spy_point(slot, problem);
         } else if (multi_match == MR_MULTIMATCH_ALL) {
             int i;
 
             for (i = 0; i < matches.match_proc_next; i++) {
                 slot = MR_add_proc_spy_point(when, action, ignore_when,
-                    ignore_count, matches.match_procs[i], NULL, print_list,
-                    &problem);
+                    ignore_count, matches.match_procs[i], NULL,
+                    print_list, &problem);
                 MR_maybe_print_spy_point(slot, problem);
             }
         } else {
@@ -191,8 +347,8 @@
             } else if (MR_streq(line2, "*")) {
                 for (i = 0; i < matches.match_proc_next; i++) {
                     slot = MR_add_proc_spy_point(when, action, ignore_when,
-                        ignore_count, matches.match_procs[i], NULL, print_list,
-                        &problem);
+                        ignore_count, matches.match_procs[i], NULL,
+                        print_list, &problem);
                     MR_maybe_print_spy_point(slot, problem);
                 }
 
@@ -200,8 +356,8 @@
             } else if (MR_trace_is_natural_number(line2, &i)) {
                 if (0 <= i && i < matches.match_proc_next) {
                     slot = MR_add_proc_spy_point(when, action, ignore_when,
-                        ignore_count, matches.match_procs[i], NULL, print_list,
-                        &problem);
+                        ignore_count, matches.match_procs[i], NULL,
+                        print_list, &problem);
                     MR_maybe_print_spy_point(slot, problem);
                 } else {
                     fprintf(MR_mdb_out, "no such match\n");
@@ -281,13 +437,11 @@
         return KEEP_INTERACTING;
     }
 
-    if (! MR_spy_points[break_num]->spy_exists) {
+    if (! MR_spy_points[break_num]->MR_spy_exists) {
         fprintf(MR_mdb_err, "Breakpoint %d has been deleted.\n", break_num);
         return KEEP_INTERACTING;
     }
 
-    cond = MR_malloc(sizeof(MR_SpyCond));
-
     what_str = MR_malloc(strlen(words[1]) + 1);
     strcpy(what_str, words[1]);
 
@@ -329,23 +483,34 @@
         return KEEP_INTERACTING;
     }
 
-    if (MR_spy_points[break_num]->spy_cond != NULL) {
-        MR_delete_cterm(MR_spy_points[break_num]->spy_cond->cond_term);
-        MR_free(MR_spy_points[break_num]->spy_cond->cond_what_string);
-        MR_free(MR_spy_points[break_num]->spy_cond->cond_term_string);
-        MR_free(MR_spy_points[break_num]->spy_cond);
-    }
-
-    cond->cond_var_spec = var_spec;
-    cond->cond_path = path;
-    cond->cond_test = test;
-    cond->cond_term = term;
-    cond->cond_term_string = term_str;
-    cond->cond_what_string = what_str;
-    cond->cond_require_var = require_var;
-    cond->cond_require_path = require_path;
+    if (MR_spy_points[break_num]->MR_spy_cond != NULL) {
+        MR_delete_cterm(MR_spy_points[break_num]->MR_spy_cond->MR_cond_term);
+        MR_free(MR_spy_points[break_num]->MR_spy_cond->MR_cond_what_string);
+        MR_free(MR_spy_points[break_num]->MR_spy_cond->MR_cond_term_string);
+        MR_free(MR_spy_points[break_num]->MR_spy_cond);
+    }
+
+    if (MR_spy_points[break_num]->MR_spy_when == MR_SPY_USER_EVENT_SET) {
+        /*
+        ** If the breakpoint is matched by all events in an event set (or
+        ** possibly all events in all event sets), then it doesn't make sense
+        ** to insist on any given variable name existing at the matching event.
+        */
+        require_var = MR_FALSE;
+        require_path = MR_FALSE;
+    }
+
+    cond = MR_malloc(sizeof(MR_SpyCond));
+    cond->MR_cond_var_spec = var_spec;
+    cond->MR_cond_path = path;
+    cond->MR_cond_test = test;
+    cond->MR_cond_term = term;
+    cond->MR_cond_term_string = term_str;
+    cond->MR_cond_what_string = what_str;
+    cond->MR_cond_require_var = require_var;
+    cond->MR_cond_require_path = require_path;
 
-    MR_spy_points[break_num]->spy_cond = cond;
+    MR_spy_points[break_num]->MR_spy_cond = cond;
 
     MR_print_spy_point(MR_mdb_out, break_num, MR_TRUE);
     return KEEP_INTERACTING;
@@ -367,7 +532,9 @@
     {
         ; /* the usage message has already been printed */
     } else if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
-        if (0 <= n && n < MR_spy_point_next && MR_spy_points[n]->spy_exists) {
+        if (0 <= n && n < MR_spy_point_next &&
+            MR_spy_points[n]->MR_spy_exists)
+        {
             problem = MR_ignore_spy_point(n, ignore_when, ignore_count);
             MR_maybe_print_spy_point(n, problem);
         } else {
@@ -380,7 +547,7 @@
 
         count = 0;
         for (i = 0; i < MR_spy_point_next; i++) {
-            if (MR_spy_points[i]->spy_exists) {
+            if (MR_spy_points[i]->MR_spy_exists) {
                 problem = MR_ignore_spy_point(n, ignore_when, ignore_count);
                 MR_maybe_print_spy_point(n, problem);
                 count++;
@@ -393,7 +560,7 @@
     } 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]->MR_spy_exists)
         {
             n = MR_most_recent_spy_point;
             problem = MR_ignore_spy_point(n, ignore_when, ignore_count);
@@ -413,40 +580,62 @@
 MR_trace_cmd_break_print(char **words, int word_count, MR_TraceCmdInfo *cmd,
     MR_EventInfo *event_info, MR_Code **jumpaddr)
 {
-    int                 n;
+    int                 break_num;
     int                 i;
     MR_BrowseFormat     format;
     MR_bool             at_start;
     MR_bool             warn;
     MR_SpyPrintList     print_list;
+    MR_SpyPrint         sp;
+    const char          *problem;
+    MR_bool             any_problem;
 
-    if (! MR_trace_options_break_print(&format, &at_start, &warn,
+    if (! MR_trace_options_break_print(&break_num, &format, &at_start, &warn,
         &words, &word_count))
     {
         ; /* the usage message has already been printed */
-    } else if (word_count > 2 && MR_trace_is_natural_number(words[1], &n)) {
-        if (word_count == 3 && MR_streq(words[2], "none")) {
-            MR_clear_spy_point_print_list(n);
-            MR_print_spy_point(MR_mdb_out, n, MR_TRUE);
-        } else if (0 <= n && n < MR_spy_point_next
-            && MR_spy_points[n]->spy_exists)
+    } else if (word_count > 1) {
+        if (break_num < 0) {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err, "mdb: no break point exists.\n");
+        } else if (! (0 <= break_num && break_num < MR_spy_point_next
+            && MR_spy_points[break_num]->MR_spy_exists))
         {
+            fflush(MR_mdb_out);
+            fprintf(MR_mdb_err, "mdb: break point #%d does not exist.\n",
+                break_num);
+        } else {
+            if (word_count == 2 && MR_streq(words[1], "none")) {
+                MR_clear_spy_point_print_list(break_num);
+                MR_print_spy_point(MR_mdb_out, break_num, MR_TRUE);
+            } else {
             print_list = NULL;
-            for (i = 2; i < word_count; i++) {
-                print_list = MR_add_to_print_list_end(format, words[i], warn,
-                    print_list);
+                any_problem = MR_FALSE;
+                for (i = 1; i < word_count; i++) {
+                    problem = MR_parse_spy_print(format, warn, words[i], &sp);
+                    if (problem != NULL) {
+                        fflush(MR_mdb_out);
+                        fprintf(MR_mdb_err, "mdb: cannot parse `%s'\n",
+                            words[i]);
+                        any_problem = MR_TRUE;
+                    } else {
+                        print_list =
+                            MR_add_to_print_list_end(sp, print_list);
+                    }
             }
 
+                if (! any_problem) {
             if (at_start) {
-                MR_add_spy_point_print_list_start(n, print_list);
+                        MR_add_spy_point_print_list_start(break_num,
+                            print_list);
             } else {
-                MR_add_spy_point_print_list_end(n, print_list);
+                        MR_add_spy_point_print_list_end(break_num,
+                            print_list);
             }
 
-            MR_print_spy_point(MR_mdb_out, n, MR_TRUE);
-        } else {
-            fflush(MR_mdb_out);
-            fprintf(MR_mdb_err, "mdb: break point #%d does not exist.\n", n);
+                    MR_print_spy_point(MR_mdb_out, break_num, MR_TRUE);
+                }
+            }
         }
     } else {
         MR_trace_usage_cur_cmd();
@@ -462,8 +651,10 @@
     int n;
 
     if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
-        if (0 <= n && n < MR_spy_point_next && MR_spy_points[n]->spy_exists) {
-            MR_spy_points[n]->spy_enabled = MR_TRUE;
+        if (0 <= n && n < MR_spy_point_next &&
+            MR_spy_points[n]->MR_spy_exists)
+        {
+            MR_spy_points[n]->MR_spy_enabled = MR_TRUE;
             MR_print_spy_point(MR_mdb_out, n, MR_FALSE);
         } else {
             fflush(MR_mdb_out);
@@ -475,8 +666,8 @@
 
         count = 0;
         for (i = 0; i < MR_spy_point_next; i++) {
-            if (MR_spy_points[i]->spy_exists) {
-                MR_spy_points[i]->spy_enabled = MR_TRUE;
+            if (MR_spy_points[i]->MR_spy_exists) {
+                MR_spy_points[i]->MR_spy_enabled = MR_TRUE;
                 MR_print_spy_point(MR_mdb_out, i, MR_FALSE);
                 count++;
             }
@@ -488,9 +679,9 @@
     } 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]->MR_spy_exists)
         {
-            MR_spy_points[MR_most_recent_spy_point]->spy_enabled = MR_TRUE;
+            MR_spy_points[MR_most_recent_spy_point]->MR_spy_enabled = MR_TRUE;
             MR_print_spy_point(MR_mdb_out, MR_most_recent_spy_point, MR_FALSE);
         } else {
             fflush(MR_mdb_out);
@@ -510,8 +701,10 @@
     int n;
 
     if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
-        if (0 <= n && n < MR_spy_point_next && MR_spy_points[n]->spy_exists) {
-            MR_spy_points[n]->spy_enabled = MR_FALSE;
+        if (0 <= n && n < MR_spy_point_next &&
+            MR_spy_points[n]->MR_spy_exists)
+        {
+            MR_spy_points[n]->MR_spy_enabled = MR_FALSE;
             MR_print_spy_point(MR_mdb_out, n, MR_FALSE);
         } else {
             fflush(MR_mdb_out);
@@ -523,8 +716,8 @@
 
         count = 0;
         for (i = 0; i < MR_spy_point_next; i++) {
-            if (MR_spy_points[i]->spy_exists) {
-                MR_spy_points[i]->spy_enabled = MR_FALSE;
+            if (MR_spy_points[i]->MR_spy_exists) {
+                MR_spy_points[i]->MR_spy_enabled = MR_FALSE;
                 MR_print_spy_point(MR_mdb_out, i, MR_FALSE);
                 count++;
             }
@@ -537,9 +730,9 @@
     } 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]->MR_spy_exists)
         {
-            MR_spy_points[MR_most_recent_spy_point]->spy_enabled = MR_FALSE;
+            MR_spy_points[MR_most_recent_spy_point]->MR_spy_enabled = MR_FALSE;
             MR_print_spy_point(MR_mdb_out, MR_most_recent_spy_point, MR_FALSE);
         } else {
             fflush(MR_mdb_out);
@@ -559,10 +752,12 @@
     int n;
 
     if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
-        if (0 <= n && n < MR_spy_point_next && MR_spy_points[n]->spy_exists) {
-            MR_spy_points[n]->spy_exists = MR_FALSE;
+        if (0 <= n && n < MR_spy_point_next &&
+            MR_spy_points[n]->MR_spy_exists)
+        {
+            MR_spy_points[n]->MR_spy_exists = MR_FALSE;
             MR_print_spy_point(MR_mdb_out, n, MR_FALSE);
-            MR_spy_points[n]->spy_exists = MR_TRUE;
+            MR_spy_points[n]->MR_spy_exists = MR_TRUE;
             MR_delete_spy_point(n);
         } else {
             fflush(MR_mdb_out);
@@ -574,10 +769,10 @@
 
         count = 0;
         for (i = 0; i < MR_spy_point_next; i++) {
-            if (MR_spy_points[i]->spy_exists) {
-                MR_spy_points[i]->spy_exists = MR_FALSE;
+            if (MR_spy_points[i]->MR_spy_exists) {
+                MR_spy_points[i]->MR_spy_exists = MR_FALSE;
                 MR_print_spy_point(MR_mdb_out, i, MR_FALSE);
-                MR_spy_points[i]->spy_exists = MR_TRUE;
+                MR_spy_points[i]->MR_spy_exists = MR_TRUE;
                 MR_delete_spy_point(i);
                 count++;
             }
@@ -590,14 +785,14 @@
     } 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]->MR_spy_exists)
         {
             int slot;
 
             slot = MR_most_recent_spy_point;
-            MR_spy_points[slot]->spy_exists = MR_FALSE;
+            MR_spy_points[slot]->MR_spy_exists = MR_FALSE;
             MR_print_spy_point(MR_mdb_out, slot, MR_FALSE);
-            MR_spy_points[slot]->spy_exists = MR_TRUE;
+            MR_spy_points[slot]->MR_spy_exists = MR_TRUE;
             MR_delete_spy_point(slot);
         } else {
             fflush(MR_mdb_out);
@@ -659,42 +854,70 @@
 
 /****************************************************************************/
 
-static MR_SpyPrintList
-MR_add_to_print_list_end(MR_BrowseFormat format, char *word, MR_bool warn,
-    MR_SpyPrintList print_list)
+static const char *
+MR_parse_spy_print(MR_BrowseFormat format, MR_bool warn, char *word,
+    MR_SpyPrint *sp_ptr)
 {
-    MR_SpyPrintList     list;
-    MR_SpyPrintList     new_list;
-    MR_SpyPrint         new_node;
+    MR_SpyPrint sp;
+    const char  *problem;
+
+    word = MR_copy_string(word);
+
+    problem = NULL;
+    sp = MR_malloc(sizeof(struct MR_SpyPrint_Struct));
+    sp->MR_p_format = format;
+    sp->MR_p_warn = warn;
+    sp->MR_p_word_copy = word;
 
-    new_node = MR_malloc(sizeof(struct MR_SpyPrint_Struct));
-    new_node->p_format = format;
-    new_node->p_warn = warn;
     if (MR_streq(word, "*")) {
-        new_node->p_what = MR_SPY_PRINT_ALL;
-        new_node->p_name = NULL;
+        sp->MR_p_what = MR_SPY_PRINT_ALL;
+        /* The other fields are initialized to dummies. */
+        sp->MR_p_var_spec.MR_var_spec_kind = MR_VAR_SPEC_NAME;
+        sp->MR_p_var_spec.MR_var_spec_number = -1;
+        sp->MR_p_var_spec.MR_var_spec_name = NULL;
+        sp->MR_p_path = NULL;
     } else if (MR_streq(word, "goal")) {
-        new_node->p_what = MR_SPY_PRINT_GOAL;
-        new_node->p_name = NULL;
+        sp->MR_p_what = MR_SPY_PRINT_GOAL;
+        /* The other fields are initialized to dummies. */
+        sp->MR_p_var_spec.MR_var_spec_kind = MR_VAR_SPEC_NAME;
+        sp->MR_p_var_spec.MR_var_spec_number = -1;
+        sp->MR_p_var_spec.MR_var_spec_name = NULL;
+        sp->MR_p_path = NULL;
     } else {
-        new_node->p_what = MR_SPY_PRINT_ONE;
-        new_node->p_name = MR_copy_string(word);
+        sp->MR_p_what = MR_SPY_PRINT_ONE;
+        problem = MR_trace_parse_var_path(word,
+            &sp->MR_p_var_spec, &sp->MR_p_path);
     }
 
+    if (problem == NULL) {
+        *sp_ptr = sp;
+    } else {
+        *sp_ptr = NULL;
+    }
+
+    return problem;
+}
+
+static MR_SpyPrintList
+MR_add_to_print_list_end(MR_SpyPrint sp, MR_SpyPrintList print_list)
+{
+    MR_SpyPrintList     list;
+    MR_SpyPrintList     new_list;
+
     new_list = MR_malloc(sizeof(struct MR_SpyPrintList_Struct));
-    new_list->pl_cur = new_node;
-    new_list->pl_next = NULL;
+    new_list->MR_pl_cur = sp;
+    new_list->MR_pl_next = NULL;
 
     list = print_list;
     if (list == NULL) {
         return new_list;
     }
 
-    while (list->pl_next != NULL) {
-        list = list->pl_next;
+    while (list->MR_pl_next != NULL) {
+        list = list->MR_pl_next;
     }
 
-    list->pl_next = new_list;
+    list->MR_pl_next = new_list;
     return print_list;
 }
 
@@ -737,7 +960,7 @@
     { "-A", "-E", "-I", "-O", "-P", "-S", "-a", "-e", "-i",
     "--all", "--entry", "--ignore-entry", "--ignore-interface",
     "--interface", "--print", "--select-all", "--select-one",
-    "--stop", "here", "info", NULL };
+    "--stop", "here", "info", "user_event", NULL };
 
 const char *const    MR_trace_ignore_cmd_args[] =
     { "-E", "-I", "--ignore-entry", "--ignore-interface", NULL };
@@ -749,6 +972,7 @@
     { "all",                MR_no_argument,         NULL,   'a' },
     { "entry",              MR_no_argument,         NULL,   'e' },
     { "interface",          MR_no_argument,         NULL,   'i' },
+    { "ignore",             MR_required_argument,   NULL,   'X' },
     { "ignore-entry",       MR_required_argument,   NULL,   'E' },
     { "ignore-interface",   MR_required_argument,   NULL,   'I' },
     { "print-list",         MR_required_argument,   NULL,   'p' },
@@ -767,13 +991,14 @@
     MR_SpyPrintList *print_list, char ***words, int *word_count)
 {
     int                 c;
-    MR_SpyPrint         node;
+    MR_SpyPrint     sp;
     MR_SpyPrintList     list;
     MR_bool             warn;
+    const char      *problem;
 
     warn = MR_TRUE;
     MR_optind = 0;
-    while ((c = MR_getopt_long(*word_count, *words, "AE:I:OPSaeinp:",
+    while ((c = MR_getopt_long(*word_count, *words, "AE:I:OPSX:aeinp:",
         MR_trace_when_action_multi_ignore_opts, NULL)) != EOF)
     {
         switch (c) {
@@ -795,8 +1020,15 @@
                 break;
 
             case 'p':
-                *print_list = MR_add_to_print_list_end(MR_BROWSE_FORMAT_FLAT,
-                    MR_optarg, warn, *print_list);
+                problem = MR_parse_spy_print(MR_BROWSE_FORMAT_FLAT, warn,
+                    MR_optarg, &sp);
+                if (problem != NULL) {
+                    fflush(MR_mdb_out);
+                    fprintf(MR_mdb_err, "mdb: cannot parse `%s'\n", MR_optarg);
+                    return MR_FALSE;
+                }
+
+                *print_list = MR_add_to_print_list_end(sp, *print_list);
                 break;
 
             case 'E':
@@ -815,6 +1047,14 @@
                 *ignore_when = MR_SPY_IGNORE_INTERFACE;
                 break;
 
+            case 'X':
+                if (! MR_trace_is_natural_number(MR_optarg, ignore_count)) {
+                    MR_trace_usage_cur_cmd();
+                    return MR_FALSE;
+                }
+                *ignore_when = MR_SPY_IGNORE_ALL;
+                break;
+
             case 'A':
                 *multi_match = MR_MULTIMATCH_ALL;
                 break;
@@ -844,7 +1084,7 @@
 
 static struct MR_option MR_trace_condition_opts[] =
 {
-    { "break-num",          MR_required_argument,   NULL,   'n' },
+    { "break-num",          MR_required_argument,   NULL,   'b' },
     { "dont-require-var",   MR_no_argument,         NULL,   'v' },
     { "dont-require-path",  MR_no_argument,         NULL,   'p' },
     { NULL,                 MR_no_argument,         NULL,   0 }
@@ -858,12 +1098,12 @@
     int n;
 
     MR_optind = 0;
-    while ((c = MR_getopt_long(*word_count, *words, "n:vp",
+    while ((c = MR_getopt_long(*word_count, *words, "b:vp",
         MR_trace_condition_opts, NULL)) != EOF)
     {
         switch (c) {
 
-            case 'n':
+            case 'b':
                 if (! MR_trace_is_natural_number(MR_optarg, &n)) {
                     MR_trace_usage_cur_cmd();
                     return MR_FALSE;
@@ -898,6 +1138,7 @@
 
 static struct MR_option MR_trace_ignore_count_opts[] =
 {
+    { "ignore",             MR_required_argument,   NULL,   'X' },
     { "ignore-entry",       MR_required_argument,   NULL,   'E' },
     { "ignore-interface",   MR_required_argument,   NULL,   'I' },
     { NULL,                 MR_no_argument,         NULL,   0 }
@@ -910,7 +1151,7 @@
     int c;
 
     MR_optind = 0;
-    while ((c = MR_getopt_long(*word_count, *words, "E:I:",
+    while ((c = MR_getopt_long(*word_count, *words, "E:I:X:",
         MR_trace_ignore_count_opts, NULL)) != EOF)
     {
         switch (c) {
@@ -931,6 +1172,14 @@
                 *ignore_when = MR_SPY_IGNORE_INTERFACE;
                 break;
 
+            case 'X':
+                if (! MR_trace_is_natural_number(MR_optarg, ignore_count)) {
+                    MR_trace_usage_cur_cmd();
+                    return MR_FALSE;
+                }
+                *ignore_when = MR_SPY_IGNORE_ALL;
+                break;
+
             default:
                 MR_trace_usage_cur_cmd();
                 return MR_FALSE;
@@ -944,6 +1193,7 @@
 
 static struct MR_option MR_trace_break_print_opts[] =
 {
+    { "break-num",  MR_required_argument, NULL,   'b' },
     { "end",        MR_no_argument, NULL,   'e' },
     { "no-warn",    MR_no_argument, NULL,   'n' },
     { "flat",       MR_no_argument, NULL,   'f' },
@@ -954,20 +1204,30 @@
 };
 
 static MR_bool
-MR_trace_options_break_print(MR_BrowseFormat *format, MR_bool *at_start,
-    MR_bool *warn, char ***words, int *word_count)
+MR_trace_options_break_print(int *break_num, MR_BrowseFormat *format,
+    MR_bool *at_start, MR_bool *warn, char ***words, int *word_count)
 {
     int c;
+    int n;
 
+    *break_num = MR_most_recent_spy_point;
     *format = MR_BROWSE_FORMAT_FLAT;
     *at_start = MR_TRUE;
     *warn = MR_TRUE;
     MR_optind = 0;
-    while ((c = MR_getopt_long(*word_count, *words, "enfrvp",
+    while ((c = MR_getopt_long(*word_count, *words, "b:enfrvp",
         MR_trace_break_print_opts, NULL)) != EOF)
     {
         switch (c) {
 
+            case 'b':
+                if (! MR_trace_is_natural_number(MR_optarg, &n)) {
+                    MR_trace_usage_cur_cmd();
+                    return MR_FALSE;
+                }
+                *break_num = n;
+                break;
+
             case 'e':
                 *at_start = MR_FALSE;
                 break;
Index: trace/mercury_trace_cmd_misc.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_cmd_misc.c,v
retrieving revision 1.3
diff -u -b -r1.3 mercury_trace_cmd_misc.c
--- trace/mercury_trace_cmd_misc.c	29 Nov 2006 05:18:36 -0000	1.3
+++ trace/mercury_trace_cmd_misc.c	12 Jan 2007 11:18:24 -0000
@@ -164,6 +164,8 @@
 
             case MR_SPY_LINENO:
             case MR_SPY_SPECIFIC:
+            case MR_SPY_USER_EVENT:
+            case MR_SPY_USER_EVENT_SET:
                 MR_fatal_error("save cmd: invalid default scope");
         }
 
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.232
diff -u -b -r1.232 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	3 Jan 2007 05:17:21 -0000	1.232
+++ trace/mercury_trace_internal.c	18 Jan 2007 10:17:28 -0000
@@ -358,25 +358,6 @@
         MR_io_tabling_start = MR_IO_ACTION_MAX;
         MR_io_tabling_end = MR_IO_ACTION_MAX;
 
-        for (i = 0; i < MR_trace_event_set_next; i++) {
-            if (! MR_trace_event_sets[i].MR_tes_is_consistent) {
-                fprintf(MR_mdb_out,
-                    "The executable's modules were compiled with "
-                    "inconsistent definitions of user event set %s.\n",
-                    MR_trace_event_sets[i].MR_tes_name);
-            } else {
-                MR_trace_event_sets[i].MR_tes_event_set =
-                    MR_read_event_set("no input file",
-                        MR_trace_event_sets[i].MR_tes_desc);
-                if (MR_trace_event_sets[i].MR_tes_event_set == NULL) {
-                    fprintf(MR_mdb_out,
-                        "Internal error: could not parse "
-                        "the specification of event set %s.\n",
-                        MR_trace_event_sets[i].MR_tes_name);
-                }
-            }
-        }
-
         MR_trace_internal_initialized = MR_TRUE;
     }
 }
@@ -808,37 +789,38 @@
 {
     MR_SpyPrint    node;
     const char      *problem;
-    char            *after_problem;
+    MR_VarSpec      *after_var_spec;
     int             count;
 
     count = 0;
-    for (; print_list != NULL; print_list = print_list->pl_next) {
+    for (; print_list != NULL; print_list = print_list->MR_pl_next) {
         count++;
-        node = print_list->pl_cur;
-        after_problem = NULL;
+        node = print_list->MR_pl_cur;
+        after_var_spec = NULL;
 
-        switch (node->p_what) {
+        switch (node->MR_p_what) {
             case MR_SPY_PRINT_ALL:
                 problem = MR_trace_browse_all(MR_mdb_out,
-                    MR_trace_browse_internal, node->p_format);
+                    MR_trace_browse_internal, node->MR_p_format);
                 break;
 
             case MR_SPY_PRINT_GOAL:
                 problem = MR_trace_browse_one_goal(MR_mdb_out,
                     MR_trace_browse_goal_internal, MR_BROWSE_CALLER_PRINT,
-                    node->p_format);
+                    node->MR_p_format);
                 break;
 
             case MR_SPY_PRINT_ONE:
-                problem = MR_trace_parse_browse_one(MR_mdb_out, MR_TRUE,
-                    node->p_name, MR_trace_browse_internal,
-                    MR_BROWSE_CALLER_PRINT, node->p_format, MR_FALSE);
+                problem = MR_trace_browse_one_path(MR_mdb_out, MR_TRUE,
+                    node->MR_p_var_spec, node->MR_p_path,
+                    MR_trace_browse_internal, MR_BROWSE_CALLER_PRINT,
+                    node->MR_p_format, MR_FALSE);
                 if (problem != NULL &&
                     MR_streq(problem, "there is no such variable"))
                 {
-                    if (node->p_warn) {
+                    if (node->MR_p_warn) {
                         problem = "there is no variable named";
-                        after_problem = node->p_name;
+                        after_var_spec = &node->MR_p_var_spec;
                     } else {
                         problem = NULL;
                     }
@@ -847,15 +829,16 @@
                 break;
 
             default:
-                MR_fatal_error("invalid node->p_what");
+                MR_fatal_error("invalid node->MR_p_what");
                 break;
         }
 
         if (problem != NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: %s", problem);
-            if (after_problem != NULL) {
-                fprintf(MR_mdb_err, " %s", after_problem);
+            if (after_var_spec != NULL) {
+                fprintf(MR_mdb_err, " ");
+                MR_print_var_spec(MR_mdb_err, after_var_spec);
             }
             fprintf(MR_mdb_err, ".\n");
         }
@@ -1388,7 +1371,7 @@
 
     list = print_list;
     len = 0;
-    for (; list != NULL; list = list->pl_next) {
+    for (; list != NULL; list = list->MR_pl_next) {
         len++;
     }
 
Index: trace/mercury_trace_spy.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_spy.c,v
retrieving revision 1.29
diff -u -b -r1.29 mercury_trace_spy.c
--- trace/mercury_trace_spy.c	29 Nov 2006 05:18:40 -0000	1.29
+++ trace/mercury_trace_spy.c	18 Jan 2007 08:08:14 -0000
@@ -44,6 +44,8 @@
     "entry",
     "specific",
     "linenumber",
+    "user_event",
+    "user_event_set",
 };
 
 /*
@@ -70,8 +72,8 @@
 */
 
 typedef struct {
-    const MR_ProcLayout     *spy_proc;
-    MR_SpyPoint            *spy_points;
+    const MR_ProcLayout     *MR_sp_proc;
+    MR_SpyPoint             *MR_sp_points;
 } MR_SpiedProc;
 
 static  MR_SpiedProc       *MR_spied_procs;
@@ -89,8 +91,8 @@
 */
 
 typedef struct {
-    const MR_LabelLayout    *spy_label;
-    int                     spy_point_num;
+    const MR_LabelLayout    *MR_sl_label;
+    int                     MR_sl_point_num;
 } MR_SpiedLabel;
 
 static  MR_SpiedLabel      *MR_spied_labels;
@@ -100,6 +102,54 @@
 /* The initial size of the spied labels table. */
 #define MR_INIT_SPIED_LABELS    10
 
+/*
+** The table of spied on user event names, with one entry per user event
+** name that is currently being spied on, ordered on the event name,
+** and with counters saying which is the next free slot and how many slots
+** are allocated.
+**
+** All the MR_SPY_USER_EVENT breakpoints are listed in MR_spied_user_events,
+** whether or not the breakpoint requires a specific event set as well as a
+** specific name.
+*/
+
+typedef struct {
+    const char                  *MR_sue_user_event_name;
+    MR_SpyPoint                 *MR_sue_points;
+} MR_SpiedUserEvent;
+
+static  MR_SpiedUserEvent       *MR_spied_user_events;
+static  int                     MR_spied_user_event_next = 0;
+static  int                     MR_spied_user_event_max = 0;
+
+/* The initial size of the spied user events table. */
+#define MR_INIT_SPIED_USER_EVENTS  10
+
+/*
+** The table of spied on user event set names, with one entry per user event
+** set name that is currently being spied on, ordered on the event set name,
+** and with counters saying which is the next free slot and how many slots
+** are allocated.
+**
+** Only the MR_SPY_USER_EVENT_SET breakpoints that specify an event set
+** are listed in MR_spied_user_event_sets. The ones that do not specify
+** an event set are all listed in MR_spied_universal_user_events.
+*/
+
+typedef struct {
+    const char                  *MR_sues_user_event_set;
+    MR_SpyPoint                 *MR_sues_points;
+} MR_SpiedUserEventSet;
+
+static  MR_SpiedUserEventSet    *MR_spied_user_event_sets;
+static  int                     MR_spied_user_event_set_next = 0;
+static  int                     MR_spied_user_event_set_max = 0;
+
+/* The initial size of the spied user event sets table. */
+#define MR_INIT_SPIED_USER_EVENT_SETS  10
+
+static  MR_SpyPoint             *MR_spied_universal_user_events;
+
 /**************************************************************************/
 
 static  int         MR_compare_addr(const void *address1,
@@ -107,16 +157,23 @@
 static  int         MR_search_spy_table_for_proc(const MR_ProcLayout *entry);
 static  int         MR_search_spy_table_for_label(
                         const MR_LabelLayout *label);
+static  int         MR_search_spy_table_for_user_event_name(
+                        const char *user_event_name);
+static  int         MR_search_spy_table_for_user_event_set(
+                        const char *user_event_set);
 static  MR_bool     MR_spy_cond_is_true(MR_SpyPoint *point,
                         const MR_LabelLayout *label);
+static  int         MR_add_spy_point(MR_bool reuse, MR_SpyPoint *point);
 static  void        MR_add_line_spy_point_callback(
                         const MR_LabelLayout *label, int spy_point_num);
 static  int         MR_compare_spied_labels(const void *, const void *);
 static  void        MR_delete_spy_print_list(MR_SpyPrintList print_list);
 static  void        MR_update_enabled_action(MR_SpyPoint *point,
-                        MR_TracePort port, MR_SpyAction *action_ptr,
-                        MR_bool *enabled_ptr);
+                        const MR_LabelLayout *layout, MR_TracePort port,
+                        MR_bool *enabled_ptr, MR_SpyAction *action_ptr,
+                        MR_SpyPrintList *print_listr_ptr);
 static  const char  *MR_ignore_when_to_string(MR_SpyIgnore_When ignore_when);
+static  void        MR_print_spy_print_what(FILE *fp, MR_SpyPrint sp);
 
 /*
 ** Compare two addresses, and return an integer which is <0, 0, or >0
@@ -144,7 +201,7 @@
 }
 
 /*
-** Return the index of the entry in MR_spied_procs whose spy_proc field
+** Return the index of the entry in MR_spied_procs whose MR_sp_proc field
 ** is entry, or a negative number if absent.
 */
 
@@ -155,7 +212,7 @@
     MR_bool found;
 
     MR_bsearch(MR_spied_proc_next, slot, found,
-        MR_compare_addr(MR_spied_procs[slot].spy_proc, entry));
+        MR_compare_addr(MR_spied_procs[slot].MR_sp_proc, entry));
     if (found) {
         return slot;
     } else {
@@ -164,7 +221,7 @@
 }
 
 /*
-** Return the index of the entry in MR_spied_labels whose spy_label field
+** Return the index of the entry in MR_spied_labels whose MR_sl_label field
 ** is label, or a negative number if absent.
 */
 
@@ -175,7 +232,51 @@
     MR_bool found;
 
     MR_bsearch(MR_spied_label_next, slot, found,
-        MR_compare_addr(MR_spied_labels[slot].spy_label, label));
+        MR_compare_addr(MR_spied_labels[slot].MR_sl_label, label));
+    if (found) {
+        return slot;
+    } else {
+        return -1;
+    }
+}
+
+/*
+** Return the index of the entry in MR_spied_user_events whose
+** MR_sue_user_event_name field is user_event_name, or a negative number
+** if absent.
+*/
+
+static int
+MR_search_spy_table_for_user_event_name(const char *user_event_name)
+{
+    int     slot;
+    MR_bool found;
+
+    MR_bsearch(MR_spied_user_event_next, slot, found,
+        strcmp(MR_spied_user_events[slot].MR_sue_user_event_name,
+            user_event_name));
+    if (found) {
+        return slot;
+    } else {
+        return -1;
+    }
+}
+
+/*
+** Return the index of the entry in MR_spied_user_event_sets whose
+** MR_sues_user_event_set field is user_event_set, or a negative number
+** if absent.
+*/
+
+static int
+MR_search_spy_table_for_user_event_set(const char *user_event_set)
+{
+    int     slot;
+    MR_bool found;
+
+    MR_bsearch(MR_spied_user_event_set_next, slot, found,
+        strcmp(MR_spied_user_event_sets[slot].MR_sues_user_event_set,
+            user_event_set));
     if (found) {
         return slot;
     } else {
@@ -186,35 +287,36 @@
 MR_bool
 MR_event_matches_spy_point(const MR_LabelLayout *layout,
     MR_TracePort port, MR_SpyAction *action_ptr,
-    MR_SpyPrintList *print_list)
+    MR_SpyPrintList *print_list_ptr)
 {
     int                     slot;
     MR_bool                 enabled;
     MR_SpyPoint            *point;
     MR_SpyAction           action;
+    MR_SpyPrintList         print_list;
     const MR_LabelLayout    *parent;
+    const MR_UserEvent      *user_event;
+    const MR_UserEventSpec  *user_event_spec;
+    const char              *user_event_set;
+    const char              *user_event_name;
     const char              *problem;
     MR_Word                 *base_sp;
     MR_Word                 *base_curfr;
 
     enabled = MR_FALSE;
     action = MR_SPY_PRINT;
-    *print_list = NULL;
+    print_list = NULL;
 
     if (MR_spied_label_next > 0) {
         slot = MR_search_spy_table_for_label(layout);
         if (slot >= 0) {
-            point = MR_spy_points[MR_spied_labels[slot].spy_point_num];
-            if (point->spy_when != MR_SPY_LINENO) {
+            point = MR_spy_points[MR_spied_labels[slot].MR_sl_point_num];
+            if (point->MR_spy_when != MR_SPY_LINENO) {
                 MR_fatal_error("non-lineno spy point in spied labels array");
             }
 
-            if (MR_spy_cond_is_true(point, layout)) {
-                MR_update_enabled_action(point, port, &action, &enabled);
-                if (*print_list == NULL) {
-                    *print_list = point->spy_print_list;
-                }
-            }
+            MR_update_enabled_action(point, layout, port,
+                &enabled, &action, &print_list);
         }
 
         if (MR_port_is_interface(port)) {
@@ -226,48 +328,100 @@
             if (parent != NULL && 0 <=
                 (slot = MR_search_spy_table_for_label(parent)))
             {
-                point = MR_spy_points[MR_spied_labels[slot].spy_point_num];
-                if (point->spy_when != MR_SPY_LINENO) {
+                point = MR_spy_points[MR_spied_labels[slot].MR_sl_point_num];
+                if (point->MR_spy_when != MR_SPY_LINENO) {
                     MR_fatal_error("non-lineno spy point in "
                         "spied labels array");
                 }
 
-                if (MR_spy_cond_is_true(point, layout)) {
-                    MR_update_enabled_action(point, port, &action, &enabled);
-                    if (*print_list == NULL) {
-                        *print_list = point->spy_print_list;
+                MR_update_enabled_action(point, layout, port,
+                    &enabled, &action, &print_list);
+            }
+        }
+    }
+
+    user_event = layout->MR_sll_user_event;
+    if (user_event != NULL) {
+        user_event_spec = &MR_user_event_spec(layout);
+        user_event_name = user_event_spec->MR_ues_event_name;
+        user_event_set = MR_user_event_set_name(layout);
+
+        /*
+        ** Check for breakpoints that specify an event name, and possibly
+        ** and event set.
+        */
+
+        slot = MR_search_spy_table_for_user_event_name(user_event_name);
+        if (slot >= 0) {
+            for (point = MR_spied_user_events[slot].MR_sue_points;
+                point != NULL; point = point->MR_spy_next)
+            {
+                if (point->MR_spy_when != MR_SPY_USER_EVENT) {
+                    MR_fatal_error("non-named-user-event spy point "
+                        "in named user event array");
+                }
+
+                if (point->MR_spy_user_event_set == NULL ||
+                    MR_streq(user_event_set, point->MR_spy_user_event_set))
+                {
+                    MR_update_enabled_action(point, layout, port,
+                        &enabled, &action, &print_list);
                     }
                 }
             }
+
+        /*
+        ** Check for breakpoints that specify just an event set.
+        */
+
+        slot = MR_search_spy_table_for_user_event_set(user_event_set);
+        if (slot >= 0) {
+            for (point = MR_spied_user_event_sets[slot].MR_sues_points;
+                point != NULL; point = point->MR_spy_next)
+            {
+                if (point->MR_spy_when != MR_SPY_USER_EVENT_SET) {
+                    MR_fatal_error("non-named-user-event spy point "
+                        "in named user event array");
+                }
+
+                MR_update_enabled_action(point, layout, port,
+                    &enabled, &action, &print_list);
+            }
+        }
+
+        /*
+        ** Check for breakpoints that specify neither event name nor event set.
+        */
+
+        for (point = MR_spied_universal_user_events; point != NULL;
+            point = point->MR_spy_next)
+        {
+            if (point->MR_spy_when != MR_SPY_USER_EVENT_SET) {
+                MR_fatal_error("non-unnamed-user-event spy point "
+                    "in unnamed user event list");
+            }
+
+            MR_update_enabled_action(point, layout, port,
+                &enabled, &action, &print_list);
         }
     }
 
     slot = MR_search_spy_table_for_proc(layout->MR_sll_entry);
     if (slot >= 0) {
-        for (point = MR_spied_procs[slot].spy_points; point != NULL;
-            point = point->spy_next)
+        for (point = MR_spied_procs[slot].MR_sp_points; point != NULL;
+            point = point->MR_spy_next)
         {
-            switch (point->spy_when) {
+            switch (point->MR_spy_when) {
 
                 case MR_SPY_ALL:
-                    if (MR_spy_cond_is_true(point, layout)) {
-                        MR_update_enabled_action(point, port, &action,
-                            &enabled);
-                        if (*print_list == NULL) {
-                            *print_list = point->spy_print_list;
-                        }
-                    }
+                    MR_update_enabled_action(point, layout, port,
+                        &enabled, &action, &print_list);
                     break;
 
                 case MR_SPY_ENTRY:
                     if (MR_port_is_entry(port)) {
-                        if (MR_spy_cond_is_true(point, layout)) {
-                            MR_update_enabled_action(point, port, &action,
-                                &enabled);
-                            if (*print_list == NULL) {
-                                *print_list = point->spy_print_list;
-                            }
-                        }
+                        MR_update_enabled_action(point, layout, port,
+                            &enabled, &action, &print_list);
                     } else {
                         continue;
                     }
@@ -276,13 +430,8 @@
 
                 case MR_SPY_INTERFACE:
                     if (MR_port_is_interface(port)) {
-                        if (MR_spy_cond_is_true(point, layout)) {
-                            MR_update_enabled_action(point, port, &action,
-                                &enabled);
-                            if (*print_list == NULL) {
-                                *print_list = point->spy_print_list;
-                            }
-                        }
+                        MR_update_enabled_action(point, layout, port,
+                            &enabled, &action, &print_list);
                     } else {
                         continue;
                     }
@@ -290,14 +439,9 @@
                     break;
 
                 case MR_SPY_SPECIFIC:
-                    if (layout == point->spy_label) {
-                        if (MR_spy_cond_is_true(point, layout)) {
-                            MR_update_enabled_action(point, port, &action,
-                                &enabled);
-                            if (*print_list == NULL) {
-                                *print_list = point->spy_print_list;
-                            }
-                        }
+                    if (layout == point->MR_spy_label) {
+                        MR_update_enabled_action(point, layout, port,
+                            &enabled, &action, &print_list);
                     } else {
                         continue;
                     }
@@ -306,6 +450,17 @@
 
                 case MR_SPY_LINENO:
                     MR_fatal_error("lineno spy point in spied procs array");
+                    break;
+
+                case MR_SPY_USER_EVENT:
+                    MR_fatal_error("user_event spy point "
+                        "in spied procs array");
+                    break;
+
+                case MR_SPY_USER_EVENT_SET:
+                    MR_fatal_error("user_event_set spy point "
+                        "in spied procs array");
+                    break;
 
                 default:
                     MR_fatal_error("bad spy point when in "
@@ -316,6 +471,7 @@
 
     if (enabled) {
         *action_ptr = action;
+        *print_list_ptr = print_list;
         return MR_TRUE;
     } else {
         return MR_FALSE;
@@ -323,33 +479,39 @@
 }
 
 static void
-MR_update_enabled_action(MR_SpyPoint *point, MR_TracePort port,
-    MR_SpyAction *action_ptr, MR_bool *enabled_ptr)
+MR_update_enabled_action(MR_SpyPoint *point, const MR_LabelLayout *layout,
+    MR_TracePort port, MR_bool *enabled_ptr, MR_SpyAction *action_ptr,
+    MR_SpyPrintList *print_list_ptr)
 {
-    if (point->spy_enabled) {
-        if (point->spy_ignore_count == 0) {
+    if (point->MR_spy_enabled && MR_spy_cond_is_true(point, layout)) {
+        if (point->MR_spy_ignore_count == 0) {
             *enabled_ptr = MR_TRUE;
-            *action_ptr = MR_max(*action_ptr, point->spy_action);
+            *action_ptr = MR_max(*action_ptr, point->MR_spy_action);
+            if (*print_list_ptr == NULL) {
+                *print_list_ptr = point->MR_spy_print_list;
         }
-
-        if (point->spy_ignore_count > 0) {
-            switch (point->spy_ignore_when) {
+        } else if (point->MR_spy_ignore_count > 0) {
+            switch (point->MR_spy_ignore_when) {
 
                 case MR_SPY_DONT_IGNORE:
                     break;
 
                 case MR_SPY_IGNORE_ENTRY:
                     if (port == MR_PORT_CALL) {
-                        --point->spy_ignore_count;
+                        --point->MR_spy_ignore_count;
                     }
                     break;
 
                 case MR_SPY_IGNORE_INTERFACE:
                     if (MR_port_is_interface(port)) {
-                        --point->spy_ignore_count;
+                        --point->MR_spy_ignore_count;
                     }
                     break;
 
+                case MR_SPY_IGNORE_ALL:
+                    --point->MR_spy_ignore_count;
+                    break;
+
                 default:
                     MR_fatal_error("MR_update_enabled_action: "
                         "invalid ignore_when");
@@ -381,13 +543,13 @@
     MR_bool         retval;
     MR_SpyCond      *cond;
 
-    if (point->spy_cond == NULL) {
+    if (point->MR_spy_cond == NULL) {
         return MR_TRUE;
     }
 
     MR_restore_transient_registers();
 
-    cond = point->spy_cond;
+    cond = point->MR_spy_cond;
 
     /*
     ** From this point, returning should be done by setting both
@@ -404,10 +566,10 @@
     MR_trace_init_point_vars(label_layout, saved_regs,
         (MR_TracePort) label_layout->MR_sll_port, MR_FALSE);
 
-    problem = MR_lookup_unambiguous_var_spec(cond->cond_var_spec,
+    problem = MR_lookup_unambiguous_var_spec(cond->MR_cond_var_spec,
         &type_info, &value, &name);
     if (problem != NULL) {
-        if (cond->cond_require_var) {
+        if (cond->MR_cond_require_var) {
             MR_spy_point_cond_problem = problem;
             retval = MR_TRUE;
         } else {
@@ -419,11 +581,11 @@
     }
 
     value_ptr = &value;
-    bad_path = MR_select_specified_subterm(cond->cond_path,
+    bad_path = MR_select_specified_subterm(cond->MR_cond_path,
         type_info, value_ptr, &sub_type_info, &sub_value_ptr);
 
     if (bad_path != NULL) {
-        if (cond->cond_require_var) {
+        if (cond->MR_cond_require_var) {
             MR_spy_point_cond_problem = MR_trace_bad_path(bad_path);
             retval = MR_TRUE;
         } else {
@@ -442,7 +604,7 @@
     MR_trace_func_enabled = MR_FALSE;
     MR_TRACE_CALL_MERCURY(
         ML_BROWSE_match_with_cterm((MR_Word) sub_type_info, *sub_value_ptr,
-            cond->cond_term, &match);
+            cond->MR_cond_term, &match);
     );
     MR_trace_func_enabled = saved_trace_func_enabled;
 
@@ -450,7 +612,7 @@
     fprintf(stdout, "%d\n", match);
 #endif
 
-    switch (cond->cond_test) {
+    switch (cond->MR_cond_test) {
         case MR_SPY_TEST_EQUAL:
             MR_spy_point_cond_problem = NULL;
             if (match != 0) {
@@ -487,6 +649,33 @@
 static const char *incompatible =
     "Ignore count is not compatible with break point specification";
 
+static int
+MR_add_spy_point(MR_bool reuse, MR_SpyPoint *point)
+{
+    int i;
+    int point_slot;
+
+    if (reuse) {
+        /* Try to reuse an existing slot in the MR_spy_points array. */
+        for (i = 0; i < MR_spy_point_next; i++) {
+            if (! MR_spy_points[i]->MR_spy_exists) {
+                MR_most_recent_spy_point = i;
+                MR_spy_points[i] = point;
+                return i;
+            }
+        }
+    }
+
+    /* Allocate a new slot. */
+    MR_ensure_room_for_next(MR_spy_point, MR_SpyPoint *, MR_INIT_SPY_POINTS);
+    point_slot = MR_spy_point_next;
+    MR_spy_points[point_slot] = point;
+    MR_spy_point_next++;
+
+    MR_most_recent_spy_point = point_slot;
+    return point_slot;
+}
+
 int
 MR_add_proc_spy_point(MR_SpyWhen when, MR_SpyAction action,
     MR_SpyIgnore_When ignore_when, int ignore_count,
@@ -494,53 +683,42 @@
     MR_SpyPrintList print_list, const char **problem)
 {
     MR_SpyPoint     *point;
-    int             point_slot;
     int             proc_slot;
-    int             i;
 
     *problem = NULL;
 
+    /* Insert the spy point at the head of the list for the proc. */
+    point = MR_NEW(MR_SpyPoint);
+    point->MR_spy_when             = when;
+    point->MR_spy_exists           = MR_TRUE;
+    point->MR_spy_enabled          = MR_TRUE;
+    point->MR_spy_action           = action;
+    point->MR_spy_ignore_when      = ignore_when;
+    point->MR_spy_ignore_count     = ignore_count;
+    point->MR_spy_cond             = NULL;
+    point->MR_spy_print_list       = print_list;
+    point->MR_spy_proc             = entry;
+    point->MR_spy_label            = label;
+    point->MR_spy_filename         = NULL;
+    point->MR_spy_linenumber       = 0;
+    point->MR_spy_user_event_set   = NULL;
+    point->MR_spy_user_event_name  = NULL;
+
     proc_slot = MR_search_spy_table_for_proc(entry);
     if (proc_slot < 0) {
         MR_ensure_room_for_next(MR_spied_proc, MR_SpiedProc,
             MR_INIT_SPIED_PROCS);
         MR_prepare_insert_into_sorted(MR_spied_procs,
             MR_spied_proc_next, proc_slot,
-            MR_compare_addr(MR_spied_procs[proc_slot].spy_proc, entry));
-        MR_spied_procs[proc_slot].spy_proc = entry;
-        MR_spied_procs[proc_slot].spy_points = NULL;
+            MR_compare_addr(MR_spied_procs[proc_slot].MR_sp_proc, entry));
+        MR_spied_procs[proc_slot].MR_sp_proc = entry;
+        MR_spied_procs[proc_slot].MR_sp_points = NULL;
     }
 
-    /* Insert the spy point at the head of the list for the proc. */
-    point = MR_NEW(MR_SpyPoint);
-    point->spy_when    = when;
-    point->spy_exists  = MR_TRUE;
-    point->spy_enabled = MR_TRUE;
-    point->spy_action  = action;
-    point->spy_ignore_when  = ignore_when;
-    point->spy_ignore_count = ignore_count;
-    point->spy_cond    = NULL;
-    point->spy_print_list   = print_list;
-    point->spy_proc    = entry;
-    point->spy_label   = label;
-    point->spy_next    = MR_spied_procs[proc_slot].spy_points;
-    MR_spied_procs[proc_slot].spy_points = point;
+    point->MR_spy_next = MR_spied_procs[proc_slot].MR_sp_points;
+    MR_spied_procs[proc_slot].MR_sp_points = point;
 
-    for (i = 0; i < MR_spy_point_next; i++) {
-        if (! MR_spy_points[i]->spy_exists) {
-            MR_most_recent_spy_point = i;
-            MR_spy_points[i] = point;
-            return i;
-        }
-    }
-
-    MR_ensure_room_for_next(MR_spy_point, MR_SpyPoint *, MR_INIT_SPY_POINTS);
-    point_slot = MR_spy_point_next;
-    MR_spy_points[point_slot] = point;
-    MR_spy_point_next++;
-
-    MR_most_recent_spy_point = point_slot;
-    return point_slot;
+    return MR_add_spy_point(MR_TRUE, point);
 }
 
 /* 1024 characters should be big enough ... */
@@ -604,23 +782,20 @@
         MR_compare_spied_labels);
 
     point = MR_NEW(MR_SpyPoint);
-    point->spy_when       = MR_SPY_LINENO;
-    point->spy_exists     = MR_TRUE;
-    point->spy_enabled    = MR_TRUE;
-    point->spy_action     = action;
-    point->spy_ignore_when  = ignore_when;
-    point->spy_ignore_count = ignore_count;
-    point->spy_cond       = NULL;
-    point->spy_print_list = print_list;
-    point->spy_filename   = filename;
-    point->spy_linenumber = linenumber;
+    point->MR_spy_when            = MR_SPY_LINENO;
+    point->MR_spy_exists          = MR_TRUE;
+    point->MR_spy_enabled         = MR_TRUE;
+    point->MR_spy_action          = action;
+    point->MR_spy_ignore_when     = ignore_when;
+    point->MR_spy_ignore_count    = ignore_count;
+    point->MR_spy_cond            = NULL;
+    point->MR_spy_print_list      = print_list;
+    point->MR_spy_filename        = filename;
+    point->MR_spy_linenumber      = linenumber;
+    point->MR_spy_user_event_set  = NULL;
+    point->MR_spy_user_event_name = NULL;
 
-    MR_ensure_room_for_next(MR_spy_point, MR_SpyPoint *, MR_INIT_SPY_POINTS);
-    MR_spy_points[point_slot] = point;
-    MR_spy_point_next++;
-
-    MR_most_recent_spy_point = point_slot;
-    return point_slot;
+    return MR_add_spy_point(MR_FALSE, point);
 }
 
 static void
@@ -631,8 +806,8 @@
     MR_ensure_room_for_next(MR_spied_label, MR_SpiedLabel,
         MR_INIT_SPIED_LABELS);
     spied_label_slot = MR_spied_label_next;
-    MR_spied_labels[spied_label_slot].spy_label = label;
-    MR_spied_labels[spied_label_slot].spy_point_num = spy_point_num;
+    MR_spied_labels[spied_label_slot].MR_sl_label = label;
+    MR_spied_labels[spied_label_slot].MR_sl_point_num = spy_point_num;
     MR_spied_label_next++;
 }
 
@@ -645,8 +820,91 @@
     label1 = (const MR_SpiedLabel *) l1;
     label2 = (const MR_SpiedLabel *) l2;
 
-    return (int) ((MR_Integer) label1->spy_label
-        - (MR_Integer) label2->spy_label);
+    return (int) ((MR_Integer) label1->MR_sl_label
+        - (MR_Integer) label2->MR_sl_label);
+}
+
+int
+MR_add_user_event_spy_point(MR_SpyAction action,
+    MR_SpyIgnore_When ignore_when, int ignore_count,
+    const char *user_event_set, const char *user_event_name,
+    MR_SpyPrintList print_list, const char **problem)
+{
+    MR_SpyPoint     *point;
+    int             name_slot;
+    int             set_slot;
+    int             point_slot;
+    int             i;
+
+    *problem = NULL;
+
+    if (user_event_set != NULL) {
+        user_event_set = strdup(user_event_set);
+    }
+
+    if (user_event_name != NULL) {
+        user_event_name = strdup(user_event_name);
+    }
+
+    point = MR_NEW(MR_SpyPoint);
+    point->MR_spy_exists           = MR_TRUE;
+    point->MR_spy_enabled          = MR_TRUE;
+    point->MR_spy_action           = action;
+    point->MR_spy_ignore_when      = ignore_when;
+    point->MR_spy_ignore_count     = ignore_count;
+    point->MR_spy_cond             = NULL;
+    point->MR_spy_print_list       = print_list;
+    point->MR_spy_proc             = NULL;
+    point->MR_spy_label            = NULL;
+    point->MR_spy_user_event_set   = user_event_set;
+    point->MR_spy_user_event_name  = user_event_name;
+
+    if (user_event_name == NULL) {
+        point->MR_spy_when = MR_SPY_USER_EVENT_SET;
+
+        if (user_event_set == NULL) {
+            point->MR_spy_next = MR_spied_universal_user_events;
+            MR_spied_universal_user_events = point;
+        } else {
+            set_slot = MR_search_spy_table_for_user_event_set(user_event_set);
+            if (set_slot < 0) {
+                MR_ensure_room_for_next(MR_spied_user_event_set,
+                    MR_SpiedUserEventSet, MR_INIT_SPIED_USER_EVENT_SETS);
+                MR_prepare_insert_into_sorted(MR_spied_user_event_sets,
+                    MR_spied_user_event_set_next, set_slot,
+                    strcmp(MR_spied_user_event_sets[set_slot].
+                        MR_sues_user_event_set, user_event_set));
+                MR_spied_user_event_sets[set_slot].MR_sues_user_event_set =
+                    user_event_set;
+                MR_spied_user_event_sets[set_slot].MR_sues_points = NULL;
+            }
+
+            point->MR_spy_next =
+                MR_spied_user_event_sets[set_slot].MR_sues_points;
+            MR_spied_user_event_sets[set_slot].MR_sues_points = point;
+        }
+    } else {
+        point->MR_spy_when = MR_SPY_USER_EVENT;
+
+        name_slot = MR_search_spy_table_for_user_event_name(user_event_name);
+        if (name_slot < 0) {
+            MR_ensure_room_for_next(MR_spied_user_event,
+                MR_SpiedUserEvent, MR_INIT_SPIED_USER_EVENTS);
+            MR_prepare_insert_into_sorted(MR_spied_user_events,
+                MR_spied_user_event_next, name_slot,
+                strcmp(MR_spied_user_events[name_slot].
+                    MR_sue_user_event_name, user_event_name));
+            MR_spied_user_events[name_slot].MR_sue_user_event_name =
+                user_event_name;
+            MR_spied_user_events[name_slot].MR_sue_points = NULL;
+        }
+
+        point->MR_spy_next =
+            MR_spied_user_events[name_slot].MR_sue_points;
+        MR_spied_user_events[name_slot].MR_sue_points = point;
+    }
+
+    return MR_add_spy_point(MR_TRUE, point);
 }
 
 void
@@ -660,13 +918,13 @@
     }
 
     /* find the last node in print_list */
-    while (list->pl_next != NULL) {
-        list = list->pl_next;
+    while (list->MR_pl_next != NULL) {
+        list = list->MR_pl_next;
     }
 
     /* add the existing spy_print_list at the end of print_list */
-    list->pl_next = MR_spy_points[point_slot]->spy_print_list;
-    MR_spy_points[point_slot]->spy_print_list = print_list;
+    list->MR_pl_next = MR_spy_points[point_slot]->MR_spy_print_list;
+    MR_spy_points[point_slot]->MR_spy_print_list = print_list;
 }
 
 void
@@ -674,33 +932,33 @@
 {
     MR_SpyPrintList list;
 
-    list = MR_spy_points[point_slot]->spy_print_list;
+    list = MR_spy_points[point_slot]->MR_spy_print_list;
     if (list == NULL) {
-        MR_spy_points[point_slot]->spy_print_list = print_list;
+        MR_spy_points[point_slot]->MR_spy_print_list = print_list;
         return;
     }
 
     /* find the last node in print_list */
-    while (list->pl_next != NULL) {
-        list = list->pl_next;
+    while (list->MR_pl_next != NULL) {
+        list = list->MR_pl_next;
     }
 
     /* add the print_list at the end of the existing spy_print_list */
-    list->pl_next = print_list;
+    list->MR_pl_next = print_list;
 }
 
 void
 MR_clear_spy_point_print_list(int point_slot)
 {
-    MR_delete_spy_print_list(MR_spy_points[point_slot]->spy_print_list);
-    MR_spy_points[point_slot]->spy_print_list = NULL;
+    MR_delete_spy_print_list(MR_spy_points[point_slot]->MR_spy_print_list);
+    MR_spy_points[point_slot]->MR_spy_print_list = NULL;
 }
 
 const char *
 MR_ignore_spy_point(int point_slot, MR_SpyIgnore_When ignore_when,
     int ignore_count)
 {
-    switch (MR_spy_points[point_slot]->spy_when) {
+    switch (MR_spy_points[point_slot]->MR_spy_when) {
         case MR_SPY_ENTRY:
         case MR_SPY_INTERFACE:
         case MR_SPY_ALL:
@@ -716,8 +974,8 @@
             break;
     }
 
-    MR_spy_points[point_slot]->spy_ignore_when  = ignore_when;
-    MR_spy_points[point_slot]->spy_ignore_count = ignore_count;
+    MR_spy_points[point_slot]->MR_spy_ignore_when  = ignore_when;
+    MR_spy_points[point_slot]->MR_spy_ignore_count = ignore_count;
     return NULL;
 }
 
@@ -728,13 +986,13 @@
         return;
     }
 
-    MR_delete_spy_print_list(print_list->pl_next);
+    MR_delete_spy_print_list(print_list->MR_pl_next);
 
-    if (print_list->pl_cur->p_name != NULL) {
-        MR_free(print_list->pl_cur->p_name);
+    if (print_list->MR_pl_cur->MR_p_word_copy != NULL) {
+        MR_free(print_list->MR_pl_cur->MR_p_word_copy);
     }
 
-    MR_free(print_list->pl_cur);
+    MR_free(print_list->MR_pl_cur);
     MR_free(print_list);
 }
 
@@ -754,29 +1012,29 @@
         MR_most_recent_spy_point = -1;
     }
 
-    if (! MR_spy_points[point_table_slot]->spy_exists) {
+    if (! MR_spy_points[point_table_slot]->MR_spy_exists) {
         return;
     }
 
-    MR_spy_points[point_table_slot]->spy_exists = MR_FALSE;
+    MR_spy_points[point_table_slot]->MR_spy_exists = MR_FALSE;
 
-    MR_delete_spy_print_list(point->spy_print_list);
+    MR_delete_spy_print_list(point->MR_spy_print_list);
     /* in case it gets deleted again */
-    point->spy_print_list = NULL;
+    point->MR_spy_print_list = NULL;
 
-    if (point->spy_cond != NULL) {
-        MR_delete_cterm(point->spy_cond->cond_term);
-        MR_free(point->spy_cond->cond_what_string);
-        MR_free(point->spy_cond->cond_term_string);
-        MR_free(point->spy_cond);
+    if (point->MR_spy_cond != NULL) {
+        MR_delete_cterm(point->MR_spy_cond->MR_cond_term);
+        MR_free(point->MR_spy_cond->MR_cond_what_string);
+        MR_free(point->MR_spy_cond->MR_cond_term_string);
+        MR_free(point->MR_spy_cond);
 
         /* in case it gets deleted again */
-        point->spy_cond = NULL;
+        point->MR_spy_cond = NULL;
     }
 
-    if (point->spy_when == MR_SPY_LINENO) {
+    if (point->MR_spy_when == MR_SPY_LINENO) {
         /* Release the storage acquired by MR_copy_string. */
-        MR_free(point->spy_filename);
+        MR_free(point->MR_spy_filename);
 
         /*
         ** Remove the spy point from the spied label table list.
@@ -784,11 +1042,11 @@
 
         label_slot = 0;
         for (i = 0; i < MR_spied_label_next; i++) {
-            if (MR_spied_labels[i].spy_point_num != point_table_slot) {
-                MR_spied_labels[label_slot].spy_label =
-                    MR_spied_labels[i].spy_label;
-                MR_spied_labels[label_slot].spy_point_num =
-                    MR_spied_labels[i].spy_point_num;
+            if (MR_spied_labels[i].MR_sl_point_num != point_table_slot) {
+                MR_spied_labels[label_slot].MR_sl_label =
+                    MR_spied_labels[i].MR_sl_label;
+                MR_spied_labels[label_slot].MR_sl_point_num =
+                    MR_spied_labels[i].MR_sl_point_num;
                 label_slot++;
             }
         }
@@ -800,23 +1058,23 @@
         ** for its proc.
         */
 
-        proc_table_slot = MR_search_spy_table_for_proc(point->spy_proc);
+        proc_table_slot = MR_search_spy_table_for_proc(point->MR_spy_proc);
         if (proc_table_slot < 0) {
             MR_fatal_error("deleted spy point was not indexed by proc addr");
         }
 
-        cur_addr = &MR_spied_procs[proc_table_slot].spy_points;
-        cur = MR_spied_procs[proc_table_slot].spy_points;
+        cur_addr = &MR_spied_procs[proc_table_slot].MR_sp_points;
+        cur = MR_spied_procs[proc_table_slot].MR_sp_points;
         while (cur != NULL && cur != point) {
-            cur_addr = &cur->spy_next;
-            cur = cur->spy_next;
+            cur_addr = &cur->MR_spy_next;
+            cur = cur->MR_spy_next;
         }
 
         if (cur == NULL) {
             MR_fatal_error("deleted spy point was not on proc index list");
         }
 
-        *cur_addr = point->spy_next;
+        *cur_addr = point->MR_spy_next;
     }
 }
 
@@ -829,38 +1087,67 @@
     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", point->spy_filename, point->spy_linenumber);
+        point->MR_spy_exists ?
+            (point->MR_spy_enabled ? "+" : "-") :
+            (point->MR_spy_enabled ? "E" : "D"),
+        MR_spy_action_string(point->MR_spy_action),
+        MR_spy_when_names[point->MR_spy_when]);
+
+    switch (point->MR_spy_when) {
+        case MR_SPY_ALL:
+        case MR_SPY_INTERFACE:
+        case MR_SPY_ENTRY:
+        case MR_SPY_SPECIFIC:
+            MR_print_proc_id(fp, point->MR_spy_proc);
+            break;
+
+        case MR_SPY_LINENO:
+            fprintf(fp, "%s:%d",
+                point->MR_spy_filename, point->MR_spy_linenumber);
+            break;
+
+        case MR_SPY_USER_EVENT:
+            /* MR_spy_when_names has already printed "user_event". */
+            if (point->MR_spy_user_event_set != NULL) {
+                fprintf(fp, "%s %s",
+                    point->MR_spy_user_event_set,
+                    point->MR_spy_user_event_name);
     } else {
-        MR_print_proc_id(fp, point->spy_proc);
+                fprintf(fp, "%s",
+                    point->MR_spy_user_event_name);
     }
+            break;
 
-    if (point->spy_ignore_count > 1) {
+        case MR_SPY_USER_EVENT_SET:
+            /* MR_spy_when_names has already printed "user_event_set". */
+            if (point->MR_spy_user_event_set != NULL) {
+                fprintf(fp, "%s",
+                    point->MR_spy_user_event_set);
+            }
+            break;
+    }
+
+    if (point->MR_spy_ignore_count > 1) {
         fprintf(fp, "\n%12s(ignore next %d %s events)\n",
-            "", point->spy_ignore_count,
-            MR_ignore_when_to_string(point->spy_ignore_when));
-    } else if (point->spy_ignore_count > 0) {
+            "", point->MR_spy_ignore_count,
+            MR_ignore_when_to_string(point->MR_spy_ignore_when));
+    } else if (point->MR_spy_ignore_count > 0) {
         fprintf(fp, "\n%12s(ignore next %s event)\n",
-            "", MR_ignore_when_to_string(point->spy_ignore_when));
+            "", MR_ignore_when_to_string(point->MR_spy_ignore_when));
     } else {
         fprintf(fp, "\n");
     }
 
-    if (point->spy_cond != NULL) {
-        cond = point->spy_cond;
+    if (point->MR_spy_cond != NULL) {
+        cond = point->MR_spy_cond;
 
         fprintf(fp, "%12s", "");
 
-        if (! cond->cond_require_var) {
+        if (! cond->MR_cond_require_var) {
             fprintf(fp, "-v ");
         }
 
-        if (! cond->cond_require_path) {
+        if (! cond->MR_cond_require_path) {
             fprintf(fp, "-p ");
         }
 
@@ -868,34 +1155,19 @@
         fprintf(fp, "\n");
     }
 
-    if (verbose && point->spy_print_list != NULL) {
+    if (verbose && point->MR_spy_print_list != NULL) {
         MR_SpyPrintList list;
         MR_SpyPrint     node;
 
         fprintf(fp, "%12s", "");
-        for (list = point->spy_print_list; list != NULL; list = list->pl_next)
+        for (list = point->MR_spy_print_list; list != NULL;
+            list = list->MR_pl_next)
         {
-            node = list->pl_cur;
-            switch (node->p_what) {
-                case MR_SPY_PRINT_GOAL:
-                    fprintf(fp, "goal");
-                    break;
-
-                case MR_SPY_PRINT_ALL:
-                    fprintf(fp, "all");
-                    break;
-
-                case MR_SPY_PRINT_ONE:
-                    fprintf(fp, "%s", node->p_name);
-                    break;
-
-                default:
-                    MR_fatal_error("invalid node->p_name");
-                    break;
-            }
+            node = list->MR_pl_cur;
+            MR_print_spy_print_what(fp, node);
 
             fprintf(fp, " (");
-            switch (node->p_format) {
+            switch (node->MR_p_format) {
                 case MR_BROWSE_FORMAT_FLAT:
                     fprintf(fp, "flat");
                     break;
@@ -917,17 +1189,17 @@
                     break;
 
                 default:
-                    MR_fatal_error("invalid node->p_format");
+                    MR_fatal_error("invalid node->MR_p_format");
                     break;
             }
 
-            if (! node->p_warn) {
+            if (! node->MR_p_warn) {
                 fprintf(fp, ", nowarn");
             }
 
             fprintf(fp, ")");
 
-            if (list->pl_next == NULL) {
+            if (list->MR_pl_next == NULL) {
                 fprintf(fp, "\n");
             } else {
                 fprintf(fp, ", ");
@@ -939,25 +1211,29 @@
 void
 MR_print_spy_cond(FILE *fp, MR_SpyCond *cond)
 {
-    switch (cond->cond_var_spec.MR_var_spec_kind) {
+    switch (cond->MR_cond_var_spec.MR_var_spec_kind) {
         case MR_VAR_SPEC_NUMBER:
-            fprintf(fp, "%d", cond->cond_var_spec.MR_var_spec_number);
+            fprintf(fp, "%d", cond->MR_cond_var_spec.MR_var_spec_number);
             break;
 
         case MR_VAR_SPEC_NAME:
-            fprintf(fp, "%s", cond->cond_var_spec.MR_var_spec_name);
+            fprintf(fp, "%s", cond->MR_cond_var_spec.MR_var_spec_name);
             break;
 
-        default:
-            MR_fatal_error("MR_print_spy_point: invalid cond_what");
+        case MR_VAR_SPEC_HELD_NAME:
+            fprintf(fp, "$%s", cond->MR_cond_var_spec.MR_var_spec_name);
+            break;
+
+        case MR_VAR_SPEC_ATTRIBUTE:
+            fprintf(fp, "!%s", cond->MR_cond_var_spec.MR_var_spec_name);
             break;
     }
 
-    if (cond->cond_path != NULL) {
-        fprintf(fp, " ^%s", cond->cond_path);
+    if (cond->MR_cond_path != NULL) {
+        fprintf(fp, " ^%s", cond->MR_cond_path);
     }
 
-    switch (cond->cond_test) {
+    switch (cond->MR_cond_test) {
         case MR_SPY_TEST_EQUAL:
             fprintf(fp, " = ");
             break;
@@ -971,7 +1247,7 @@
             break;
     }
 
-    MR_print_cterm(fp, cond->cond_term);
+    MR_print_cterm(fp, cond->MR_cond_term);
 }
 
 static const char *
@@ -998,13 +1274,13 @@
 
     spy_point_num = 0;
     for (i = 0; i < MR_spy_point_next; i++) {
-        if (! MR_spy_points[i]->spy_exists) {
+        if (! MR_spy_points[i]->MR_spy_exists) {
             continue;
         }
 
         point = MR_spy_points[i];
 
-        switch (point->spy_action) {
+        switch (point->MR_spy_action) {
             case MR_SPY_STOP:
                 fprintf(fp, "break ");
                 break;
@@ -1018,14 +1294,14 @@
                 return MR_TRUE;
         }
 
-        if (point->spy_ignore_count > 0) {
-            switch (point->spy_ignore_when) {
+        if (point->MR_spy_ignore_count > 0) {
+            switch (point->MR_spy_ignore_when) {
                 case MR_SPY_IGNORE_INTERFACE:
-                    fprintf(fp, " -I%d", point->spy_ignore_count);
+                    fprintf(fp, " -I%d", point->MR_spy_ignore_count);
                     break;
 
                 case MR_SPY_IGNORE_ENTRY:
-                    fprintf(fp, " -E%d", point->spy_ignore_count);
+                    fprintf(fp, " -E%d", point->MR_spy_ignore_count);
                     break;
 
                 default:
@@ -1033,26 +1309,26 @@
             }
         }
 
-        switch (point->spy_when) {
+        switch (point->MR_spy_when) {
             case MR_SPY_LINENO:
-                fprintf(fp, "%s:%d\n", point->spy_filename,
-                    point->spy_linenumber);
+                fprintf(fp, "%s:%d\n",
+                    point->MR_spy_filename, point->MR_spy_linenumber);
                 break;
 
             case MR_SPY_ALL:
                 fprintf(fp, "-a ");
-                MR_print_proc_spec(fp, point->spy_proc);
+                MR_print_proc_spec(fp, point->MR_spy_proc);
                 fprintf(fp, "\n");
                 break;
 
             case MR_SPY_INTERFACE:
-                MR_print_proc_spec(fp, point->spy_proc);
+                MR_print_proc_spec(fp, point->MR_spy_proc);
                 fprintf(fp, "\n");
                 break;
 
             case MR_SPY_ENTRY:
                 fprintf(fp, "-e ");
-                MR_print_proc_spec(fp, point->spy_proc);
+                MR_print_proc_spec(fp, point->MR_spy_proc);
                 fprintf(fp, "\n");
                 break;
 
@@ -1066,21 +1342,21 @@
                 return MR_TRUE;
         }
 
-        if (point->spy_cond != NULL) {
+        if (point->MR_spy_cond != NULL) {
             MR_SpyCond *cond;
 
-            cond = point->spy_cond;
+            cond = point->MR_spy_cond;
             fprintf(fp, "condition ");
 
-            if (!cond->cond_require_var) {
+            if (!cond->MR_cond_require_var) {
                 fprintf(fp, "-v "); /* also implies -p */
-            } else if (!cond->cond_require_path) {
+            } else if (!cond->MR_cond_require_path) {
                 fprintf(fp, "-p ");
             }
 
-            fprintf(fp, "%s ", cond->cond_what_string);
+            fprintf(fp, "%s ", cond->MR_cond_what_string);
 
-            switch (cond->cond_test) {
+            switch (cond->MR_cond_test) {
                 case MR_SPY_TEST_EQUAL:
                     fprintf(fp, "= ");
                     break;
@@ -1094,27 +1370,27 @@
                     break;
             }
 
-            fprintf(fp, "%s\n", cond->cond_term_string);
+            fprintf(fp, "%s\n", cond->MR_cond_term_string);
         }
 
-        if (!point->spy_enabled) {
+        if (!point->MR_spy_enabled) {
             fprintf(fp, "disable\n");
         }
 
-        if (point->spy_print_list != NULL) {
+        if (point->MR_spy_print_list != NULL) {
             MR_SpyPrintList   list;
             MR_SpyPrint        node;
 
-            list = point->spy_print_list;
-            for (; list != NULL; list = list->pl_next) {
-                node = list->pl_cur;
+            list = point->MR_spy_print_list;
+            for (; list != NULL; list = list->MR_pl_next) {
+                node = list->MR_pl_cur;
 
                 fprintf(fp, "break_print -e");
-                if (! node->p_warn) {
+                if (! node->MR_p_warn) {
                     fprintf(fp, " -n");
                 }
 
-                switch (node->p_format) {
+                switch (node->MR_p_format) {
                     case MR_BROWSE_FORMAT_FLAT:
                         fprintf(fp, " -f");
                         break;
@@ -1136,34 +1412,39 @@
                         break;
 
                     default:
-                        MR_fatal_error("invalid node->p_format");
+                        MR_fatal_error("invalid node->MR_p_format");
                         break;
                 }
 
-                switch (node->p_what) {
+                fprintf(fp, " ");
+                MR_print_spy_print_what(fp, node);
+                fprintf(fp, "\n");
+            }
+        }
+
+        spy_point_num++;
+    }
+
+    return MR_FALSE;
+}
+
+static void
+MR_print_spy_print_what(FILE *fp, MR_SpyPrint sp)
+{
+    switch (sp->MR_p_what) {
                     case MR_SPY_PRINT_GOAL:
-                        fprintf(fp, " goal");
+            fprintf(fp, "goal");
                         break;
 
                     case MR_SPY_PRINT_ALL:
-                        fprintf(fp, " all");
+            fprintf(fp, "all");
                         break;
 
                     case MR_SPY_PRINT_ONE:
-                        fprintf(fp, " %s", node->p_name);
-                        break;
-
-                    default:
-                        MR_fatal_error("invalid node->p_name");
-                        break;
-                }
-
-                fprintf(fp, "\n");
-            }
+            MR_print_var_spec(fp, &sp->MR_p_var_spec);
+            if (sp->MR_p_path != NULL) {
+                fprintf(fp, "^%s", sp->MR_p_path);
         }
-
-        spy_point_num++;
+            break;
     }
-
-    return MR_FALSE;
 }
Index: trace/mercury_trace_spy.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_spy.h,v
retrieving revision 1.13
diff -u -b -r1.13 mercury_trace_spy.h
--- trace/mercury_trace_spy.h	29 Nov 2006 05:18:41 -0000	1.13
+++ trace/mercury_trace_spy.h	18 Jan 2007 07:10:56 -0000
@@ -36,13 +36,16 @@
     MR_SPY_INTERFACE,
     MR_SPY_ENTRY,
     MR_SPY_SPECIFIC,
-    MR_SPY_LINENO
+    MR_SPY_LINENO,
+    MR_SPY_USER_EVENT,
+    MR_SPY_USER_EVENT_SET
 } MR_SpyWhen;
 
 typedef enum {
     MR_SPY_DONT_IGNORE,
     MR_SPY_IGNORE_INTERFACE,
-    MR_SPY_IGNORE_ENTRY
+    MR_SPY_IGNORE_ENTRY,
+    MR_SPY_IGNORE_ALL
 } MR_SpyIgnore_When;
 
 extern  const char                      *MR_spy_when_names[];
@@ -61,44 +64,48 @@
 } MR_SpyPrintWhat;
 
 struct MR_SpyPrint_Struct {
-    MR_BrowseFormat p_format;
-    MR_SpyPrintWhat p_what;
-    char            *p_name;    /* if MR_SPY_PRINT_ONE */
-    MR_bool         p_warn;
+    MR_BrowseFormat MR_p_format;
+    MR_SpyPrintWhat MR_p_what;
+    char            *MR_p_word_copy;
+    MR_VarSpec      MR_p_var_spec;  /* if MR_SPY_PRINT_ONE */
+    char            *MR_p_path;     /* if MR_SPY_PRINT_ONE */
+    MR_bool         MR_p_warn;
 };
 
 struct MR_SpyPrintList_Struct {
-    MR_SpyPrint     pl_cur;
-    MR_SpyPrintList pl_next;
+    MR_SpyPrint     MR_pl_cur;
+    MR_SpyPrintList MR_pl_next;
 };
 
 typedef struct MR_SpyPoint_Struct MR_SpyPoint;
 
 typedef struct {
-    MR_VarSpec      cond_var_spec;
-    char            *cond_path;
-    MR_SpyTest      cond_test;
-    MR_CTerm        cond_term;
-    MR_bool         cond_require_var;
-    MR_bool         cond_require_path;
-    char            *cond_what_string;
-    char            *cond_term_string;
+    MR_VarSpec      MR_cond_var_spec;
+    char            *MR_cond_path;
+    MR_SpyTest      MR_cond_test;
+    MR_CTerm        MR_cond_term;
+    MR_bool         MR_cond_require_var;
+    MR_bool         MR_cond_require_path;
+    char            *MR_cond_what_string;
+    char            *MR_cond_term_string;
 } MR_SpyCond;
 
 struct MR_SpyPoint_Struct {
-    MR_bool                 spy_exists;     /* MR_FALSE if deleted */
-    MR_bool                 spy_enabled;
-    MR_SpyWhen              spy_when;
-    MR_SpyAction            spy_action;
-    MR_SpyIgnore_When       spy_ignore_when;
-    int                     spy_ignore_count;
-    MR_SpyCond              *spy_cond;
-    MR_SpyPrintList         spy_print_list;
-    const MR_ProcLayout     *spy_proc;      /* if not LINENO */
-    const MR_LabelLayout    *spy_label;     /* if SPECIFIC */
-    char                    *spy_filename;  /* if LINENO */
-    int                     spy_linenumber; /* if LINENO */
-    MR_SpyPoint             *spy_next;      /* if not LINENO */
+    MR_bool                 MR_spy_exists;          /* MR_FALSE if deleted */
+    MR_bool                 MR_spy_enabled;
+    MR_SpyWhen              MR_spy_when;
+    MR_SpyAction            MR_spy_action;
+    MR_SpyIgnore_When       MR_spy_ignore_when;
+    int                     MR_spy_ignore_count;
+    MR_SpyCond              *MR_spy_cond;
+    MR_SpyPrintList         MR_spy_print_list;
+    const MR_ProcLayout     *MR_spy_proc;           /* if not LINENO */
+    const MR_LabelLayout    *MR_spy_label;          /* if SPECIFIC */
+    char                    *MR_spy_filename;       /* if LINENO */
+    int                     MR_spy_linenumber;      /* if LINENO */
+    const char              *MR_spy_user_event_set; /* if USER_EVENT or SET */
+    const char              *MR_spy_user_event_name;/* if USER_EVENT */
+    MR_SpyPoint             *MR_spy_next;           /* if not LINENO */
 };
 
 /*
@@ -128,9 +135,9 @@
                             MR_SpyPrintList *print_list);
 
 /*
-** Add a new spy point on a procedure (as opposed to on a line number)
-** to the table. If this cannot be done, return a negative number and set
-** *problem to point to an error message.
+** Add a new spy point on a procedure (as opposed to on a line number or
+** user event) to the table. If this cannot be done, return a negative number
+** and set *problem to point to an error message.
 */
 
 extern  int         MR_add_proc_spy_point(MR_SpyWhen when,
@@ -140,9 +147,9 @@
                         MR_SpyPrintList print_list, const char **problem);
 
 /*
-** Add a new spy point on a line number (as opposed to on a procedure)
-** to the table. If this cannot be done, return a negative number and set
-** *problem to point to an error message.
+** Add a new spy point on a line number (as opposed to on a procedure or user
+** event) to the table. If this cannot be done, return a negative number
+** and set *problem to point to an error message.
 */
 
 extern  int         MR_add_line_spy_point(MR_SpyAction action,
@@ -151,6 +158,18 @@
                         MR_SpyPrintList print_list, const char **problem);
 
 /*
+** Add a new spy point on a user event (as opposed to on a procedure or
+** line number) to the table. If this cannot be done, return a negative number
+** and set *problem to point to an error message.
+*/
+
+extern  int             MR_add_user_event_spy_point(MR_SpyAction action,
+                            MR_SpyIgnore_When ignore_when, int ignore_count,
+                            const char *user_event_set,
+                            const char *user_event_name,
+                            MR_SpyPrintList print_list, const char **problem);
+
+/*
 ** Add the given set of things to be printed to the spy point's list,
 ** at either the start or the end of the existing list.
 */
Index: trace/mercury_trace_tables.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_tables.c,v
retrieving revision 1.48
diff -u -b -r1.48 mercury_trace_tables.c
--- trace/mercury_trace_tables.c	10 Jan 2007 07:55:49 -0000	1.48
+++ trace/mercury_trace_tables.c	11 Jan 2007 16:54:35 -0000
@@ -173,7 +173,6 @@
     if (MR_search_module_info_by_name(module->MR_ml_name) == NULL) {
         MR_insert_module_info(module);
 
-        if (module->MR_ml_version_number >= MR_LAYOUT_VERSION__EVENTSETNAME) {
             if (module->MR_ml_user_event_set_desc != NULL) {
                 int                 i;
                 MR_bool             found;
@@ -182,6 +181,7 @@
                 
                 event_set_name = module->MR_ml_user_event_set_name;
 
+            found = MR_FALSE;
                 for (i = 0; i < MR_trace_event_set_next; i++) {
                     if (MR_streq(MR_trace_event_sets[i].MR_tes_name,
                         event_set_name))
@@ -191,6 +191,11 @@
                             module->MR_ml_user_event_set_desc))
                         {
                             trace_event_set->MR_tes_is_consistent = MR_FALSE;
+                        fprintf(MR_mdb_out,
+                            "The executable's modules were compiled with "
+                            "inconsistent definitions of "
+                            "user event set `%s'.\n",
+                            event_set_name);
                         }
 
                         found = MR_TRUE;
@@ -203,13 +208,26 @@
                         MR_TraceEventSet, MR_INIT_EVENT_SET_TABLE_SIZE);
                     trace_event_set =
                         &MR_trace_event_sets[MR_trace_event_set_next];
+                MR_trace_event_set_next++;
+
                     trace_event_set->MR_tes_name = event_set_name;
                     trace_event_set->MR_tes_desc =
                             module->MR_ml_user_event_set_desc;
                     trace_event_set->MR_tes_is_consistent = MR_TRUE;
+                trace_event_set->MR_tes_num_specs =
+                    module->MR_ml_num_user_event_specs;
                     trace_event_set->MR_tes_specs =
                             module->MR_ml_user_event_specs;
-                    MR_trace_event_set_next++;
+                trace_event_set->MR_tes_event_set = 
+                    MR_read_event_set("no input file",
+                        trace_event_set->MR_tes_desc);
+
+                if (trace_event_set->MR_tes_event_set == NULL) {
+                    fprintf(MR_mdb_out,
+                        "Internal error: could not parse "
+                        "the specification of event set `%s'.\n",
+                        event_set_name);
+                }
 
                     if (MR_trace_event_sets_max_num_attr <
                         module->MR_ml_user_event_max_num_attr)
@@ -221,7 +239,6 @@
                 }
             }
         }
-    }
 }
 
 static const MR_ModuleLayout *
Index: trace/mercury_trace_tables.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_tables.h,v
retrieving revision 1.28
diff -u -b -r1.28 mercury_trace_tables.h
--- trace/mercury_trace_tables.h	14 Dec 2006 04:36:04 -0000	1.28
+++ trace/mercury_trace_tables.h	11 Jan 2007 15:02:30 -0000
@@ -67,7 +67,7 @@
     MR_bool                 MR_tes_is_consistent;
     MR_EventSet             MR_tes_event_set;
     int                     MR_tes_num_specs;
-    MR_UserEventSpec        *MR_tes_specs;
+    const MR_UserEventSpec  *MR_tes_specs;
 } MR_TraceEventSet;
 
 extern  MR_TraceEventSet    *MR_trace_event_sets;
Index: trace/mercury_trace_vars.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_vars.c,v
retrieving revision 1.76
diff -u -b -r1.76 mercury_trace_vars.c
--- trace/mercury_trace_vars.c	11 Jan 2007 03:41:51 -0000	1.76
+++ trace/mercury_trace_vars.c	18 Jan 2007 10:59:58 -0000
@@ -184,11 +184,6 @@
                             const MR_ProgVarDetails *var2);
 static  int             MR_compare_slots_on_headvar_num(const void *p1,
                             const void *p2);
-static  const char      *MR_trace_browse_one_path(FILE *out,
-                            MR_bool print_var_name, MR_VarSpec var_spec,
-                            char *path, MR_Browser browser,
-                            MR_BrowseCallerType caller,
-                            MR_BrowseFormat format, MR_bool must_be_unique);
 static  char            *MR_trace_browse_var(FILE *out, MR_bool print_var_name,
                             MR_TypeInfo type_info, MR_Word value,
                             const char *name, char *path,
@@ -1123,6 +1118,28 @@
     }
 }
 
+void
+MR_print_var_spec(FILE *fp, MR_VarSpec *var_spec)
+{
+    switch (var_spec->MR_var_spec_kind) {
+        case MR_VAR_SPEC_NUMBER:
+            fprintf(fp, "%d", var_spec->MR_var_spec_number);
+            break;
+
+        case MR_VAR_SPEC_NAME:
+            fprintf(fp, "%s", var_spec->MR_var_spec_name);
+            break;
+
+        case MR_VAR_SPEC_HELD_NAME:
+            fprintf(fp, "$%s", var_spec->MR_var_spec_name);
+            break;
+
+        case MR_VAR_SPEC_ATTRIBUTE:
+            fprintf(fp, "!%s", var_spec->MR_var_spec_name);
+            break;
+    }
+}
+
 static int
 MR_compare_slots_on_headvar_num(const void *p1, const void *p2)
 {
@@ -1408,7 +1425,7 @@
     return NULL;
 }
 
-static const char *
+const char *
 MR_trace_browse_one_path(FILE *out, MR_bool print_var_name,
     MR_VarSpec var_spec, char *path, MR_Browser browser,
     MR_BrowseCallerType caller, MR_BrowseFormat format,
@@ -1432,7 +1449,7 @@
         bad_path = MR_trace_browse_var(out, print_var_name, type_info, value,
             name, path, browser, caller, format);
         if (bad_path != NULL) {
-            return MR_trace_bad_path(bad_path);
+            return MR_trace_bad_path_in_var(&var_spec, bad_path);
         }
     } else {
         int success_count;
@@ -1540,22 +1557,89 @@
 #define BAD_PATH_MSG_PREFIX     "the path "
 #define BAD_PATH_MSG_SUFFIX     " does not exist"
 
+static  char    MR_trace_bad_path_buffer[BAD_PATH_BUFFER_SIZE];
+
 const char *
 MR_trace_bad_path(const char *path)
 {
-    static  char    buffer[BAD_PATH_BUFFER_SIZE];
-
     if (strlen(BAD_PATH_MSG_PREFIX) + strlen(path) +
         strlen(BAD_PATH_MSG_SUFFIX) < BAD_PATH_BUFFER_SIZE)
     {
-        sprintf(buffer, "%s%s%s", BAD_PATH_MSG_PREFIX, path,
+        sprintf(MR_trace_bad_path_buffer, "%s%s%s", BAD_PATH_MSG_PREFIX, path,
             BAD_PATH_MSG_SUFFIX);
-        return buffer;
+        return MR_trace_bad_path_buffer;
     } else {
         return "the given path does not exist";
     }
 }
 
+#define BAD_VAR_PATH_BUFFER_SIZE    128
+#define BAD_VAR_PATH_MSG_MIDDLE     " in variable "
+
+static char MR_trace_bad_path_in_var_buffer[BAD_VAR_PATH_BUFFER_SIZE];
+
+const char *
+MR_trace_bad_path_in_var(MR_VarSpec *var_spec, const char *path)
+{
+    const char  *path_msg;
+    int         suffix_len;
+
+    path_msg = MR_trace_bad_path(path);
+    suffix_len = 0;
+    switch (var_spec->MR_var_spec_kind) {
+        case MR_VAR_SPEC_NUMBER:
+            /* This should be ample. */
+            suffix_len = 20;
+            break;
+
+        case MR_VAR_SPEC_NAME:
+            suffix_len = strlen(var_spec->MR_var_spec_name);
+            break;
+
+        case MR_VAR_SPEC_HELD_NAME:
+            suffix_len = strlen(var_spec->MR_var_spec_name) + 1;
+            break;
+
+        case MR_VAR_SPEC_ATTRIBUTE:
+            suffix_len = strlen(var_spec->MR_var_spec_name) + 1;
+            break;
+    }
+
+    if (strlen(path_msg) + strlen(BAD_VAR_PATH_MSG_MIDDLE) + suffix_len
+        < BAD_PATH_BUFFER_SIZE)
+    {
+        switch (var_spec->MR_var_spec_kind) {
+            case MR_VAR_SPEC_NUMBER:
+                sprintf(MR_trace_bad_path_in_var_buffer, "%s%s%d",
+                    path_msg, BAD_VAR_PATH_MSG_MIDDLE,
+                    var_spec->MR_var_spec_number);
+                break;
+
+            case MR_VAR_SPEC_NAME:
+                sprintf(MR_trace_bad_path_in_var_buffer, "%s%s%s",
+                    path_msg, BAD_VAR_PATH_MSG_MIDDLE,
+                    var_spec->MR_var_spec_name);
+                break;
+
+            case MR_VAR_SPEC_HELD_NAME:
+                sprintf(MR_trace_bad_path_in_var_buffer, "%s%s$%s",
+                    path_msg, BAD_VAR_PATH_MSG_MIDDLE,
+                    var_spec->MR_var_spec_name);
+                break;
+
+            case MR_VAR_SPEC_ATTRIBUTE:
+                sprintf(MR_trace_bad_path_in_var_buffer, "%s%s!%s",
+                    path_msg, BAD_VAR_PATH_MSG_MIDDLE,
+                    var_spec->MR_var_spec_name);
+                break;
+        }
+
+        return MR_trace_bad_path_in_var_buffer;
+    } else {
+        return path_msg;
+    }
+}
+
 const char *
 MR_trace_browse_all(FILE *out, MR_Browser browser, MR_BrowseFormat format)
 {
@@ -1741,6 +1825,21 @@
         fprintf(out, "%7s", "");
         fprintf(out, "%s", name);
         len = strlen(name);
+
+        if (path != NULL) {
+            char    sep;
+
+            /* Try to conform to the separator used in the path. */
+            if (strchr(path, '/') != NULL && strchr(path, '^') == NULL) {
+                sep = '/';
+            } else {
+                sep = '^';
+            }
+
+            fprintf(out, "%c%s", sep, path);
+            len += 1 + strlen(path);
+        }
+
         while (len < MR_TRACE_PADDED_VAR_NAME_LENGTH) {
             fputc(' ', out);
             len++;
Index: trace/mercury_trace_vars.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_vars.h,v
retrieving revision 1.32
diff -u -b -r1.32 mercury_trace_vars.h
--- trace/mercury_trace_vars.h	29 Nov 2006 05:18:42 -0000	1.32
+++ trace/mercury_trace_vars.h	18 Jan 2007 08:34:33 -0000
@@ -89,6 +89,12 @@
                         MR_VarSpec *var_spec);
 
 /*
+** Print the given MR_VarSpec.
+*/
+
+extern  void        MR_print_var_spec(FILE *fp, MR_VarSpec *var_spec);
+
+/*
 ** These functions are documented near the top of this file.
 */
 
@@ -241,6 +247,13 @@
                         MR_BrowseCallerType caller, MR_BrowseFormat format,
                         MR_bool must_be_unique);
 
+
+extern  const char  *MR_trace_browse_one_path(FILE *out,
+                        MR_bool print_var_name, MR_VarSpec var_spec,
+                        char *path, MR_Browser browser,
+                        MR_BrowseCallerType caller, MR_BrowseFormat format,
+                        MR_bool must_be_unique);
+
 /*
 ** Print the list of the names and values of all variables live at the current
 ** point. The variables names are printed directly to the given file, but
@@ -293,11 +306,25 @@
 
 /*
 ** Given an invalid path specification, return an error message for that error.
+**
+** The returned string is valid only until the next call to MR_trace_bad_path
+** or MR_trace_bad_path_in_var.
 */
 
 extern  const char  *MR_trace_bad_path(const char *path);
 
 /*
+** Given a path specification that does not exist within the specified
+** variable, return an error message for that error.
+**
+** The returned string is valid only until the next call to MR_trace_bad_path
+** or MR_trace_bad_path_in_var.
+*/
+
+extern  const char  *MR_trace_bad_path_in_var(MR_VarSpec *var_spec,
+                        const char *path);
+
+/*
 ** Print the size of the specified variable(s) to the specified file.
 ** Return a non-NULL error message if this is not possible.
 */
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list