mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-23 13:23:47 +00:00
Estimated hours taken: 32
Branches: main
Make the debugging of minimal model tabling easier by providing a mechanism
to print the contents of the nondet stack, *including* the values of the
variables in its stack frames, even for frames which are not ancestors
of the currently executing call.
runtime/mercury_stack_trace.[ch]:
Add functions for traversing the nondet stack, and for keeping track of
through which label control returns to each nondet stack frame, so that
we know which label's layout structure to interpret the stack frame's
contents. For some, this will be the return label of a call; for
others, it will be the label of a resumption point stored in a
redoip slot.
Rename an old function to allow the new one to fit into our naming
scheme.
runtime/mercury_stack_trace.[ch]:
runtime/mercury_tabling.c:
library/exception.m:
trace/mercury_trace.c:
Add MR_ prefixes to the values of the enum returned by
MR_stack_walk_step.
Rename references to the renamed function.
runtime/mercury_conf_param.h:
Add macros for debugging label names and for debugging retries (which
needs label names, just as debugging tabling does).
Add a macro for controlling whether mercury_debug.c prints raw
addresses as well as offsets (for stack pointers) or label names (for
labels). The raw pointers can be useful in debugging, but they need to
be turned off in test cases one wants to be reproducible.
runtime/mercury_label.h:
runtime/mercury_conf_param.h:
Move the MR_NEED_ENTRY_LABEL_ARRAY and MR_NEED_ENTRY_LABEL_INFO macros
from mercury_label.h to mercury_conf_param.h, since mercury_debug.c
also needs them now.
runtime/mercury_debug.c:
addresses as well as offsets (for stack pointers) or label names (for
labels). The raw pointers can be useful in debugging, but they need to
be turned off in test cases one wants to be reproducible.
runtime/mercury_init.h:
runtime/mercury_wrapper.[ch]:
util/mkinit.c:
Add a global variable pointing to a function through which the stack
walk code in runtime/mercury_stack_trace.c can invoke code from the
debugger to print the values of the variables in nondet stack frames
without breaking the rule prohibiting references to the trace directory
from the runtime directory.
runtime/mercury_wrapper.c:
Define the succip of the dummy frame at the bottom of the nondet stack,
to avoid dereferencing a garbage pointer during detailed stack dumps.
runtime/mercury_goto.h:
Add a mechanism for always registering the name of a specific label,
even if label names are not being registered in general. This mechanism
is intended to be used for labels such as do_fail, which occur
frequently in nondet stack traces.
runtime/mercury_context.c:
runtime/mercury_engine.c:
runtime/mercury_ho_call.c:
runtime/mercury_trace_base.c:
runtime/mercury_wrapper.c:
Use this mechanism for the labels defined in these modules.
library/builtin.m:
Define type_ctor_infos for the pseudotypes representing nondet stack
frame slots unconditionally, since the debugger may now need them.
trace/mercury_trace.c:
Add conditionally enabled to code to make debugging retry easier.
trace/mercury_trace_internal.c:
Add a -d option to the nondet_stack command that causes it to print
detailed nondet stack dumps, including the names and values of the
variables in each nondet stack frame.
trace/mercury_trace_vars.c:
Provide a mechanism for printing the variables of a stack frame
even when that stack frame is not an ancestor of the current call.
doc/user_guide.texi:
Document the new option of the nondet_stack command.
tests/debugger/nondet_stack.{m,inp,exp,exp2}:
A new test case to test "nondet_stack -d".
tests/debugger/Mmakefile:
Enable the new test case.
336 lines
11 KiB
Plaintext
336 lines
11 KiB
Plaintext
#-----------------------------------------------------------------------------#
|
|
|
|
main_target: check
|
|
|
|
include ../Mmake.common
|
|
-include ../Mmake.params
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
# We suppress the printing of the banner, because different workspaces
|
|
# may get different version numbers printed in it. This would otherwise be
|
|
# the source of irrelevant difference between the actual and expected outputs.
|
|
|
|
MDB = MERCURY_SUPPRESS_MDB_BANNER=yes mdb
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
RETRY_PROGS = \
|
|
all_solutions \
|
|
browser_test \
|
|
mdb_command_test \
|
|
queens \
|
|
retry \
|
|
tabled_read
|
|
|
|
NONRETRY_PROGS = \
|
|
breakpoints \
|
|
browse_pretty \
|
|
debugger_regs \
|
|
exception_cmd \
|
|
exception_value \
|
|
exception_vars \
|
|
existential_type_classes \
|
|
field_names \
|
|
implied_instance \
|
|
interpreter \
|
|
loopcheck \
|
|
multi_parameter \
|
|
nondet_stack \
|
|
output_term_dep \
|
|
polymorphic_output \
|
|
resume_typeinfos \
|
|
shallow
|
|
|
|
|
|
# The following tests are disabled, since currently they get some spurious
|
|
# failures if readline support is enabled:
|
|
# interactive
|
|
# Note that some of the make rules for interactive are disabled too.
|
|
|
|
MCFLAGS-shallow = --trace shallow
|
|
MCFLAGS-tabled_read = --trace-table-io
|
|
MCFLAGS = --trace deep
|
|
MLFLAGS = --trace
|
|
C2INITFLAGS = --trace
|
|
|
|
# We need to use shared libraries for interactive queries to work.
|
|
# The following is necessary for shared libraries to work on Linux.
|
|
GRADEFLAGS-interactive = --pic-reg
|
|
MLFLAGS-interactive = --shared
|
|
|
|
# Debugging doesn't yet don't work in MLDS grades (hl*), and the retry command
|
|
# doesn't and will not work in deep profiling grades (profdeep).
|
|
# Also base grades `jump' and `fast' cannot be used with
|
|
# stack layouts (which are required for tracing).
|
|
|
|
ifneq "$(findstring hl,$(GRADE))" ""
|
|
PROGS=
|
|
else
|
|
ifneq "$(findstring profdeep,$(GRADE))" ""
|
|
# Eventually, this should be DEBUGGER_PROGS=$(NONRETRY_PROGS).
|
|
# However, the code that is required to switch off the profiling
|
|
# primitives in Mercury code invoked by the debugger (e.g. for
|
|
# browsing) has not yet been implemented.
|
|
DEBUGGER_PROGS=
|
|
else
|
|
DEBUGGER_PROGS=$(NONRETRY_PROGS) $(RETRY_PROGS)
|
|
endif
|
|
ifneq "$(findstring asm_,$(GRADE))" ""
|
|
PROGS=$(DEBUGGER_PROGS)
|
|
else
|
|
ifneq "$(findstring jump,$(GRADE))" ""
|
|
PROGS=
|
|
else
|
|
ifneq "$(findstring fast,$(GRADE))" ""
|
|
PROGS=
|
|
else
|
|
PROGS=$(DEBUGGER_PROGS)
|
|
endif
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
all_solutions.out: all_solutions all_solutions.inp
|
|
$(MDB) ./all_solutions < all_solutions.inp > all_solutions.out 2>&1
|
|
|
|
breakpoints.out: breakpoints breakpoints.inp
|
|
$(MDB) ./breakpoints < breakpoints.inp > breakpoints.out 2>&1
|
|
|
|
# We need to pipe the output through sed to avoid hard-coding dependencies on
|
|
# particular line numbers in the standard library source code.
|
|
browse_pretty.out: browse_pretty browse_pretty.inp
|
|
$(MDB) ./browse_pretty < browse_pretty.inp 2>&1 | \
|
|
sed 's/io.m:[0-9]*/io.m:NNNN/g' > browse_pretty.out 2>&1
|
|
|
|
# We need to pipe the output through sed to avoid hard-coding dependencies on
|
|
# particular line numbers in the standard library source code.
|
|
browser_test.out: browser_test browser_test.inp
|
|
$(MDB) ./browser_test < browser_test.inp 2>&1 | \
|
|
sed 's/io.m:[0-9]*/io.m:NNNN/g' > browser_test.out 2>&1
|
|
|
|
debugger_regs.out: debugger_regs debugger_regs.inp
|
|
$(MDB) ./debugger_regs < debugger_regs.inp > debugger_regs.out 2>&1
|
|
|
|
# We need to pipe the output through sed to avoid hard-coding dependencies on
|
|
# particular line numbers in the standard library source code.
|
|
exception_value.out: exception_value exception_value.inp
|
|
$(MDB) ./exception_value < exception_value.inp 2>&1 | \
|
|
sed -e 's/exception.m:[0-9]*/exception.m:NNNN/g' | \
|
|
sed -e '/EXCP/s/).*/)/' > exception_value.out 2>&1
|
|
|
|
# The exception_cmd, exception_vars, polymorphic_output and loopcheck tests
|
|
# are supposed to return a non-zero exit status, since they exit by throwing
|
|
# an exception. We strip the goal paths from their exception events, since
|
|
# the exact goal paths are dependent on optimization level. The stripping
|
|
# must be done outside the condition of the if-then-else.
|
|
exception_cmd.out: exception_cmd exception_cmd.inp
|
|
if $(MDB) ./exception_cmd < exception_cmd.inp \
|
|
> exception_cmd.tmp 2>&1; \
|
|
then \
|
|
sed -e '/EXCP/s/).*/)/' < exception_cmd.tmp \
|
|
> exception_cmd.out 2>&1; \
|
|
rm exception_cmd.tmp; \
|
|
false; \
|
|
else \
|
|
sed -e '/EXCP/s/).*/)/' < exception_cmd.tmp \
|
|
> exception_cmd.out 2>&1; \
|
|
rm exception_cmd.tmp; \
|
|
true; \
|
|
fi
|
|
|
|
exception_vars.out: exception_vars exception_vars.inp
|
|
if $(MDB) ./exception_vars < exception_vars.inp \
|
|
> exception_vars.tmp 2>&1; \
|
|
then \
|
|
sed -e '/EXCP/s/).*/)/' < exception_vars.tmp \
|
|
> exception_vars.out 2>&1; \
|
|
rm exception_vars.tmp; \
|
|
false; \
|
|
else \
|
|
sed -e '/EXCP/s/).*/)/' < exception_vars.tmp \
|
|
> exception_vars.out 2>&1; \
|
|
rm exception_vars.tmp; \
|
|
true; \
|
|
fi
|
|
|
|
polymorphic_output.out: polymorphic_output polymorphic_output.inp
|
|
if $(MDB) ./polymorphic_output < polymorphic_output.inp \
|
|
> polymorphic_output.tmp 2>&1; \
|
|
then \
|
|
sed -e '/EXCP/s/).*/)/' < polymorphic_output.tmp\
|
|
> polymorphic_output.out 2>&1; \
|
|
rm polymorphic_output.tmp; \
|
|
false; \
|
|
else \
|
|
sed -e '/EXCP/s/).*/)/' < polymorphic_output.tmp\
|
|
> polymorphic_output.out 2>&1; \
|
|
rm polymorphic_output.tmp; \
|
|
true; \
|
|
fi
|
|
|
|
loopcheck.out: loopcheck loopcheck.inp
|
|
if $(MDB) ./loopcheck < loopcheck.inp \
|
|
> loopcheck.tmp 2>&1; \
|
|
then \
|
|
sed -e '/EXCP/s/).*/)/' < loopcheck.tmp \
|
|
> loopcheck.out 2>&1; \
|
|
rm loopcheck.tmp; \
|
|
false; \
|
|
else \
|
|
sed -e '/EXCP/s/).*/)/' < loopcheck.tmp \
|
|
> loopcheck.out 2>&1; \
|
|
rm loopcheck.tmp; \
|
|
true; \
|
|
fi
|
|
|
|
# We need to pipe the output through sed to avoid hard-coding dependencies on
|
|
# particular line numbers in the standard library source code.
|
|
existential_type_classes.out: existential_type_classes \
|
|
existential_type_classes.inp
|
|
$(MDB) ./existential_type_classes < existential_type_classes.inp 2>&1 | \
|
|
sed 's/string.m:[0-9]*/string.m:NNNN/g' > existential_type_classes.out
|
|
|
|
field_names.out: field_names field_names.inp
|
|
$(MDB) ./field_names < field_names.inp > field_names.out 2>&1
|
|
|
|
implied_instance.out: implied_instance implied_instance.inp
|
|
$(MDB) ./implied_instance < implied_instance.inp \
|
|
> implied_instance.out 2>&1
|
|
|
|
interpreter.out: interpreter interpreter.inp
|
|
$(MDB) ./interpreter interpreter.m < interpreter.inp \
|
|
> interpreter.out 2>&1
|
|
|
|
# We need to pipe the output through sed to avoid hard-coding dependencies on
|
|
# particular line numbers in the standard library source code.
|
|
multi_parameter.out: multi_parameter multi_parameter.inp
|
|
$(MDB) ./multi_parameter < multi_parameter.inp 2>&1 | \
|
|
sed 's/char.m:[0-9]*/char.m:NNNN/g' > multi_parameter.out
|
|
|
|
# We need to pipe the output through sed to avoid hard-coding dependencies on
|
|
# particular line numbers in the standard library source code.
|
|
output_term_dep.out: output_term_dep output_term_dep.inp
|
|
$(MDB) ./output_term_dep < output_term_dep.inp 2>&1 | \
|
|
sed 's/io.m:[0-9]*/io.m:NNNN/g' > output_term_dep.out 2>&1
|
|
|
|
queens.out: queens queens.inp
|
|
$(MDB) ./queens < queens.inp > queens.out 2>&1
|
|
|
|
nondet_stack.out: nondet_stack nondet_stack.inp
|
|
$(MDB) ./nondet_stack < nondet_stack.inp 2>&1 | \
|
|
sed 's/nondet_stack.m:[0-9]*/nondet_stack.m:NNNN/g' \
|
|
> nondet_stack.out 2>&1
|
|
|
|
resume_typeinfos.out: resume_typeinfos resume_typeinfos.inp
|
|
$(MDB) ./resume_typeinfos < resume_typeinfos.inp 2>&1 | \
|
|
sed 's/resume_typeinfos.m:[0-9]*/resume_typeinfos.m:NNNN/g' \
|
|
> resume_typeinfos.out 2>&1
|
|
|
|
retry.out: retry retry.inp
|
|
$(MDB) ./retry < retry.inp > retry.out 2>&1
|
|
|
|
shallow.out: shallow shallow.inp
|
|
$(MDB) ./shallow < shallow.inp > shallow.out 2>&1
|
|
|
|
tabled_read.out: tabled_read tabled_read.inp
|
|
$(MDB) ./tabled_read < tabled_read.inp > tabled_read.out 2>&1
|
|
|
|
# Note that interactive.out.orig depends on $(interactive.ints) because
|
|
# interactive.inp contains interactive queries that require interactive.ints
|
|
# to have been built.
|
|
|
|
# This rule is commented out while the interactive test case is disabled,
|
|
# because otherwise we get an undefined variable warning from make.
|
|
|
|
# interactive.out.orig: interactive interactive.inp $(interactive.ints)
|
|
# $(MDB) ./interactive < interactive.inp > interactive.out.orig 2>&1
|
|
|
|
# We pipe the output through sed to remove some spurious warnings that
|
|
# `ld' issues.
|
|
# XXX we should fix the spurious warnings about unresolved symbols.
|
|
# (The spurious warnings about exception handling are due to a flaw
|
|
# in the Digital Unix 3.2 linker, so that one is DEC's problem.)
|
|
interactive.out: interactive.out.orig
|
|
cat interactive.out.orig | \
|
|
sed \
|
|
-e '/\/usr\/bin\/ld:$$/N' \
|
|
-e 's/\/usr\/bin\/ld:.//' \
|
|
-e '/Warning: Linking some objects which contain exception information sections$$/N' \
|
|
-e 's/Warning: Linking some objects which contain exception information sections.//' \
|
|
-e '/ and some which do not. This may cause fatal runtime exception handling$$/N' \
|
|
-e 's/ and some which do not. This may cause fatal runtime exception handling.//' \
|
|
-e '/ problems (last obj encountered without exceptions was .*)\.$$/N' \
|
|
-e 's/ problems (last obj encountered without exceptions was .*)\..//' \
|
|
-e '/Warning: Unresolved:$$/N' \
|
|
-e 's/Warning: Unresolved:.//' \
|
|
-e '/<predicate .main.\/2 mode 0>$$/N' \
|
|
-e 's/<predicate .main.\/2 mode 0>.//' \
|
|
-e '/<predicate .interactive:qperm.\/2 mode 0>$$/N' \
|
|
-e 's/<predicate .interactive:qperm.\/2 mode 0>.//' \
|
|
-e '/__start$$/N' \
|
|
-e 's/__start.//' \
|
|
> interactive.out
|
|
# ignore egcs internal errors -- those are not our fault
|
|
if grep 'gcc.*Internal compiler error' interactive.out; then \
|
|
cp interactive.exp interactive.out; \
|
|
fi
|
|
|
|
# We ignore the result of this action because
|
|
# the exit status of grep is not useful in this case
|
|
mdb_command_test.out: mdb_command_test mdb_command_test.inp
|
|
-$(MDB) ./mdb_command_test < mdb_command_test.inp 2>&1 \
|
|
| egrep "internal error in the trace help system" \
|
|
> mdb_command_test.out
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
DEPS= $(PROGS:%=$(deps_subdir)%.dep)
|
|
DEPENDS= $(PROGS:%=%.depend)
|
|
OUTS= $(PROGS:%=%.out)
|
|
RESS= $(PROGS:%=%.res)
|
|
|
|
dep_local: $(DEPS)
|
|
depend_local: $(DEPENDS)
|
|
check_local: $(OUTS) $(RESS)
|
|
all_local: $(PROGS)
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
SUBDIRS = declarative
|
|
|
|
check_subdirs:
|
|
+for dir in $(SUBDIRS); do \
|
|
(cd $$dir && $(SUBDIR_MMAKE) check) || exit 1; \
|
|
done
|
|
|
|
dep_subdirs:
|
|
+for dir in $(SUBDIRS); do \
|
|
(cd $$dir && $(SUBDIR_MMAKE) dep) || exit 1; \
|
|
done
|
|
|
|
depend_subdirs:
|
|
+for dir in $(SUBDIRS); do \
|
|
(cd $$dir && $(SUBDIR_MMAKE) depend) || exit 1; \
|
|
done
|
|
|
|
realclean_subdirs:
|
|
+for dir in $(SUBDIRS); do \
|
|
(cd $$dir && $(SUBDIR_MMAKE) realclean) || exit 1; \
|
|
done
|
|
|
|
clean_subdirs:
|
|
+for dir in $(SUBDIRS); do \
|
|
(cd $$dir && $(SUBDIR_MMAKE) clean) || exit 1; \
|
|
done
|
|
|
|
all_subdirs:
|
|
+for dir in $(SUBDIRS); do \
|
|
(cd $$dir && $(SUBDIR_MMAKE) all) || exit 1; \
|
|
done
|
|
|
|
#-----------------------------------------------------------------------------#
|
|
|