mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-24 13:53:54 +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.
254 lines
8.8 KiB
C
254 lines
8.8 KiB
C
/*
|
|
** Copyright (C) 1998-2001 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.
|
|
*/
|
|
|
|
#ifndef MERCURY_STACK_TRACE_H
|
|
#define MERCURY_STACK_TRACE_H
|
|
|
|
#include <stdio.h>
|
|
#include "mercury_stack_layout.h"
|
|
|
|
/*
|
|
** mercury_stack_trace.h -
|
|
** Definitions for use by the stack tracing.
|
|
*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** MR_dump_stack:
|
|
** Given the succip, det stack pointer and current frame, generate a
|
|
** stack dump showing the name of each active procedure on the
|
|
** stack. If include_trace_data data is set, also print the
|
|
** call event number, call sequence number and depth for every
|
|
** traced procedure.
|
|
** NOTE: MR_dump_stack will assume that the succip is for the
|
|
** topmost stack frame. If you call MR_dump_stack from some
|
|
** pragma c_code, that may not be the case.
|
|
** Due to some optimizations (or lack thereof) the MR_dump_stack call
|
|
** may end up inside code that has a stack frame allocated, but
|
|
** that has a succip for the previous stack frame.
|
|
** Don't call MR_dump_stack from Mercury pragma c_code (calling
|
|
** from other C code in the runtime is probably ok, provided the
|
|
** succip corresponds to the topmost stack frame).
|
|
** (See library/require.m for a technique for calling MR_dump_stack
|
|
** from Mercury).
|
|
** If you need a more convenient way of calling from Mercury code,
|
|
** it would probably be best to make an impure predicate defined
|
|
** using `:- external'.
|
|
*/
|
|
|
|
extern void MR_dump_stack(MR_Code *success_pointer,
|
|
MR_Word *det_stack_pointer,
|
|
MR_Word *current_frame, bool include_trace_data);
|
|
|
|
/*
|
|
** MR_dump_stack_from_layout:
|
|
** This function does the same job and makes the same assumptions
|
|
** as MR_dump_stack, but instead of the succip, it takes the label
|
|
** layout of the current point in the current procedure as input.
|
|
** It also takes a parameter that tells it where to put the stack dump
|
|
** and flags that say whether to include execution trace data and/or
|
|
** line numbers.
|
|
**
|
|
** If the entire stack was printed successfully, the return value is NULL;
|
|
** otherwise, it is a string indicating why the dump was cut short.
|
|
*/
|
|
|
|
typedef void (*MR_Print_Stack_Record)(FILE *fp,
|
|
const MR_Proc_Layout *proc_layout,
|
|
int count, int level,
|
|
MR_Word *base_sp, MR_Word * base_curfr,
|
|
const char *filename, int linenumber,
|
|
const char *goal_path, bool context_mismatch);
|
|
|
|
extern const char *MR_dump_stack_from_layout(FILE *fp,
|
|
const MR_Label_Layout *label_layout,
|
|
MR_Word *det_stack_pointer,
|
|
MR_Word *current_frame,
|
|
bool include_trace_data,
|
|
bool include_contexts,
|
|
MR_Print_Stack_Record print_stack_record);
|
|
|
|
/*
|
|
** MR_dump_nondet_stack:
|
|
** This function dumps the control slots of the nondet stack.
|
|
** The output format is not meant to be intelligible to non-implementors.
|
|
*/
|
|
|
|
extern void MR_dump_nondet_stack(FILE *fp, MR_Word *maxfr);
|
|
|
|
/*
|
|
** MR_dump_nondet_stack_from_layout:
|
|
** This function dumps the nondet stack.
|
|
** The output format is not meant to be intelligible to non-implementors.
|
|
*/
|
|
|
|
extern void MR_dump_nondet_stack_from_layout(FILE *fp, MR_Word *maxfr,
|
|
const MR_Label_Layout *label_layout,
|
|
MR_Word *base_sp, MR_Word *base_curfr);
|
|
|
|
/*
|
|
** MR_find_nth_ancestor:
|
|
** Return the layout structure of the return label of the call
|
|
** ancestor_level levels above the current call. Label_layout
|
|
** tells us how to decipher the stack of the current call, while
|
|
** *stack_trace_sp and *stack_trace_curfr tell us where it is.
|
|
** On return, *stack_trace_sp and *stack_trace_curfr will be
|
|
** set up to match the specified ancestor.
|
|
**
|
|
** If the required stack walk is not possible (e.g. because some
|
|
** stack frames have no layout information, or because the stack
|
|
** does not have the required depth), the return value will be NULL,
|
|
** and problem will point to an error message.
|
|
*/
|
|
|
|
extern const MR_Label_Layout *MR_find_nth_ancestor(
|
|
const MR_Label_Layout *label_layout,
|
|
int ancestor_level, MR_Word **stack_trace_sp,
|
|
MR_Word **stack_trace_curfr, const char **problem);
|
|
|
|
/*
|
|
** MR_stack_walk_step:
|
|
** This function takes the entry_layout for the current stack
|
|
** frame (which is the topmost stack frame from the two stack
|
|
** pointers given), and moves down one stack frame, setting the
|
|
** stack pointers to their new levels.
|
|
**
|
|
** return_label_layout will be set to the stack_layout of the
|
|
** continuation label, or NULL if the bottom of the stack has
|
|
** been reached.
|
|
**
|
|
** The meanings of the possible return values from MR_stack_walk_step
|
|
** are as follows:
|
|
**
|
|
** MR_STEP_OK: everything is fine.
|
|
** MR_STEP_ERROR_BEFORE: entry_layout has no valid stack trace info.
|
|
** MR_STEP_ERROR_AFTER: entry_layout has valid stack trace info,
|
|
** but its caller does not.
|
|
**
|
|
** If a MR_stack_walk_step encounters a problem, it will set problem_ptr
|
|
** to point to a string representation of the error.
|
|
*/
|
|
|
|
typedef enum {
|
|
MR_STEP_ERROR_BEFORE,
|
|
MR_STEP_ERROR_AFTER,
|
|
MR_STEP_OK
|
|
} MR_Stack_Walk_Step_Result;
|
|
|
|
extern MR_Stack_Walk_Step_Result
|
|
MR_stack_walk_step(const MR_Proc_Layout *entry_layout,
|
|
const MR_Label_Layout **return_label_layout,
|
|
MR_Word **stack_trace_sp_ptr, MR_Word **stack_trace_curfr_ptr,
|
|
const char **problem_ptr);
|
|
|
|
/*
|
|
** MR_stack_trace_bottom should be set to the address of global_success,
|
|
** the label main/2 goes to on success. Stack dumps terminate when they
|
|
** reach a stack frame whose saved succip slot contains this address.
|
|
*/
|
|
|
|
extern MR_Code *MR_stack_trace_bottom;
|
|
|
|
/*
|
|
** MR_nondet_stack_trace_bottom should be set to the address of the buffer
|
|
** nondet stack frame created before calling main. Nondet stack dumps terminate
|
|
** when they reach a stack frame whose redoip contains this address. Note that
|
|
** the redoip and redofr slots of this frame may be hijacked.
|
|
*/
|
|
|
|
extern MR_Word *MR_nondet_stack_trace_bottom;
|
|
|
|
/*
|
|
** The different Mercury determinisms are internally represented by integers.
|
|
** This array gives the correspondance with the internal representation and
|
|
** the names that are usually used to denote determinisms.
|
|
*/
|
|
|
|
extern const char *MR_detism_names[];
|
|
|
|
/*
|
|
** MR_find_context attempts to look up the file name and line number
|
|
** corresponding to a label identified by its layout structure. If successful,
|
|
** it fills in *fileptr and *lineptr accordingly, and returns TRUE; otherwise,
|
|
** it returns FALSE.
|
|
*/
|
|
|
|
extern bool MR_find_context(const MR_Label_Layout *label,
|
|
const char **fileptr, int *lineptr);
|
|
|
|
/*
|
|
** MR_print_call_trace_info prints the call event number, call sequence number
|
|
** and call depth of the call stored in the stack frame of the procedure
|
|
** identified by the given proc layout. It requires the procedure to have
|
|
** trace layout information, and the relevant one of base_sp and base_curfr
|
|
** to be non-NULL, since these numbers are stored in stack slots.
|
|
**
|
|
** MR_maybe_print_call_trace_info calls MR_print_call_trace_info if
|
|
** include_trace_data is TRUE and the other conditions required by
|
|
** MR_print_call_trace_info are satisfied.
|
|
*/
|
|
|
|
extern void MR_print_call_trace_info(FILE *fp,
|
|
const MR_Proc_Layout *entry,
|
|
MR_Word *base_sp, MR_Word *base_curfr);
|
|
|
|
extern void MR_maybe_print_call_trace_info(FILE *fp,
|
|
bool include_trace_data,
|
|
const MR_Proc_Layout *entry,
|
|
MR_Word *base_sp, MR_Word *base_curfr);
|
|
|
|
/*
|
|
** MR_print_proc_id prints an identification of the given procedure,
|
|
** consisting of "pred" or "func", module name, pred or func name, arity,
|
|
** mode number and determinism. It does not output a newline, so that
|
|
** the caller can put something else after the procedure id on the same line.
|
|
*/
|
|
|
|
extern void MR_print_proc_id(FILE *fp, const MR_Proc_Layout *entry);
|
|
|
|
/*
|
|
** MR_print_proc_spec prints a string that uniquely specifies the given
|
|
** procedure to the debugger.
|
|
*/
|
|
|
|
extern void MR_print_proc_spec(FILE *fp, const MR_Proc_Layout *entry);
|
|
|
|
/*
|
|
** MR_print_proc_id_trace_and_context prints an identification of the given
|
|
** procedure, together with call trace information (if available), a context
|
|
** within the procedure, and possibly a context identifying the caller.
|
|
** The position argument says where (if anywhere) the contexts should appear.
|
|
*/
|
|
|
|
typedef enum {
|
|
MR_CONTEXT_NOWHERE,
|
|
MR_CONTEXT_BEFORE,
|
|
MR_CONTEXT_AFTER,
|
|
MR_CONTEXT_PREVLINE,
|
|
MR_CONTEXT_NEXTLINE
|
|
} MR_Context_Position;
|
|
|
|
extern void MR_print_proc_id_trace_and_context(FILE *fp,
|
|
bool include_trace_data, MR_Context_Position pos,
|
|
const MR_Proc_Layout *entry,
|
|
MR_Word *base_sp, MR_Word *base_curfr, const char *path,
|
|
const char *filename, int lineno, bool print_parent,
|
|
const char *parent_filename, int parent_lineno,
|
|
int indent);
|
|
|
|
/*
|
|
** MR_dump_stack_record_print() prints one line of a stack dump.
|
|
*/
|
|
|
|
extern void MR_dump_stack_record_print(FILE *fp,
|
|
const MR_Proc_Layout *entry_layout, int count,
|
|
int start_level, MR_Word *base_sp, MR_Word *base_curfr,
|
|
const char *filename, int linenumber,
|
|
const char *goal_path, bool context_mismatch);
|
|
|
|
#endif /* MERCURY_STACK_TRACE_H */
|