Files
mercury/runtime/mercury_debug.h
Zoltan Somogyi f6fafa150d Fix Mantis bug 314 for temp frames created by nondet procedures.
Also fix some bugs in related code, and improve the related debugging
infrastructure.

-------------------

runtime/mercury_stacks.[ch]:
   Fix bug 314 for temp frames created by nondet procedures. The fix will
   probably also work for *det* procedures that create temp frames on the
   nondet stack, but I can't think of a way to test that, because det
   procedures create such frames only in very specific circumstances,
   and I cannot think of a way to nest a recursive call inside those
   circumstances.

   The problem was that when we were creating new temp frames on
   the nondet stack, we did not check whether the current nondet stack segment
   had room for them. We now do.

   The stack trace tracing code needs to know the size of each nondet stack
   frame, since it uses the size to classify frames as temp or ordinary.
   The size is given by the difference in address between the address of the
   frame and the address of the previous frame. This difference would yield
   an incorrect size and hence an incorrect frame classification if a temp
   frame were allowed to have a frame on a different segment as its
   immediate predecessor.

   We prevent this by putting an ordinary (i.e. non-temp) frame at the bottom
   of every new nondet stack segment as a sentinel. We hand-build this frame,
   since it is not an "ordinary" ordinary frame. It is not created by a call,
   so it has no meaningful success continuation, and since it does not make
   any calls, no other frame's success continuation can point to it either.

   If backtracking reaches this sentinel frame, we use this fact to free
   all the segments beyond the one the sentinel frame is in, but keep the
   frame the sentinel frame is in, since we are likely to need it again.

   Document the reason why MR_incr_sp_leaf() does not have to check
   whether a new stack segment is needed. (See the fix to llds_out_instr.m
   below.)

runtime/mercury_stack_trace.[ch]:
   When traversing the nondet stack, treat the sentinel frame specially.
   We have to, since it is an ordinary frame (i.e. it is not a temp frame),
   but it is not an "ordinary" ordinary frame: it does not make calls,
   and hence calls cannot return to it, and it does not return to any
   other frame either. It therefore does not have the layout structures
   (label and proc) that the nondet stack traversal expects to find.

   Fix an old bug: the nondet stack traversal used a simple directional
   pointer comparison to check whether it has reached the bottom of the nondet
   stack. This is NOT guaranteed to work in the presence of stack segments:
   depending on exactly what addresses new stack segments get, a stack frame
   can have an address BELOW the address of the initial stack frame
   even if it is logically ABOVE that stack frame.

   Another old bug was that a difference between two pointers, which could
   be 64 bit, was stored in an int, which could be 32 bit.

   The nondet stack traversal code used a similar directional comparison
   to implement optionally stopping at an arbitrary point on the nondet stack.
   Fixing this facility (the limit_addr parameter of MR_dump_nondet_stack)
   while preserving reasonable efficiency would not be trivial, but it would
   also be pointless, since the facility is not actually used. This diff
   deletes the parameter instead.

   Move some loop invariant code out of its loop.

trace/mercury_trace_cmd_developer.c:
trace/mercury_trace_external.c:
   Don't pass the now-deleted parameter to mercury_stack_trace.c.

runtime/mercury_wrapper.c:
   Record the zone of the initial nondet stack frame, since the fix
   of mercury_stack_trace.c needs that info, and it is much more efficient
   to set it up just once.

tests/hard_coded/bug314.{m,exp}:
   The regression test for this bug.

tests/hard_coded/Mercury.options:
   Compile the new test case with the options it needs.

tests/hard_coded/Mmakefile:
   Enable the new test case.

-------------------

runtime/mercury_wrapper.c:
   The compiler knows the number of words in a stack frame it is creating,
   not necessarily the number of bytes (though it could put bounds on that
   from the number of tag bits). Since this size must sync with the runtime,
   change the runtime's variable holding this size to also be in words.

   Note that similar changes would also be beneficial for other sizes.

compiler/llds_out_instr.m:
   Conform to the change in mercury_wrapper.c, fixing an old bug
   (mercury_wrapper.c reserved 128 BYTES for leaf procedures, but
   llds_out_instr.m was using that space for procedures whose frames
   were up to 128 WORDS in size.)

compiler/mercury_memory.c:
   Conform to the change in mercury_wrapper.c.

-------------------

runtime/mercury_memory_zones.h:
   Instead of starting to use EVERY zone at a different offset, do this
   only for the INITIAL zones in each memory area, since only on these
   is it useful. When the program first starts up, it WILL be using
   the initial parts of the det stack, nondet stack and heap, so it is
   useful to make sure that these do not collide in the cache. However,
   when we allocate e.g. the second zone in e.g. the nondet stack, we are
   no more likely to be beating on the initial part of any segment
   of the det stack than on any other part of such segments.

   If a new debug macro, MR_DEBUG_STACK_SEGMENTS_SET_SIZE is set (to an int),
   use only that many words in each segment. This allows the segment switchover
   code to be exercised and debugged with smaller test cases.

runtime/mercury_conf_param.h:
   Document the MR_DEBUG_STACK_SEGMENTS_SET_SIZE macro.

   Convert this file to four-space indentation with tabs expanded.

-------------------

runtime/mercury_overflow.h:
   Make abort messages from overflows and underflows more useful by including
   more information.

runtime/mercury_overflow.c:
   Add a new function to help with the better abort messages.
   Since this file did not exist before, create it.

runtime/Mmakefile:
   Add the new source file to the list of source files.

-------------------

runtime/mercury_debug.[ch]:
   Fix problems with the formatting of the debugging output from existing
   functions.

   Add new functions for dumping info about memory zones.

   Factor out some common code.

   Convert the header file to four-space indentation.

-------------------

runtime/mercury_grade.c:
   Generate an error if stack segments are specified together with stack
   extension

-------------------

trace/.gitignore:
util/.gitignore:
tests/debugger/.gitignore:
   List some more files.

-------------------

runtime/mercury_context.c:
runtime/mercury_engine.[ch]:
runtime/mercury_misc.h:
compiler/notes/failure.html:
   Fix white space.
2014-04-18 02:02:35 +10:00

278 lines
9.7 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1995-2003, 2006, 2010 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* mercury_debug.h - definitions for debugging messages */
#ifndef MERCURY_DEBUG_H
#define MERCURY_DEBUG_H
#include "mercury_types.h" /* for MR_Word and MR_Code */
#include "mercury_type_info.h" /* for MR_TypeInfo */
#include "mercury_memory_zones.h" /* for MR_MemoryZone */
#include <stdio.h> /* for FILE */
/*---------------------------------------------------------------------------*/
#ifdef MR_DEBUG_ON
#define MR_DEBUG(action) action
#else
#define MR_DEBUG(action)
#endif
#if !defined(MR_DEBUG_GOTOS)
#define MR_debuggoto(label) ((void) 0)
#define MR_debugsreg() ((void) 0)
#else
#define MR_debuggoto(label) \
MR_IF (MR_gotodebug, \
(MR_save_transient_registers(), MR_goto_msg(stdout, label)))
#define MR_debugsreg() \
MR_IF (MR_sregdebug, \
(MR_save_transient_registers(), MR_reg_msg(stdout)))
#endif
#ifndef MR_DEBUG_HEAP_ALLOC
#define MR_debug_unravel_univ(univ, typeinfo, value) ((void) 0)
#define MR_debug_new_univ_on_hp(univ, typeinfo, value) ((void) 0)
#define MR_debug_tag_offset_incr_hp_base(ptr, tag, offset, count, is_atomic) \
((void) 0)
#else
#define MR_debug_unravel_univ(univ, typeinfo, value) \
MR_unravel_univ_msg((univ), (typeinfo), (value))
#define MR_debug_new_univ_on_hp(univ, typeinfo, value) \
MR_new_univ_on_hp_msg((univ), (typeinfo), (value))
#define MR_debug_tag_offset_incr_hp_base(ptr, tag, offset, count, is_atomic) \
MR_debug_tag_offset_incr_hp_base_msg((ptr), (tag), \
(offset), (count), (is_atomic))
#endif
#ifndef MR_LOWLEVEL_DEBUG
#define MR_debugcr1(hp) ((void) 0)
#define MR_debugcr2(hp) ((void) 0)
#define MR_debugcr3(hp) ((void) 0)
#define MR_debugincrhp(val, hp) ((void) 0)
#define MR_debugincrsp(val, sp) ((void) 0)
#define MR_debugdecrsp(val, sp) ((void) 0)
#define MR_debugregs(msg) ((void) 0)
#define MR_debugframe(msg) ((void) 0)
#define MR_debugmkframe(predname) ((void) 0)
#define MR_debugmktempframe() ((void) 0)
#define MR_debugmkdettempframe() ((void) 0)
#define MR_debugsucceed() ((void) 0)
#define MR_debugsucceeddiscard() ((void) 0)
#define MR_debugfail() ((void) 0)
#define MR_debugredo() ((void) 0)
#define MR_debugcall(proc, succ_cont) ((void) 0)
#define MR_debugtailcall(proc) ((void) 0)
#define MR_debugproceed() ((void) 0)
#define MR_debugmsg0(msg) ((void) 0)
#define MR_debugmsg1(msg, arg1) ((void) 0)
#define MR_debugmsg2(msg, arg1, arg2) ((void) 0)
#define MR_debugmsg3(msg, arg1, arg2, arg3) ((void) 0)
#else
#define MR_debugcr1(hp) \
MR_IF (MR_heapdebug, \
(MR_save_transient_registers(), \
MR_cr1_msg(stdout, hp)))
#define MR_debugcr2(hp) \
MR_IF (MR_heapdebug, \
(MR_save_transient_registers(), \
MR_cr2_msg(stdout, hp)))
#define MR_debugcr3(hp) \
MR_IF (MR_heapdebug, \
(MR_save_transient_registers(), \
MR_cr3_msg(stdout, hp)))
#define MR_debugincrhp(val, hp) \
MR_IF (MR_heapdebug, \
(MR_save_transient_registers(), \
MR_incr_hp_debug_msg(stdout, (val), (hp))))
#define MR_debugincrsp(val, sp) \
MR_IF (MR_detstackdebug, \
(MR_save_transient_registers(), \
MR_incr_sp_msg(stdout, (val), (sp))))
#define MR_debugdecrsp(val, sp) \
MR_IF (MR_detstackdebug, \
(MR_save_transient_registers(), \
MR_decr_sp_msg(stdout, (val), (sp))))
#define MR_debugregs(msg) \
MR_IF (MR_progdebug, \
(MR_save_transient_registers(), \
MR_printregs(stdout, msg)))
#define MR_debugframe(msg) \
MR_IF (MR_progdebug, \
(MR_save_transient_registers(), \
MR_printframe(stdout, msg)))
#define MR_debugmkframe(predname) \
MR_IF (MR_nondetstackdebug, \
(MR_save_transient_registers(), \
MR_mkframe_msg(stdout, predname)))
#define MR_debugmktempframe() \
MR_IF (MR_nondetstackdebug, \
(MR_save_transient_registers(), \
MR_mktempframe_msg(stdout)))
#define MR_debugmkdettempframe() \
MR_IF (MR_nondetstackdebug, \
(MR_save_transient_registers(), \
MR_mkdettempframe_msg(stdout)))
#define MR_debugsucceed() \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_succeed_msg(stdout)))
#define MR_debugsucceeddiscard() \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_succeeddiscard_msg(stdout)))
#define MR_debugfail() \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_fail_msg(stdout)))
#define MR_debugredo() \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_redo_msg(stdout)))
#define MR_debugcall(proc, succ_cont) \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_call_msg(stdout, proc, succ_cont)))
#define MR_debugtailcall(proc) \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_tailcall_msg(stdout, proc)))
#define MR_debugproceed() \
MR_IF (MR_calldebug, \
(MR_save_transient_registers(), \
MR_proceed_msg(stdout)))
#define MR_debugmsg0(msg) \
MR_IF (MR_progdebug, (fprintf(stdout, msg)))
#define MR_debugmsg1(msg, arg1) \
MR_IF (MR_progdebug, (fprintf(stdout, msg, arg1)))
#define MR_debugmsg2(msg, arg1, arg2) \
MR_IF (MR_progdebug, (fprintf(stdout, msg, arg1, arg2)))
#define MR_debugmsg3(msg, arg1, arg2, arg3) \
MR_IF (MR_progdebug, (fprintf(stdout, msg, arg1, arg2, arg3)))
#endif /* MR_LOWLEVEL_DEBUG */
#define MR_print_deep_prof_vars(fp, msg) \
do { \
fprintf(fp, "%s\n", msg); \
MR_print_deep_prof_var(fp, "curcsd", MR_current_call_site_dynamic); \
MR_print_deep_prof_var(fp, "nextcsd", MR_next_call_site_dynamic); \
} while (0)
/*---------------------------------------------------------------------------*/
#ifdef MR_DEBUG_HEAP_ALLOC
extern void MR_unravel_univ_msg(FILE *fp, MR_Word univ,
MR_TypeInfo type_info, MR_Word value);
extern void MR_new_univ_on_hp_msg(FILE *fp, MR_Word univ,
MR_TypeInfo type_info, MR_Word value);
extern void MR_debug_tag_offset_incr_hp_base_msg(FILE *fp, MR_Word ptr,
int tag, int offset, int count, int is_atomic);
#endif
#ifdef MR_LOWLEVEL_DEBUG
extern void MR_mkframe_msg(FILE *fp, const char *);
extern void MR_mktempframe_msg(FILE *fp);
extern void MR_mkdettempframe_msg(FILE *fp);
extern void MR_succeed_msg(FILE *fp);
extern void MR_succeeddiscard_msg(FILE *fp);
extern void MR_fail_msg(FILE *fp);
extern void MR_redo_msg(FILE *fp);
extern void MR_call_msg(FILE *fp, const MR_Code *proc,
const MR_Code *succ_cont);
extern void MR_tailcall_msg(FILE *fp, const MR_Code *proc);
extern void MR_proceed_msg(FILE *fp);
extern void MR_cr1_msg(FILE *fp, const MR_Word *addr);
extern void MR_cr2_msg(FILE *fp, const MR_Word *addr);
extern void MR_cr3_msg(FILE *fp, const MR_Word *addr);
extern void MR_incr_hp_debug_msg(FILE *fp, MR_Word val,
const MR_Word *addr);
extern void MR_incr_sp_msg(FILE *fp, MR_Word val, const MR_Word *addr);
extern void MR_decr_sp_msg(FILE *fp, MR_Word val, const MR_Word *addr);
#endif
#ifdef MR_DEBUG_GOTOS
extern void MR_goto_msg(FILE *fp, const MR_Code *addr);
extern void MR_reg_msg(FILE *fp);
#endif
#ifdef MR_LOWLEVEL_DEBUG
extern void MR_printint(FILE *fp, MR_Word n);
extern void MR_printstring(FILE *fp, const char *s);
extern void MR_printheap(FILE *fp, const MR_Word *h);
extern void MR_dumpframe(FILE *fp, const MR_Word *);
extern void MR_dumpnondetstack(FILE *fp);
extern void MR_printlist(FILE *fp, MR_Word p);
extern void MR_printframe(FILE *fp, const char *);
extern void MR_printregs(FILE *fp, const char *msg);
#endif
extern void MR_print_zone(FILE *fp, const MR_MemoryZone *zone);
extern void MR_print_zones(FILE *fp, const MR_MemoryZones *zones);
extern void MR_printdetstack(FILE *fp, const MR_Word *s);
extern void MR_print_detstackptr(FILE *fp, const MR_Word *s);
extern void MR_printnondetstack(FILE *fp, const MR_Word *s);
extern void MR_print_nondetstackptr(FILE *fp, const MR_Word *s);
extern void MR_print_heapptr(FILE *fp, const MR_Word *s);
extern void MR_print_label(FILE *fp, const MR_Code *w);
extern void MR_printlabel(FILE *fp, const MR_Code *w);
extern void MR_print_deep_prof_var(FILE *fp, const char *name,
MR_CallSiteDynamic *csd);
/*
** Log a message for debugging purposes. This will log the message with
** threadscope if available. In other parallel grades it will print the
** address of the MercuryEngine structure with the message to stdout.
** In all other grades, it will print the message to standard output.
** There is never any need to put a newline character at the end
** of the message; this function does that automatically.
*/
extern void MR_debug_log_message(const char *format, ...);
/*---------------------------------------------------------------------------*/
#endif /* not MERCURY_DEBUG_H */