Files
mercury/runtime/mercury_stack_trace.h
Zoltan Somogyi d1c13d57c5 Fix some layout issues in these files. There are no algorithmic
Estimated hours taken: 0.3
Branches: main

runtime/mercury_accurate_gc.h:
runtime/mercury_agc_debug.h:
runtime/mercury_array_macros.h:
runtime/mercury_construct.h:
runtime/mercury_deconstruct.h:
runtime/mercury_init.h:
runtime/mercury_layout_util.h:
runtime/mercury_stack_layout.h:
runtime/mercury_stack_trace.h:
runtime/mercury_trail.h:
	Fix some layout issues in these files. There are no algorithmic
	changes.
2005-06-21 03:12:03 +00:00

329 lines
11 KiB
C

/*
** Copyright (C) 1998-2001, 2003-2005 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 "mercury_regs.h"
#include "mercury_stack_layout.h"
#include <stdio.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, MR_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 limit is nonzero, dumps at most limit frames.
**
** If the entire wanted part of the 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,
MR_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,
MR_bool include_trace_data,
MR_bool include_contexts,
int frame_limit, int line_limit,
MR_Print_Stack_Record print_stack_record);
/*
** MR_dump_nondet_stack
**
** This function dumps the control slots of the nondet stack.
** If limit_addr is nonnull, dumps only frames above limit_addr.
** If limit is nonzero, dumps at most limit frames.
** The output format is not meant to be intelligible to non-implementors.
*/
extern void MR_dump_nondet_stack(FILE *fp, MR_Word *limit_addr,
int frame_limit, int line_limit, MR_Word *maxfr);
/*
** MR_dump_nondet_stack_from_layout
**
** This function dumps the nondet stack.
** If limit_addr is nonnull, dumps only frames above limit_addr.
** If limit is nonzero, dumps at most limit frames.
** The output format is not meant to be intelligible to non-implementors.
*/
extern void MR_dump_nondet_stack_from_layout(FILE *fp,
MR_Word *limit_addr, int frame_limit, int line_limit,
MR_Word *maxfr, const MR_Label_Layout *label_layout,
MR_Word *base_sp, MR_Word *base_curfr);
/*
** MR_traverse_nondet_stack_from_layout
**
** This function traverses the nondet stack, calling the specified
** function for each frame.
*/
typedef void MR_Traverse_Nondet_Frame_Func(void *user_data,
const MR_Label_Layout *layout, MR_Word *base_sp,
MR_Word *base_curfr);
extern void MR_traverse_nondet_stack_from_layout(
MR_Word *maxfr, const MR_Label_Layout *label_layout,
MR_Word *base_sp, MR_Word *base_curfr,
MR_Traverse_Nondet_Frame_Func *traverse_frame_func,
void *traverse_frame_func_data);
/*
** 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, i.e. to the
** caller's 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.
**
** Note that for nondetermistic code, this function will only
** traverse the success continuations (via MR_succfr),
** not the frames which represent failure continuations
** (which would be accessible via MR_redofr).
*/
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 MR_TRUE;
** otherwise, it returns MR_FALSE.
*/
extern MR_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 MR_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,
MR_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_pred_id prints everything that MR_print_proc_id does, except
** the mode number and determinism.
*/
extern void MR_print_pred_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_separate prints a string that uniquely specifies the given
** procedure to the debugger, with each component of a name in a separate field
** to allow the output to be processed by tools (e.g. awk scripts).
*/
extern void MR_print_proc_separate(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,
MR_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,
MR_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, MR_bool context_mismatch);
/*
** Find the first call event on the stack whose event number or sequence number
** is less than or equal to the given event number or sequence number. The
** level of the call in the stack is returned. This can then be passed to
** MR_trace_retry as the ancestor_level. If no such call is found then -1 is
** returned and problem is set to the reason why the call could not be
** found.
*/
typedef enum {
MR_FIND_FIRST_CALL_BEFORE_SEQ,
MR_FIND_FIRST_CALL_BEFORE_EVENT
} MR_find_first_call_seq_or_event;
extern int MR_find_first_call_less_eq_seq_or_event(
MR_find_first_call_seq_or_event seq_or_event,
MR_Unsigned seq_no_or_event_no,
const MR_Label_Layout *label_layout,
MR_Word *det_stack_pointer, MR_Word *current_frame,
const char **problem);
#endif /* MERCURY_STACK_TRACE_H */