Files
mercury/trace/mercury_trace_cmd_forward.c
Zoltan Somogyi 233b899714 Avoid some C compiler warnings in the trace directory.
trace/mercury_trace.h:
    Avoid a warning from the C compiler about casting -1 to an enum
    by adding bool next to the enum that says whether the enum is actually
    defined, or is supposed to be set later (the latter is what the cast -1
    meant).

trace/mercury_trace_cmds.h:
    Rename the type MR_Trace_Command_Info to MR_TraceCmdTableEntry,
    since this (a) says more about the values of the type, (b) avoids
    confusion with the separate MR_TraceCmdInfo type (the one that
    contained the enum mentioned above), and (c) avoids combining
    underscores with CamelCase.

trace/mercury_trace_spy.c:
    Avoid some warnings about switches on enums specifying -1 as a case.

trace/mercury_trace.c:
trace/mercury_trace_*.[ch]:
    Conform to the above changes.
2014-08-09 02:19:35 +02:00

600 lines
20 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1998-2008,2012 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.
*/
/*
** This module implements the mdb commands in the "forward" category.
**
** The structure of these files is:
**
** - all the #includes
** - local macros and declarations of local static functions
** - one function for each command in the category
** - any auxiliary functions
** - any command argument strings
** - option processing functions.
*/
#include "mercury_std.h"
#include "mercury_getopt.h"
#include "mercury_trace_internal.h"
#include "mercury_trace_cmds.h"
#include "mercury_trace_cmd_forward.h"
#include "mercury_trace_cmd_parameter.h"
#include "mercury_trace_util.h"
/****************************************************************************/
static MR_bool MR_trace_options_movement_cmd(MR_TraceCmdInfo *cmd,
char ***words, int *word_count);
/****************************************************************************/
MR_Next
MR_trace_cmd_step(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
MR_Unsigned n;
cmd->MR_trace_strict = MR_FALSE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
cmd->MR_trace_cmd = MR_CMD_STEP;
return STOP_INTERACTING;
} else if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = MR_trace_event_number + n;
return STOP_INTERACTING;
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_goto(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
MR_Unsigned n;
const char *generator_name;
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
generator_name = NULL;
if (MR_trace_event_number < n
|| !MR_cur_generator_is_named(generator_name))
{
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = n;
cmd->MR_trace_stop_generator = generator_name;
return STOP_INTERACTING;
} else {
/* XXX this message is misleading */
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "The debugger cannot go to a past event.\n");
}
#ifdef MR_USE_MINIMAL_MODEL_OWN_STACKS
} else if (word_count == 3 && MR_trace_is_natural_number(words[1], &n)) {
generator_name = words[2];
if (MR_trace_event_number < n
|| !MR_cur_generator_is_named(generator_name))
{
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = n;
/*
** We don't ever deallocate the memory allocated here,
** but this memory leak leaks only negligible amounts of memory.
*/
cmd->MR_trace_stop_generator = strdup(generator_name);
return STOP_INTERACTING;
} else {
/* XXX this message is misleading */
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "The debugger cannot go to a past event.\n");
}
#endif
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_next(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
const MR_ProcLayout *proc_layout;
const MR_LabelLayout *ancestor_layout;
MR_Unsigned depth;
MR_Unsigned stop_depth;
MR_Unsigned n;
MR_TracePort port;
MR_Word *base_sp;
MR_Word *base_curfr;
MR_Unsigned reused_frames;
MR_Level actual_level;
const char *problem; /* not used */
depth = event_info->MR_call_depth;
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
return KEEP_INTERACTING;
} else if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
stop_depth = depth - n;
} else if (word_count == 1) {
n = 0;
stop_depth = depth;
} else {
MR_trace_usage_cur_cmd();
return KEEP_INTERACTING;
}
base_sp = MR_saved_sp(event_info->MR_saved_regs);
base_curfr = MR_saved_curfr(event_info->MR_saved_regs);
proc_layout = event_info->MR_event_sll->MR_sll_entry;
MR_trace_find_reused_frames(proc_layout, base_sp, reused_frames);
port = event_info->MR_trace_port;
if (depth == stop_depth &&
(MR_port_is_final(port) || port == MR_PORT_TAILREC_CALL))
{
MR_trace_do_noop();
} else if (depth - reused_frames <= stop_depth && stop_depth < depth) {
MR_trace_do_noop_tail_rec();
} else {
ancestor_layout = MR_find_nth_ancestor(event_info->MR_event_sll,
n, &base_sp, &base_curfr, &actual_level, &problem);
if (ancestor_layout == NULL) {
fflush(MR_mdb_out);
if (problem != NULL) {
fprintf(MR_mdb_err, "mdb: %s\n", problem);
} else {
fprintf(MR_mdb_err, "mdb: not that many ancestors.\n");
}
return KEEP_INTERACTING;
} else if (actual_level != n) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err,
"mdb: that stack frame has been reused, "
"will stop in reusing call.\n");
} else {
cmd->MR_trace_cmd = MR_CMD_NEXT;
cmd->MR_trace_stop_depth = stop_depth;
return STOP_INTERACTING;
}
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_finish(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
const MR_ProcLayout *proc_layout;
const MR_LabelLayout *ancestor_layout;
MR_Unsigned depth;
MR_Unsigned stop_depth;
MR_Unsigned n;
MR_Level ancestor_level;
MR_TracePort port;
MR_Word *base_sp;
MR_Word *base_curfr;
MR_Unsigned reused_frames;
MR_Level actual_level;
const char *problem; /* not used */
depth = event_info->MR_call_depth;
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
return KEEP_INTERACTING;
} else if (word_count == 2 &&
( MR_streq(words[1], "entry") || MR_streq(words[1], "clentry")))
{
if (MR_find_clique_entry_mdb(event_info, MR_CLIQUE_ENTRY_FRAME,
&ancestor_level))
{
/* the error message has already been printed */
return KEEP_INTERACTING;
}
} else if (word_count == 2 && MR_streq(words[1], "clparent"))
{
if (MR_find_clique_entry_mdb(event_info, MR_CLIQUE_ENTRY_PARENT_FRAME,
&ancestor_level))
{
/* the error message has already been printed */
return KEEP_INTERACTING;
}
} else if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
ancestor_level = n;
} else if (word_count == 1) {
ancestor_level = 0;
} else {
MR_trace_usage_cur_cmd();
return KEEP_INTERACTING;
}
base_sp = MR_saved_sp(event_info->MR_saved_regs);
base_curfr = MR_saved_curfr(event_info->MR_saved_regs);
proc_layout = event_info->MR_event_sll->MR_sll_entry;
MR_trace_find_reused_frames(proc_layout, base_sp, reused_frames);
port = event_info->MR_trace_port;
stop_depth = depth - ancestor_level;
if (MR_port_is_final(port) && depth == stop_depth) {
MR_trace_do_noop();
} else if (MR_port_is_final(port) &&
depth - reused_frames <= stop_depth && stop_depth < depth)
{
MR_trace_do_noop_tail_rec();
} else {
ancestor_layout = MR_find_nth_ancestor(event_info->MR_event_sll,
ancestor_level, &base_sp, &base_curfr, &actual_level, &problem);
if (ancestor_layout == NULL) {
fflush(MR_mdb_out);
if (problem != NULL) {
fprintf(MR_mdb_err, "mdb: %s\n", problem);
} else {
fprintf(MR_mdb_err, "mdb: not that many ancestors.\n");
}
return KEEP_INTERACTING;
} else if (actual_level != ancestor_level) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "%d %d\n",
(int) ancestor_level, (int) actual_level);
fprintf(MR_mdb_err,
"mdb: that stack frame has been reused, "
"will stop at finish of reusing call.\n");
} else {
cmd->MR_trace_cmd = MR_CMD_FINISH;
cmd->MR_trace_stop_depth = stop_depth;
return STOP_INTERACTING;
}
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_fail(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
MR_Determinism detism;
MR_Unsigned depth;
MR_Unsigned stop_depth;
MR_Unsigned n;
detism = event_info->MR_event_sll->MR_sll_entry->MR_sle_detism;
depth = event_info->MR_call_depth;
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
return KEEP_INTERACTING;
} else if (word_count == 2 && MR_trace_is_natural_number(words[1], &n)) {
stop_depth = depth - n;
} else if (word_count == 1) {
stop_depth = depth;
} else {
MR_trace_usage_cur_cmd();
return KEEP_INTERACTING;
}
if (MR_DETISM_DET_STACK(detism)) {
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: cannot continue until failure: "
"selected procedure has determinism %s.\n",
MR_detism_names[detism]);
return KEEP_INTERACTING;
}
/*
** A procedure that lives on the nondet stack cannot have its stack frame
** reused by tail recursive calls (at least not when any kind of debugging
** is enabled).
*/
if (depth == stop_depth && event_info->MR_trace_port == MR_PORT_FAIL) {
MR_trace_do_noop();
} else if (depth == stop_depth &&
event_info->MR_trace_port == MR_PORT_EXCEPTION)
{
fflush(MR_mdb_out);
fprintf(MR_mdb_err, "mdb: cannot continue until failure: "
"the call has raised an exception.\n");
} else {
cmd->MR_trace_cmd = MR_CMD_FAIL;
cmd->MR_trace_stop_depth = stop_depth;
return STOP_INTERACTING;
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_exception(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
if (event_info->MR_trace_port != MR_PORT_EXCEPTION) {
cmd->MR_trace_cmd = MR_CMD_EXCP;
return STOP_INTERACTING;
} else {
MR_trace_do_noop();
}
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_return(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
if (event_info->MR_trace_port == MR_PORT_EXIT) {
cmd->MR_trace_cmd = MR_CMD_RETURN;
return STOP_INTERACTING;
} else {
MR_trace_do_noop();
}
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_user(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
cmd->MR_trace_cmd = MR_CMD_USER;
return STOP_INTERACTING;
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_forward(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
MR_TracePort port;
port = event_info->MR_trace_port;
if (port == MR_PORT_FAIL ||
port == MR_PORT_REDO ||
port == MR_PORT_EXCEPTION)
{
cmd->MR_trace_cmd = MR_CMD_RESUME_FORWARD;
return STOP_INTERACTING;
} else {
MR_trace_do_noop();
}
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_mindepth(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
MR_Unsigned newdepth;
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 2 &&
MR_trace_is_natural_number(words[1], &newdepth))
{
cmd->MR_trace_cmd = MR_CMD_MIN_DEPTH;
cmd->MR_trace_stop_depth = newdepth;
return STOP_INTERACTING;
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_maxdepth(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
MR_Unsigned newdepth;
cmd->MR_trace_strict = MR_TRUE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 2 &&
MR_trace_is_natural_number(words[1], &newdepth))
{
cmd->MR_trace_cmd = MR_CMD_MAX_DEPTH;
cmd->MR_trace_stop_depth = newdepth;
return STOP_INTERACTING;
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
MR_Next
MR_trace_cmd_continue(char **words, int word_count, MR_TraceCmdInfo *cmd,
MR_EventInfo *event_info, MR_Code **jumpaddr)
{
cmd->MR_trace_strict = MR_FALSE;
cmd->MR_trace_print_level_specified = MR_FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
MR_init_trace_check_integrity(cmd);
if (! MR_trace_options_movement_cmd(cmd, &words, &word_count)) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
cmd->MR_trace_cmd = MR_CMD_TO_END;
if (! cmd->MR_trace_print_level_specified) {
/*
** The user did not specify the print level;
** select the intelligent default.
*/
if (cmd->MR_trace_strict) {
cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
} else {
cmd->MR_trace_print_level = MR_PRINT_LEVEL_SOME;
}
}
return STOP_INTERACTING;
} else {
MR_trace_usage_cur_cmd();
}
return KEEP_INTERACTING;
}
/****************************************************************************/
const char *const MR_trace_movement_cmd_args[] =
{ "-N", "-S", "-a", "-i", "-n", "-s",
"--none", "--some", "--all", "--integrity",
"--strict", "--no-strict", NULL };
/****************************************************************************/
static struct MR_option MR_trace_movement_cmd_opts[] =
{
{ "all", MR_no_argument, NULL, 'a' },
{ "none", MR_no_argument, NULL, 'n' },
{ "some", MR_no_argument, NULL, 's' },
{ "nostrict", MR_no_argument, NULL, 'N' },
{ "strict", MR_no_argument, NULL, 'S' },
#ifdef MR_TRACE_CHECK_INTEGRITY
{ "integrity", MR_no_argument, NULL, 'i' },
#endif
{ NULL, MR_no_argument, NULL, 0 }
};
static MR_bool
MR_trace_options_movement_cmd(MR_TraceCmdInfo *cmd,
char ***words, int *word_count)
{
int c;
#ifdef MR_TRACE_CHECK_INTEGRITY
#define MR_TRACE_MOVEMENT_OPTS "NSains"
#else
#define MR_TRACE_MOVEMENT_OPTS "NSans"
#endif
MR_optind = 0;
while ((c = MR_getopt_long(*word_count, *words, MR_TRACE_MOVEMENT_OPTS,
MR_trace_movement_cmd_opts, NULL)) != EOF)
{
switch (c) {
case 'N':
cmd->MR_trace_strict = MR_FALSE;
break;
case 'S':
cmd->MR_trace_strict = MR_TRUE;
break;
case 'a':
cmd->MR_trace_print_level_specified = MR_TRUE;
cmd->MR_trace_print_level = MR_PRINT_LEVEL_ALL;
break;
case 'n':
cmd->MR_trace_print_level_specified = MR_TRUE;
cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
break;
case 's':
cmd->MR_trace_print_level_specified = MR_TRUE;
cmd->MR_trace_print_level = MR_PRINT_LEVEL_SOME;
break;
#ifdef MR_TRACE_CHECK_INTEGRITY
case 'i':
cmd->MR_trace_check_integrity = MR_TRUE;
break;
#endif
default:
MR_trace_usage_cur_cmd();
return MR_FALSE;
}
}
*words = *words + MR_optind - 1;
*word_count = *word_count - MR_optind + 1;
return MR_TRUE;
}