for review: new debugger command set (part 4 of 4)
Zoltan Somogyi
zs at cs.mu.OZ.AU
Thu Oct 1 18:52:25 AEST 1998
Index: trace/mercury_trace_external.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_external.c,v
retrieving revision 1.1
diff -u -u -r1.1 mercury_trace_external.c
--- mercury_trace_external.c 1998/09/29 05:11:52 1.1
+++ mercury_trace_external.c 1998/09/29 06:58:57
@@ -26,7 +26,7 @@
RECAST MERCURY_TRACE_UTIL AS MERCURY_LAYOUT_UTIL
#include "mercury_trace.h"
#include "mercury_trace_external.h"
-#include "mercury_trace_util.h"
+#include "mercury_layout_util.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
@@ -68,11 +68,11 @@
MISC RUNTIME CHANGES
Integer *debugger_request_type_ptr);
static bool MR_found_match(const MR_Stack_Layout_Label *layout,
- MR_trace_port port, Unsigned seqno, Unsigned depth,
+ MR_Trace_Port port, Unsigned seqno, Unsigned depth,
/* XXX registers */
const char *path, Word search_data);
static void MR_output_current_slots(const MR_Stack_Layout_Label *layout,
- MR_trace_port port, Unsigned seqno, Unsigned depth,
+ MR_Trace_Port port, Unsigned seqno, Unsigned depth,
const char *path);
static void MR_output_current_vars(Word var_list, Word string_list);
static void MR_output_current_nth_var(Word var);
@@ -80,9 +80,10 @@
RECAST MERCURY_TRACE_UTIL AS MERCURY_LAYOUT_UTIL
Word type_list);
static Word MR_trace_make_var_names_list(
const MR_Stack_Layout_Label *layout);
-static Word MR_trace_make_type_list(const MR_Stack_Layout_Label *layout);
+static Word MR_trace_make_type_list(const MR_Stack_Layout_Label *layout,
+ Word *saved_regs);
static Word MR_trace_make_nth_var(const MR_Stack_Layout_Label *layout,
- Word debugger_request);
+ Word *saved_regs, Word debugger_request);
static int MR_get_var_number(Word debugger_request);
#if 0
@@ -320,9 +321,9 @@
RECAST MERCURY_TRACE_UTIL AS MERCURY_LAYOUT_UTIL
MISC RUNTIME CHANGES
}
void
-MR_trace_event_external(MR_trace_cmd_info *cmd,
- const MR_Stack_Layout_Label *layout, MR_trace_port port,
- Unsigned seqno, Unsigned depth, const char *path)
+MR_trace_event_external(MR_Trace_Cmd_Info *cmd,
+ const MR_Stack_Layout_Label *layout, Word *saved_regs,
+ MR_Trace_Port port, Unsigned seqno, Unsigned depth, const char *path)
{
static bool searching = FALSE;
static Word search_data;
@@ -370,9 +371,10 @@
}
var_names_list =
MR_trace_make_var_names_list(layout);
- type_list = MR_trace_make_type_list(layout);
+ type_list = MR_trace_make_type_list(layout,
+ saved_regs);
MR_output_current_live_var_names(var_names_list,
- type_list);
+ type_list);
break;
case MR_REQUEST_CURRENT_VARS:
@@ -380,7 +382,7 @@
fprintf(stderr, "\nMercury runtime: "
"REQUEST_CURRENT_VARS\n");
}
- var_list = MR_trace_make_var_list(layout);
+ var_list = MR_make_var_list(layout, saved_regs);
var_names_list =
MR_trace_make_var_names_list(layout);
MR_output_current_vars(var_list,
@@ -392,7 +394,7 @@
fprintf(stderr, "\nMercury runtime: "
"REQUEST_NTH_CURRENT_VAR\n");
}
- var = MR_trace_make_nth_var(layout,
+ var = MR_trace_make_nth_var(layout, saved_regs,
debugger_request);
MR_output_current_nth_var(var);
break;
@@ -420,7 +422,7 @@
static void
MR_output_current_slots(const MR_Stack_Layout_Label *layout,
- MR_trace_port port, Unsigned seqno, Unsigned depth, const char *path)
+ MR_Trace_Port port, Unsigned seqno, Unsigned depth, const char *path)
{
MR_DI_output_current_slots(
MR_trace_event_number,
@@ -477,7 +479,7 @@
static bool
MR_found_match(const MR_Stack_Layout_Label *layout,
- MR_trace_port port, Unsigned seqno, Unsigned depth,
+ MR_Trace_Port port, Unsigned seqno, Unsigned depth,
/* XXX live vars */
const char *path, Word search_data)
{
@@ -548,7 +550,7 @@
*/
static Word
-MR_trace_make_type_list(const MR_Stack_Layout_Label *layout)
+MR_trace_make_type_list(const MR_Stack_Layout_Label *layout, Word *saved_regs)
{
int var_count;
const MR_Stack_Layout_Vars *vars;
@@ -571,7 +573,7 @@
name = MR_name_if_present(vars, i);
var = &vars->MR_slvs_pairs[i];
- if (!MR_trace_get_type_filtered(var, name, &type_info))
+ if (! MR_get_type_filtered(var, saved_regs, name, &type_info))
{
continue;
}
@@ -591,7 +593,7 @@
*/
static Word
-MR_trace_make_nth_var(const MR_Stack_Layout_Label *layout,
+MR_trace_make_nth_var(const MR_Stack_Layout_Label *layout, Word *saved_regs,
Word debugger_request)
{
int var_number;
@@ -615,8 +617,8 @@
incr_hp(univ, 2);
- if (MR_trace_get_type_and_value_filtered(var, name, &type_info,
- &value))
+ if (MR_get_type_and_value_filtered(var, saved_regs, name,
+ &type_info, &value))
{
field(mktag(0), univ, UNIV_OFFSET_FOR_TYPEINFO) = type_info;
field(mktag(0), univ, UNIV_OFFSET_FOR_DATA) = value;
Index: trace/mercury_trace_external.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_external.h,v
retrieving revision 1.1
diff -u -u -r1.1 mercury_trace_external.h
--- mercury_trace_external.h 1998/09/29 05:11:54 1.1
+++ mercury_trace_external.h 1998/09/29 06:58:58
RECAST MERCURY_TRACE_UTIL AS MERCURY_LAYOUT_UTIL
MISC RUNTIME CHANGES
@@ -11,10 +11,10 @@
extern void MR_trace_init_external(void);
extern void MR_trace_final_external(void);
-extern void MR_trace_event_external(MR_trace_cmd_info *cmd,
+extern void MR_trace_event_external(MR_Trace_Cmd_Info *cmd,
const MR_Stack_Layout_Label *layout,
- MR_trace_port port, Unsigned seqno, Unsigned depth,
- const char *path);
+ Word *saved_regs, MR_Trace_Port port, Unsigned seqno,
+ Unsigned depth, const char *path);
#endif /* MR_USE_EXTERNAL_DEBUGGER */
Index: trace/mercury_trace_help.c
===================================================================
RCS file: mercury_trace_help.c
diff -N mercury_trace_help.c
--- /dev/null Wed May 28 10:49:58 1997
+++ mercury_trace_help.c Wed Sep 23 18:30:47 1998
IMPLEMENT NEW DEBUGGER COMMAND SET
@@ -0,0 +1,126 @@
+/*
+** Copyright (C) 1998 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_trace_help.c
+**
+** Help system for the internal debugger.
+** Most of the implementation is in library/help.m;
+** this is only the interface.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#include "mercury_imp.h"
+#include "mercury_trace_help.h"
+#include "mercury_macros.h"
+#include "mercury_misc.h"
+#include "mercury_deep_copy.h"
+#include "help.h"
+#include "io.h"
+#include <stdio.h>
+
+static Word MR_trace_help_system;
+static Word MR_trace_help_system_type;
+static Word MR_trace_help_stdout;
+
+static const char *MR_trace_help_add_node(Word path, const char *name,
+ int slot, const char *text);
+static void MR_trace_help_ensure_init(void);
+static void MR_trace_help_make_permanent(void);
+
+const char *
+MR_trace_add_cat(const char *category, int slot, const char *text)
+{
+ Word path;
+
+ MR_trace_help_ensure_init();
+ path = list_empty();
+ return MR_trace_help_add_node(path, category, slot, text);
+}
+
+const char *
+MR_trace_add_item(const char *category, const char *item, int slot,
+ const char *text)
+{
+ Word path;
+
+ MR_trace_help_ensure_init();
+ path = list_empty();
+ path = list_cons(category, path);
+ return MR_trace_help_add_node(path, item, slot, text);
+}
+
+static const char *
+MR_trace_help_add_node(Word path, const char *name, int slot, const char *text)
+{
+ Word result;
+ char *msg;
+
+ ML_HELP_add_help_node(MR_trace_help_system, path, slot,
+ (String) (Word) name, (String) (Word) text,
+ &result, &MR_trace_help_system);
+ MR_trace_help_make_permanent();
+ if (ML_HELP_result_is_error(result, &msg)) {
+ return msg;
+ } else {
+ return NULL;
+ }
+}
+
+void
+MR_trace_help(void)
+{
+ MR_trace_help_ensure_init();
+ ML_HELP_help(MR_trace_help_system, MR_trace_help_stdout);
+}
+
+void
+MR_trace_help_word(const char *word)
+{
+ MR_trace_help_ensure_init();
+ ML_HELP_name(MR_trace_help_system, (String) (Word) word,
+ MR_trace_help_stdout);
+}
+
+void
+MR_trace_help_cat_item(const char *category, const char *item)
+{
+ Word path;
+ Word result;
+ char *msg;
+
+ MR_trace_help_ensure_init();
+ path = list_empty();
+ path = list_cons(item, path);
+ path = list_cons(category, path);
+ ML_HELP_path(MR_trace_help_system, path, MR_trace_help_stdout, &result);
+ if (ML_HELP_result_is_error(result, &msg)) {
+ printf("internal error in the trace help system: %s\n", msg);
+ }
+}
+
+static void
+MR_trace_help_ensure_init(void)
+{
+ static bool MR_trace_help_init_done = FALSE;
+
+ if (! MR_trace_help_init_done) {
+ ML_HELP_init(&MR_trace_help_system);
+ ML_HELP_help_system_type(&MR_trace_help_system_type);
+ MR_trace_help_make_permanent();
+ ML_io_stdout_stream(&MR_trace_help_stdout);
+ MR_trace_help_init_done = TRUE;
+ }
+}
+
+static void
+MR_trace_help_make_permanent(void)
+{
+ save_transient_registers();
+ MR_trace_help_system = MR_make_permanent(MR_trace_help_system,
+ MR_trace_help_system_type);
+ restore_transient_registers();
+}
Index: trace/mercury_trace_help.h
===================================================================
RCS file: mercury_trace_help.h
diff -N mercury_trace_help.h
--- /dev/null Wed May 28 10:49:58 1997
+++ mercury_trace_help.h Tue Sep 22 12:30:04 1998
RECAST MERCURY_TRACE_UTIL AS MERCURY_LAYOUT_UTIL
@@ -0,0 +1,43 @@
+/*
+** Copyright (C) 1998 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_trace_help.h
+**
+** Defines the interface of the help system for the internal debugger.
+*/
+
+#ifndef MERCURY_TRACE_HELP_H
+#define MERCURY_TRACE_HELP_H
+
+/*
+** These function add a help node, which must a category or an item
+** within a category. It returns NULL if the addition was successful,
+** and a pointer to an error message otherwise.
+*/
+
+extern const char *MR_trace_add_cat(const char *category, int slot,
+ const char *text);
+
+extern const char *MR_trace_add_item(const char *category,
+ const char *item, int slot, const char *text);
+
+/*
+** These functions print help to standard output.
+**
+** MR_trace_help prints a list of the top-level help nodes.
+** MR_trace_help_word prints the text of all the help nodes with the given
+** name. If there are none, it prints a list of the top-level help nodes.
+** MR_trace_help_cat_item prints the text of the node at path cat/item.
+*/
+
+extern void MR_trace_help(void);
+extern void MR_trace_help_word(const char *word);
+
+extern void MR_trace_help_cat_item(const char *cat,
+ const char *item);
+
+#endif /* MERCURY_TRACE_HELP_H */
Index: trace/mercury_trace_internal.c
<the whole file is smaller and much more readable than the diff>
IMPLEMENT NEW DEBUGGER COMMAND SET
SUPPORT RETRY
ADD REDO EVENTS
ADD TRACE DEPTH HISTOGRAMS
/*
** Copyright (C) 1998 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 file contains the code of the internal, in-process debugger.
**
** Main author: Zoltan Somogyi.
*/
#include "mercury_imp.h"
#include "mercury_trace.h"
#include "mercury_trace_internal.h"
#include "mercury_trace_alias.h"
#include "mercury_trace_help.h"
#include "mercury_trace_spy.h"
#include "mercury_trace_tables.h"
#include "mercury_layout_util.h"
#include "mercury_macros.h"
#include "mercury_getopt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* The initial size of the spy points table. */
#define MR_INIT_SPY_POINTS 10
/* The initial size of arrays of argument values. */
#define MR_INIT_ARG_COUNT 20
/* The initial size of arrays of words. */
#define MR_INIT_WORD_COUNT 20
/* The initial size of arrays of characters. */
#define MR_INIT_BUF_LEN 80
/* The initial number of lines in documentation entries. */
#define MR_INIT_DOC_CHARS 800
#define MDBRC_FILENAME ".mdbrc"
#define DEFAULT_MDBRC_FILENAME "mdbrc"
/* XXX We should consider whether the following should be thread local. */
static MR_Spy_Point **MR_spy_points;
static int MR_spy_point_next = 0;
static int MR_spy_point_max = 0;
static MR_Trace_Print_Level MR_default_print_level = MR_PRINT_LEVEL_SOME;
static bool MR_scroll_control = FALSE;
static int MR_scroll_next = 0;
static int MR_scroll_limit = 24;
static bool MR_echo_commands = FALSE;
static int MR_trace_saved_call_seqno;
static int MR_trace_saved_call_depth;
static int MR_trace_saved_event_number;
typedef struct MR_Line_Struct {
char *MR_line_contents;
struct MR_Line_Struct *MR_line_next;
} MR_Line;
static MR_Line *MR_line_head = NULL;
static MR_Line *MR_line_tail = NULL;
typedef enum {
KEEP_INTERACTING,
STOP_INTERACTING
} MR_Next;
static void MR_trace_internal_ensure_init(void);
static bool MR_trace_internal_init_from_env(const char *env_var);
static bool MR_trace_internal_init_from_file(const char *filename);
static bool MR_trace_internal_init_from_env_dir(const char *env_var,
const char *filename);
static MR_Next MR_trace_debug_cmd(char *line, MR_Trace_Cmd_Info *cmd,
const MR_Stack_Layout_Label *layout,
Word *saved_regs, MR_Trace_Port port,
int seqno, int depth, const char *path,
int *ancestor_level, int *max_mr_num, Code **jumpaddr);
static bool MR_trace_options_strict_print(MR_Trace_Cmd_Info *cmd,
char ***words, int *word_count,
const char *cat, const char *item);
static bool MR_trace_options_when_action(MR_Spy_When *when,
MR_Spy_Action *action, char ***words, int *word_count,
const char *cat, const char *item);
static bool MR_trace_options_quiet(bool *verbose,
char ***words, int *word_count,
const char *cat, const char *item);
static bool MR_trace_options_confirmed(bool *confirmed, char ***words,
int *word_count, const char *cat, const char *item);
static void MR_trace_retry(const MR_Stack_Layout_Label *layout,
Word *saved_regs, int seqno, int depth,
int *max_mr_num, Code **jumpaddr);
static Word MR_trace_find_input_arg(const MR_Stack_Layout_Label *label,
Word *saved_regs, const char *name, bool *succeeded);
static void MR_trace_internal_add_spy_point(MR_Spy_When when,
MR_Spy_Action action,
const MR_Stack_Layout_Entry *entry,
const MR_Stack_Layout_Label *label, const char *path);
static void MR_print_spy_point(int i);
static void MR_trace_list_vars(const MR_Stack_Layout_Label *top_layout,
Word *saved_regs, int ancestor_level);
static const char *MR_trace_browse_check_level(const MR_Stack_Layout_Label
*top_layout, Word *saved_regs, int ancestor_level);
static void MR_trace_browse_one(const MR_Stack_Layout_Label *top_layout,
Word *saved_regs, int ancestor_level, int which_var);
static void MR_trace_browse_all(const MR_Stack_Layout_Label *top_layout,
Word *saved_regs, int ancestor_level);
static void MR_trace_browse_var(const char *name,
const MR_Stack_Layout_Var *var,
Word *saved_regs, Word *base_sp, Word *base_curfr,
Word *type_params);
static const char *MR_trace_read_help_text(void);
static bool MR_trace_is_number(char *word, int *value);
static bool MR_trace_is_number_prefix(char *word, char **suffix,
int *value);
static const char *MR_trace_parse_line(char *line,
char ***words, int *word_max, int *word_count);
static int MR_trace_break_into_words(char *line,
char ***words_ptr, int *word_max_ptr);
static void MR_trace_source(const char *filename);
static void MR_trace_source_from_open_file(FILE *fp);
static char *MR_trace_getline(const char *prompt, FILE *fp);
static char *MR_trace_getline_queue(void);
static char *MR_trace_getline_raw(FILE *fp);
static void MR_insert_line_at_head(const char *line);
static void MR_insert_line_at_tail(const char *line);
static Code *MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
const MR_Stack_Layout_Label *layout, Word *saved_regs,
MR_Trace_Port port, int seqno, int depth,
const char *path, int *max_mr_num);
static void MR_trace_event_print_internal_report(
const MR_Stack_Layout_Label *layout,
MR_Trace_Port port, int seqno, int depth,
const char *path);
static void MR_trace_print_port(MR_Trace_Port port);
static bool MR_trace_valid_command(const char *word);
Code *
MR_trace_event_internal(MR_Trace_Cmd_Info *cmd, bool interactive,
const MR_Stack_Layout_Label *layout, Word *saved_regs,
MR_Trace_Port port, int seqno, int depth,
const char *path, int *max_mr_num)
{
int i;
int c;
int count;
bool count_given;
int ancestor_level;
Code *jumpaddr;
char *line;
MR_Next res;
if (! interactive) {
return MR_trace_event_internal_report(cmd, layout, saved_regs,
port, seqno, depth, path, max_mr_num);
}
MR_trace_enabled = FALSE;
MR_trace_internal_ensure_init();
MR_trace_event_print_internal_report(layout, port, seqno, depth, path);
/*
** These globals can be overwritten when we call Mercury code,
** such as the term browser. We therefore save and restore them
** across calls to MR_trace_debug_cmd. However, we store the
** saved values in global instead of local variables, to allow them
** to be modified by MR_trace_retry().
*/
MR_trace_saved_call_seqno = MR_trace_call_seqno;
MR_trace_saved_call_depth = MR_trace_call_depth;
MR_trace_saved_event_number = MR_trace_event_number;
/* by default, print variables from the current call */
ancestor_level = 0;
/* by default, return where we came from */
jumpaddr = NULL;
do {
line = MR_trace_getline("mdb> ", stdin);
res = MR_trace_debug_cmd(line, cmd, layout, saved_regs,
port, seqno, depth, path,
&ancestor_level, max_mr_num, &jumpaddr);
} while (res == KEEP_INTERACTING);
cmd->MR_trace_must_check = (! cmd->MR_trace_strict) ||
(cmd->MR_trace_print_level != MR_PRINT_LEVEL_NONE);
MR_trace_call_seqno = MR_trace_saved_call_seqno;
MR_trace_call_depth = MR_trace_saved_call_depth;
MR_trace_event_number = MR_trace_saved_event_number;
MR_scroll_next = 0;
MR_trace_enabled = TRUE;
return jumpaddr;
}
static const char MR_trace_banner[] =
"Melbourne Mercury Debugger, mdb version 0.8.\n\
Copyright 1998 University of Melbourne, Australia.\n\
mdb is free software, covered by the GNU General Public License.\n\
There is absolutely no warranty for mdb.\n";
static bool MR_trace_internal_initialized = FALSE;
static void
MR_trace_internal_ensure_init(void)
{
if (! MR_trace_internal_initialized) {
char *env;
int n;
printf(MR_trace_banner);
env = getenv("LINES");
if (env != NULL && MR_trace_is_number(env, &n)) {
MR_scroll_limit = n;
}
MR_trace_internal_init_from_env("MERCURY_DEBUGGER_INIT") ||
MR_trace_internal_init_from_file(MDBRC_FILENAME) ||
MR_trace_internal_init_from_env_dir("HOME", MDBRC_FILENAME) ||
MR_trace_internal_init_from_env("DEFAULT_MERCURY_DEBUGGER_INIT");
MR_trace_internal_initialized = TRUE;
}
}
static bool
MR_trace_internal_init_from_env(const char *env_var)
{
char *init;
init = getenv(env_var);
if (init != NULL) {
MR_trace_source(init);
return TRUE;
} else {
return FALSE;
}
}
static bool
MR_trace_internal_init_from_file(const char *filename)
{
FILE *fp;
if ((fp = fopen(filename, "r")) != NULL) {
MR_trace_source_from_open_file(fp);
fclose(fp);
return TRUE;
} else {
return FALSE;
}
}
static bool
MR_trace_internal_init_from_env_dir(const char *env_var, const char *filename)
{
char *env;
char *buf;
int len;
FILE *fp;
env = getenv(env_var);
if (env == NULL) {
return FALSE;
}
buf = checked_malloc(strlen(env) + strlen(filename) + 2);
(void) strcpy(buf, env);
(void) strcat(buf, "/");
(void) strcat(buf, filename);
if ((fp = fopen(buf, "r")) != NULL) {
MR_trace_source_from_open_file(fp);
fclose(fp);
free(buf);
return TRUE;
} else {
free(buf);
return FALSE;
}
}
static MR_Next
MR_trace_debug_cmd(char *line, MR_Trace_Cmd_Info *cmd,
const MR_Stack_Layout_Label *layout, Word *saved_regs,
MR_Trace_Port port, int seqno, int depth, const char *path,
int *ancestor_level, int *max_mr_num, Code **jumpaddr)
{
char **words;
char **orig_words;
int word_max;
int word_count;
const char *alias_key;
char **alias_words;
int alias_word_count;
int alias_copy_start;
const char *problem;
char *semicolon;
int i;
int n;
if (line == NULL) {
/*
** We got an EOF.
** We arrange things so we don't have to treat this case
** specially in the command interpreter below.
*/
line = MR_copy_string("quit");
}
if (MR_echo_commands) {
fputs(line, stdout);
putc('\n', stdout);
}
if ((semicolon = strchr(line, ';')) != NULL) {
/*
** The line contains at least two commands.
** Execute only the first command now; put the others
** back in the input to be processed later.
*/
*semicolon = '\0';
MR_insert_line_at_head(MR_copy_string(semicolon+1));
}
problem = MR_trace_parse_line(line, &words, &word_max, &word_count);
if (problem != NULL) {
printf("%s\n", problem);
goto return_keep_interacting;
}
if (word_count == 0) {
alias_key = "EMPTY";
alias_copy_start = 0;
} else if (MR_trace_is_number(words[0], &n)) {
alias_key = "NUMBER";
alias_copy_start = 0;
} else {
alias_key = words[0];
alias_copy_start = 1;
}
if (MR_trace_lookup_alias(alias_key, &alias_words, &alias_word_count))
{
MR_ensure_big_enough(alias_word_count, word, const char *,
MR_INIT_WORD_COUNT);
/* Move the original words (except the alias key) up. */
for (i = word_count - 1; i >= alias_copy_start; i--) {
words[i + alias_word_count - alias_copy_start]
= words[i];
}
/* Move the alias body to the words array. */
for (i = 0; i < alias_word_count; i++) {
words[i] = alias_words[i];
}
word_count += alias_word_count - alias_copy_start;
}
/*
** At this point, the first word_count members of the words
** array contain the command. We save the value of words for
** freeing just before return, since the variable words itself
** can be overwritten by option processing.
*/
orig_words = words;
if (word_count == 0) {
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = MR_trace_event_number + 1;
cmd->MR_trace_strict = FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
goto return_stop_interacting;
} else if (MR_trace_is_number(words[0], &n)) {
if (word_count == 1) {
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = MR_trace_event_number + n;
cmd->MR_trace_strict = FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
goto return_stop_interacting;
} else {
printf("One of the first two words "
"must be a command.\n");
}
} else if (streq(words[0], "step")) {
cmd->MR_trace_strict = FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "step")) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = MR_trace_event_number + 1;
goto return_stop_interacting;
} else if (word_count == 2
&& MR_trace_is_number(words[1], &n)) {
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = MR_trace_event_number + n;
goto return_stop_interacting;
} else {
MR_trace_help_cat_item("forward", "step");
}
} else if (streq(words[0], "goto")) {
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "goto")) {
; /* the usage message has already been printed */
} else if (word_count == 2 && MR_trace_is_number(words[1], &n))
{
if (MR_trace_event_number < n) {
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = n;
goto return_stop_interacting;
} else {
printf("The debugger cannot go "
"to a past event.\n");
}
} else {
MR_trace_help_cat_item("forward", "goto");
}
} else if (streq(words[0], "finish")) {
int stop_depth;
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "finish")) {
; /* the usage message has already been printed */
goto return_keep_interacting;
} else if (word_count == 2 && MR_trace_is_number(words[1], &n))
{
stop_depth = depth - n;
} else if (word_count == 1) {
stop_depth = depth;
} else {
MR_trace_help_cat_item("forward", "finish");
goto return_keep_interacting;
}
if (depth == stop_depth && MR_port_is_final(port)) {
printf("This command is a no-op from this port.\n");
} else {
cmd->MR_trace_cmd = MR_CMD_FINISH;
cmd->MR_trace_stop_depth = stop_depth;
goto return_stop_interacting;
}
} else if (streq(words[0], "return")) {
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "return")) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
if (port == MR_PORT_EXIT) {
cmd->MR_trace_cmd = MR_CMD_RETURN;
goto return_stop_interacting;
} else {
printf("This command is a no-op from this port.\n");
}
} else {
MR_trace_help_cat_item("forward", "return");
}
} else if (streq(words[0], "forward")) {
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "forward")) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
if (port == MR_PORT_FAIL || port == MR_PORT_REDO) {
cmd->MR_trace_cmd = MR_CMD_RESUME_FORWARD;
goto return_stop_interacting;
} else {
printf("This command is a no-op from this port.\n");
}
} else {
MR_trace_help_cat_item("forward", "forward");
}
} else if (streq(words[0], "mindepth")) {
int newdepth;
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "mindepth")) {
; /* the usage message has already been printed */
} else if (word_count == 2 &&
MR_trace_is_number(words[1], &newdepth))
{
cmd->MR_trace_cmd = MR_CMD_MIN_DEPTH;
cmd->MR_trace_stop_depth = newdepth;
goto return_stop_interacting;
} else {
MR_trace_help_cat_item("forward", "mindepth");
}
} else if (streq(words[0], "maxdepth")) {
int newdepth;
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_default_print_level;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "maxdepth")) {
; /* the usage message has already been printed */
} else if (word_count == 2 &&
MR_trace_is_number(words[1], &newdepth))
{
cmd->MR_trace_cmd = MR_CMD_MAX_DEPTH;
cmd->MR_trace_stop_depth = newdepth;
goto return_stop_interacting;
} else {
MR_trace_help_cat_item("forward", "maxdepth");
}
} else if (streq(words[0], "continue")) {
cmd->MR_trace_strict = FALSE;
cmd->MR_trace_print_level = (MR_Trace_Cmd_Type) -1;
if (! MR_trace_options_strict_print(cmd, &words, &word_count,
"forward", "continue")) {
; /* 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 ==
(MR_Trace_Cmd_Type) -1) {
/*
** 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;
}
}
goto return_stop_interacting;
} else {
MR_trace_help_cat_item("forward", "continue");
}
} else if (streq(words[0], "retry")) {
int stop_depth;
if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
stop_depth = depth - n;
} else if (word_count == 1) {
stop_depth = depth;
} else {
MR_trace_help_cat_item("backward", "retry");
goto return_keep_interacting;
}
if (stop_depth == depth && MR_port_is_final(port)) {
MR_trace_retry(layout, saved_regs, seqno, depth,
max_mr_num, jumpaddr);
cmd->MR_trace_cmd = MR_CMD_GOTO;
cmd->MR_trace_stop_event = MR_trace_event_number + 1;
cmd->MR_trace_strict = FALSE;
cmd->MR_trace_print_level = MR_default_print_level;
goto return_stop_interacting;
} else {
char *retry_cmd;
/* Finish the call to be retried. */
cmd->MR_trace_cmd = MR_CMD_FINISH;
cmd->MR_trace_stop_depth = stop_depth;
cmd->MR_trace_strict = TRUE;
cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
/* Arrange to retry the call once it is finished. */
MR_insert_line_at_head("retry");
goto return_stop_interacting;
}
} else if (streq(words[0], "level")) {
if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
problem = MR_trace_browse_check_level(layout,
saved_regs, n);
if (problem == NULL) {
*ancestor_level = n;
printf("Ancestor level set to %d\n",
*ancestor_level);
} else {
printf("%s\n", problem);
}
} else {
MR_trace_help_cat_item("browsing", "level");
}
} else if (streq(words[0], "up")) {
if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
problem = MR_trace_browse_check_level(layout,
saved_regs, *ancestor_level + n);
if (problem == NULL) {
*ancestor_level += n;
printf("Ancestor level set to %d\n",
*ancestor_level);
} else {
printf("%s\n", problem);
}
} else if (word_count == 1) {
problem = MR_trace_browse_check_level(layout,
saved_regs, *ancestor_level + 1);
if (problem == NULL) {
*ancestor_level += 1;
printf("Ancestor level set to %d\n",
*ancestor_level);
} else {
printf("%s\n", problem);
}
} else {
MR_trace_help_cat_item("browsing", "up");
}
} else if (streq(words[0], "down")) {
if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
problem = MR_trace_browse_check_level(layout,
saved_regs, *ancestor_level - n);
if (problem == NULL) {
*ancestor_level -= n;
printf("Ancestor level set to %d\n",
*ancestor_level);
} else {
printf("%s\n", problem);
}
} else if (word_count == 1) {
problem = MR_trace_browse_check_level(layout,
saved_regs, *ancestor_level - 1);
if (problem == NULL) {
*ancestor_level -= 1;
printf("Ancestor level set to %d\n",
*ancestor_level);
} else {
printf("%s\n", problem);
}
} else {
MR_trace_help_cat_item("browsing", "down");
}
} else if (streq(words[0], "vars")) {
if (word_count == 1) {
MR_trace_list_vars(layout, saved_regs,
*ancestor_level);
} else {
MR_trace_help_cat_item("browsing", "vars");
}
} else if (streq(words[0], "print")) {
if (word_count == 2) {
if (MR_trace_is_number(words[1], &n)) {
MR_trace_browse_one(layout, saved_regs,
*ancestor_level, n);
} else if streq(words[1], "*") {
MR_trace_browse_all(layout, saved_regs,
*ancestor_level);
} else {
MR_trace_help_cat_item("browsing", "print");
}
} else {
MR_trace_help_cat_item("browsing", "print");
}
} else if (streq(words[0], "stack")) {
if (word_count == 1) {
const char *result;
do_init_modules();
result = MR_dump_stack_from_layout(stdout,
layout->MR_sll_entry,
MR_saved_sp(saved_regs),
MR_saved_curfr(saved_regs));
if (result != NULL) {
printf("%s\n", result);
}
} else {
MR_trace_help_cat_item("browsing", "stack");
}
} else if (streq(words[0], "current")) {
if (word_count == 1) {
MR_trace_event_print_internal_report(layout, port,
seqno, depth, path);
} else {
MR_trace_help_cat_item("browsing", "current");
}
} else if (streq(words[0], "break")) {
MR_Proc_Spec spec;
MR_Spy_When when;
MR_Spy_Action action;
if (word_count == 2 && streq(words[1], "info")) {
for (i = 0; i < MR_spy_point_next; i++) {
MR_print_spy_point(i);
}
goto return_keep_interacting;
}
when = MR_SPY_INTERFACE;
action = MR_SPY_STOP;
if (! MR_trace_options_when_action(&when, &action,
&words, &word_count, "breakpoint", "break")) {
; /* the usage message has already been printed */
} else if (word_count == 2 && streq(words[1], "here")) {
MR_register_all_modules_and_procs(stdout, TRUE);
MR_trace_internal_add_spy_point(MR_SPY_SPECIFIC,
action, layout->MR_sll_entry, layout, path);
} else if (word_count == 2 &&
MR_parse_proc_spec(words[1], &spec))
{
const MR_Stack_Layout_Entry *spy_proc;
bool unique;
MR_register_all_modules_and_procs(stdout, TRUE);
spy_proc = MR_search_for_matching_procedure(&spec,
&unique);
if (spy_proc != NULL) {
if (unique) {
MR_trace_internal_add_spy_point(when,
action, spy_proc, NULL, path);
} else {
printf("Ambiguous procedure "
"specification. "
"The matches are:\n");
MR_process_matching_procedures(&spec,
MR_print_proc_id_for_debugger);
}
} else {
printf("There is no such procedure.\n");
}
} else {
MR_trace_help_cat_item("breakpoint", "break");
}
} else if (streq(words[0], "enable")) {
if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
if (0 <= n && n < MR_spy_point_next) {
MR_spy_points[n]->spy_enabled = TRUE;
MR_print_spy_point(n);
} else {
printf("Break point #%d does not exist.\n", n);
}
} else if (word_count == 2 && streq(words[1], "*")) {
for (i = 0; i < MR_spy_point_next; i++) {
MR_spy_points[i]->spy_enabled = TRUE;
MR_print_spy_point(n);
}
if (MR_spy_point_next == 0) {
printf("There no break points yet.\n");
}
} else {
MR_trace_help_cat_item("breakpoint", "enable");
}
} else if (streq(words[0], "disable")) {
if (word_count == 2 && MR_trace_is_number(words[1], &n)) {
if (0 <= n && n < MR_spy_point_next) {
MR_spy_points[n]->spy_enabled = FALSE;
MR_print_spy_point(n);
} else {
printf("Break point #%d does not exist.\n", n);
}
} else if (word_count == 2 && streq(words[1], "*")) {
for (i = 0; i < MR_spy_point_next; i++) {
MR_spy_points[i]->spy_enabled = FALSE;
MR_print_spy_point(n);
}
if (MR_spy_point_next == 0) {
printf("There no break points yet.\n");
}
} else {
MR_trace_help_cat_item("breakpoint", "disable");
}
} else if (streq(words[0], "register")) {
bool verbose;
if (! MR_trace_options_quiet(&verbose, &words, &word_count,
"breakpoint", "register")) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
MR_register_all_modules_and_procs(stdout, verbose);
} else {
MR_trace_help_cat_item("breakpoint", "register");
}
} else if (streq(words[0], "modules")) {
if (word_count == 1) {
MR_register_all_modules_and_procs(stdout, TRUE);
MR_dump_module_list(stdout);
} else {
MR_trace_help_cat_item("breakpoint", "modules");
}
} else if (streq(words[0], "procedures")) {
if (word_count == 2) {
MR_register_all_modules_and_procs(stdout, TRUE);
MR_dump_module_procs(stdout, words[1]);
} else {
MR_trace_help_cat_item("breakpoint", "procedures");
}
} else if (streq(words[0], "printlevel")) {
if (word_count == 2) {
if (streq(words[1], "none")) {
MR_default_print_level = MR_PRINT_LEVEL_NONE;
printf("Default print level set to none.\n");
} else if (streq(words[1], "some")) {
MR_default_print_level = MR_PRINT_LEVEL_SOME;
printf("Default print level set to some.\n");
} else if (streq(words[1], "all")) {
MR_default_print_level = MR_PRINT_LEVEL_ALL;
printf("Default print level set to all.\n");
} else {
MR_trace_help_cat_item("parameter", "printlevel");
}
} else if (word_count == 1) {
printf("The default print level is ");
switch (MR_default_print_level) {
case MR_PRINT_LEVEL_NONE:
printf("none.\n");
break;
case MR_PRINT_LEVEL_SOME:
printf("some.\n");
break;
case MR_PRINT_LEVEL_ALL:
printf("all.\n");
break;
default:
printf("something weird.\n");
break;
}
} else {
MR_trace_help_cat_item("parameter", "printlevel");
}
} else if (streq(words[0], "scroll")) {
if (word_count == 2) {
if (streq(words[1], "off")) {
MR_scroll_control = FALSE;
printf("Scroll control disabled\n");
} else if (streq(words[1], "on")) {
MR_scroll_control = TRUE;
printf("Scroll control enabled\n");
} else if (MR_trace_is_number(words[1], &n)) {
MR_scroll_limit = n;
printf("Scroll window size set to %d\n",
MR_scroll_limit);
} else {
MR_trace_help_cat_item("parameter", "scroll");
}
} else if (word_count == 1) {
printf("Scroll control is ");
if (MR_scroll_control) {
printf("on");
} else {
printf("off");
}
printf(", scroll window size is %d\n", MR_scroll_limit);
} else {
MR_trace_help_cat_item("parameter", "scroll");
}
} else if (streq(words[0], "echo")) {
if (word_count == 2) {
if (streq(words[1], "off")) {
MR_echo_commands = FALSE;
printf("Command echo disabled\n");
} else if (streq(words[1], "on")) {
MR_echo_commands = TRUE;
printf("Command echo enabled\n");
} else {
MR_trace_help_cat_item("parameter", "echo");
}
} else if (word_count == 1) {
printf("Command echo is ");
if (MR_echo_commands) {
printf("on.\n");
} else {
printf("off.\n");
}
} else {
MR_trace_help_cat_item("parameter", "echo");
}
} else if (streq(words[0], "alias")) {
if (word_count == 1) {
MR_trace_print_all_aliases(stdout);
} else if (word_count == 2) {
MR_trace_print_alias(stdout, words[1]);
} else {
if (MR_trace_valid_command(words[2])) {
MR_trace_add_alias(words[1],
words+2, word_count-2);
MR_trace_print_alias(stdout, words[1]);
} else {
printf("%s is not a valid command\n", words[2]);
}
}
} else if (streq(words[0], "unalias")) {
if (word_count == 2) {
if (MR_trace_remove_alias(words[1])) {
printf("Alias %s removed.\n", words[1]);
} else {
printf("Alias %s cannot be removed, since it does not exist.\n", words[1]);
}
} else {
MR_trace_help_cat_item("parameter", "unalias");
}
} else if (streq(words[0], "document_category")) {
int slot;
const char *msg;
const char *help_text;
help_text = MR_trace_read_help_text();
if (word_count != 3) {
MR_trace_help_cat_item("help", "document_category");
} else if (! MR_trace_is_number(words[1], &slot)) {
MR_trace_help_cat_item("help", "document_category");
} else {
msg = MR_trace_add_cat(words[2], slot, help_text);
if (msg != NULL) {
printf("Document category %s not added: %s.\n",
words[2], msg);
}
}
} else if (streq(words[0], "document")) {
int slot;
const char *msg;
const char *help_text;
help_text = MR_trace_read_help_text();
if (word_count != 4) {
MR_trace_help_cat_item("help", "document");
} else if (! MR_trace_is_number(words[2], &slot)) {
MR_trace_help_cat_item("help", "document");
} else {
msg = MR_trace_add_item(words[1], words[3], slot,
help_text);
if (msg != NULL) {
printf("Document item %s in category %s"
" not added: %s.\n",
words[3], words[1], msg);
}
}
} else if (streq(words[0], "help")) {
if (word_count == 1) {
MR_trace_help();
} else if (word_count == 2) {
MR_trace_help_word(words[1]);
} else if (word_count == 3) {
MR_trace_help_cat_item(words[1], words[2]);
} else {
MR_trace_help_cat_item("misc", "help");
}
} else if (streq(words[0], "histogram_all")) {
if (word_count == 2) {
FILE *fp;
fp = fopen(words[1], "w");
if (fp == NULL) {
perror(words[1]);
} else {
MR_trace_print_histogram(fp, "All-inclusive",
MR_trace_histogram_all,
MR_trace_histogram_hwm);
fclose(fp);
}
} else {
MR_trace_help_cat_item("exp", "histogram_all");
}
} else if (streq(words[0], "histogram_exp")) {
if (word_count == 2) {
FILE *fp;
if (fp == NULL) {
perror(words[1]);
} else {
MR_trace_print_histogram(fp, "Experimental",
MR_trace_histogram_exp,
MR_trace_histogram_hwm);
fclose(fp);
}
} else {
MR_trace_help_cat_item("exp", "histogram_exp");
}
} else if (streq(words[0], "clear_histogram")) {
if (word_count == 1) {
for (i = 0; i <= MR_trace_histogram_hwm; i++) {
MR_trace_histogram_exp[i] = 0;
}
} else {
MR_trace_help_cat_item("exp", "clear_histogram");
}
} else if (streq(words[0], "nondet_stack")) {
if (word_count == 1) {
do_init_modules();
MR_dump_nondet_stack_from_layout(stdout,
MR_saved_maxfr(saved_regs));
} else {
MR_trace_help_cat_item("developer", "nondet_stack");
}
} else if (streq(words[0], "stack_regs")) {
if (word_count == 1) {
printf("sp = %p, curfr = %p, maxfr = %p\n",
MR_saved_sp(saved_regs),
MR_saved_curfr(saved_regs),
MR_saved_maxfr(saved_regs));
} else {
MR_trace_help_cat_item("developer", "stack_regs");
}
} else if (streq(words[0], "source")) {
if (word_count == 2) {
MR_trace_source(words[1]);
} else {
MR_trace_help_cat_item("misc", "source");
}
} else if (streq(words[0], "quit")) {
bool confirmed;
confirmed = FALSE;
if (! MR_trace_options_confirmed(&confirmed,
&words, &word_count, "misc", "quit")) {
; /* the usage message has already been printed */
} else if (word_count == 1) {
if (! confirmed) {
char *line2;
line2 = MR_trace_getline(
"mdb: are you sure you want to quit? ",
stdin);
if (line2 == NULL) {
/* This means the user input EOF. */
confirmed = TRUE;
} else {
i = 0;
while (line2[i] != '\0' &&
MR_isspace(line2[i]))
{
i++;
}
if (line2[i] == 'y' || line2[i] == 'Y')
{
confirmed = TRUE;
}
free(line2);
}
}
if (confirmed) {
exit(EXIT_SUCCESS);
}
} else {
MR_trace_help_cat_item("misc", "quit");
}
} else {
printf("Unknown command `%s'. "
"Give the command `help' for help.\n", words[0]);
}
/* fall through */
return_keep_interacting:
free(line);
free(orig_words);
return KEEP_INTERACTING;
return_stop_interacting:
free(line);
free(orig_words);
return STOP_INTERACTING;
}
static struct MR_option MR_trace_strict_print_opts[] =
{
{ "all", FALSE, NULL, 'a' },
{ "none", FALSE, NULL, 'n' },
{ "some", FALSE, NULL, 's' },
{ "nostrict", FALSE, NULL, 'N' },
{ "strict", FALSE, NULL, 'S' }
};
static bool
MR_trace_options_strict_print(MR_Trace_Cmd_Info *cmd,
char ***words, int *word_count, const char *cat, const char *item)
{
int c;
MR_optind = 0;
while ((c = MR_getopt_long(*word_count, *words, "NSans",
MR_trace_strict_print_opts, NULL)) != EOF)
{
switch (c) {
case 'N':
cmd->MR_trace_strict = FALSE;
break;
case 'S':
cmd->MR_trace_strict = TRUE;
break;
case 'a':
cmd->MR_trace_print_level = MR_PRINT_LEVEL_ALL;
break;
case 'n':
cmd->MR_trace_print_level = MR_PRINT_LEVEL_NONE;
break;
case 's':
cmd->MR_trace_print_level = MR_PRINT_LEVEL_SOME;
break;
default:
MR_trace_help_cat_item(cat, item);
return FALSE;
}
}
*words = *words + MR_optind - 1;
*word_count = *word_count - MR_optind + 1;
return TRUE;
}
static struct MR_option MR_trace_when_action_opts[] =
{
{ "all", FALSE, NULL, 'a' },
{ "entry", FALSE, NULL, 'e' },
{ "interface", FALSE, NULL, 'i' },
{ "print", FALSE, NULL, 'P' },
{ "stop", FALSE, NULL, 'S' }
};
static bool
MR_trace_options_when_action(MR_Spy_When *when, MR_Spy_Action *action,
char ***words, int *word_count, const char *cat, const char *item)
{
int c;
MR_optind = 0;
while ((c = MR_getopt_long(*word_count, *words, "PSaei",
MR_trace_when_action_opts, NULL)) != EOF)
{
switch (c) {
case 'a':
*when = MR_SPY_ALL;
break;
case 'e':
*when = MR_SPY_ENTRY;
break;
case 'i':
*when = MR_SPY_INTERFACE;
break;
case 'P':
*action = MR_SPY_PRINT;
break;
case 'S':
*action = MR_SPY_STOP;
break;
default:
MR_trace_help_cat_item(cat, item);
return FALSE;
}
}
*words = *words + MR_optind - 1;
*word_count = *word_count - MR_optind + 1;
return TRUE;
}
static bool
MR_trace_options_confirmed(bool *confirmed, char ***words, int *word_count,
const char *cat, const char *item)
{
int c;
MR_optind = 0;
while ((c = MR_getopt(*word_count, *words, "NYny")) != EOF) {
switch (c) {
case 'n':
case 'N':
*confirmed = FALSE;
break;
case 'y':
case 'Y':
*confirmed = TRUE;
break;
default:
MR_trace_help_cat_item(cat, item);
return FALSE;
}
}
*words = *words + MR_optind - 1;
*word_count = *word_count - MR_optind + 1;
return TRUE;
}
static struct MR_option MR_trace_quiet_opts[] =
{
{ "quiet", FALSE, NULL, 'q' },
{ "verbose", FALSE, NULL, 'v' }
};
static bool
MR_trace_options_quiet(bool *verbose, char ***words, int *word_count,
const char *cat, const char *item)
{
int c;
MR_optind = 0;
while ((c = MR_getopt_long(*word_count, *words, "qv",
MR_trace_quiet_opts, NULL)) != EOF)
{
switch (c) {
case 'q':
*verbose = FALSE;
break;
case 'v':
*verbose = TRUE;
break;
default:
MR_trace_help_cat_item(cat, item);
return FALSE;
}
}
*words = *words + MR_optind - 1;
*word_count = *word_count - MR_optind + 1;
return TRUE;
}
static void
MR_trace_retry(const MR_Stack_Layout_Label *this_label, Word *saved_regs,
int seqno, int depth, int *max_mr_num, Code **jumpaddr)
{
const MR_Stack_Layout_Entry *entry;
const MR_Stack_Layout_Label *call_label;
const MR_Stack_Layout_Vars *input_args;
Word *args;
int arg_max;
int arg_num;
Word arg_value;
int i;
bool succeeded;
entry = this_label->MR_sll_entry;
call_label = entry->MR_sle_call_label;
if (call_label->MR_sll_var_count < 0) {
printf("Cannot perform retry because information about "
"the input arguments is not available.\n");
return;
}
input_args = &call_label->MR_sll_var_info;
/*
** With the Boehm collector, args need not be considered a root,
** since its contents are just copies of values from elsewhere,
** With the native collector, it need not be considered a root
** because its lifetime spans only this function, in which
** no native garbage collection can be triggered.
*/
args = NULL;
arg_max = 0;
for (i = 0; i < call_label->MR_sll_var_count; i++) {
arg_value = MR_trace_find_input_arg(this_label, saved_regs,
input_args->MR_slvs_names[i], &succeeded);
if (! succeeded) {
printf("Cannot perform retry because the values of "
"some input arguments are missing.\n");
return;
}
arg_num = MR_get_register_number(
input_args->MR_slvs_pairs[i].MR_slv_locn);
if (arg_num > 0) {
MR_ensure_big_enough(arg_num, arg, Word,
MR_INIT_ARG_COUNT);
args[arg_num] = arg_value;
} else {
fatal_error("illegal location for input argument");
}
}
MR_trace_saved_call_seqno = seqno - 1;
MR_trace_saved_call_depth = depth - 1;
if (MR_DETISM_DET_STACK(entry->MR_sle_detism)) {
MR_Live_Lval location;
Word *this_frame;
/*
** We are at a final port, so both curfr and maxfr
** must already have been reset to their original values.
** We only need to set up the succip register for the "call",
** and then remove this frame from the det stack.
*/
location = entry->MR_sle_succip_locn;
if (MR_LIVE_LVAL_TYPE(location) != MR_LVAL_TYPE_STACKVAR) {
fatal_error("illegal location for stored succip");
}
this_frame = MR_saved_sp(saved_regs);
MR_saved_succip(saved_regs) = MR_based_stackvar(this_frame,
MR_LIVE_LVAL_NUMBER(location));
MR_saved_sp(saved_regs) -= entry->MR_sle_stack_slots;
MR_trace_saved_event_number =
MR_event_num_stackvar(this_frame);
} else {
Word *this_frame;
/*
** We are at a final port, so sp must already have been reset
** to its original value. We only need to set up the succip
** and curfr registers for the "call", and remove this frame,
** and any other frames above it, from the nondet stack.
*/
this_frame = MR_saved_curfr(saved_regs);
MR_saved_succip(saved_regs) = MR_succip_slot(this_frame);
MR_saved_curfr(saved_regs) = MR_succfr_slot(this_frame);
MR_saved_maxfr(saved_regs) = MR_prevfr_slot(this_frame);
MR_trace_saved_event_number =
MR_event_num_framevar(this_frame);
}
for (i = 1; i < arg_max; i++) {
saved_reg(saved_regs, i) = args[i];
}
if (args != NULL) {
free(args);
}
*max_mr_num = max(*max_mr_num, arg_max);
*jumpaddr = entry->MR_sle_code_addr;
MR_trace_call_seqno = MR_trace_saved_call_seqno;
MR_trace_call_depth = MR_trace_saved_call_depth;
MR_trace_event_number = MR_trace_saved_event_number;
}
static Word
MR_trace_find_input_arg(const MR_Stack_Layout_Label *label, Word *saved_regs,
const char *name, bool *succeeded)
{
const MR_Stack_Layout_Vars *vars;
int i;
vars = &label->MR_sll_var_info;
if (vars->MR_slvs_names == NULL) {
*succeeded = FALSE;
return 0;
}
for (i = 0; i < label->MR_sll_var_count; i++) {
if (streq(vars->MR_slvs_names[i], name)) {
return MR_lookup_live_lval_base(
vars->MR_slvs_pairs[i].MR_slv_locn, saved_regs,
MR_saved_sp(saved_regs),
MR_saved_curfr(saved_regs), succeeded);
}
}
*succeeded = FALSE;
return 0;
}
static void
MR_trace_internal_add_spy_point(MR_Spy_When when, MR_Spy_Action action,
const MR_Stack_Layout_Entry *entry, const MR_Stack_Layout_Label *label,
const char *path)
{
MR_Spy_Point *spy_point;
MR_ensure_room_for_next(MR_spy_point, MR_Spy_Point *,
MR_INIT_SPY_POINTS);
spy_point = MR_add_spy_point(when, action, entry, label, path);
MR_spy_points[MR_spy_point_next] = spy_point;
MR_print_spy_point(MR_spy_point_next);
MR_spy_point_next++;
}
static void
MR_print_spy_point(int spy_point_num)
{
printf("%2d: %1s %-5s %9s ",
spy_point_num,
MR_spy_points[spy_point_num]->spy_enabled ? "+" : "-",
MR_spy_action_string(MR_spy_points[spy_point_num]->spy_action),
MR_spy_when_string(MR_spy_points[spy_point_num]->spy_when));
MR_print_proc_id_for_debugger(MR_spy_points[spy_point_num]->spy_proc);
}
static void
MR_trace_list_vars(const MR_Stack_Layout_Label *top_layout, Word *saved_regs,
int ancestor_level)
{
const MR_Stack_Layout_Label *level_layout;
Word *base_sp;
Word *base_curfr;
Word *type_params;
int var_count;
const MR_Stack_Layout_Vars *vars;
int i;
const char *problem;
base_sp = MR_saved_sp(saved_regs);
base_curfr = MR_saved_curfr(saved_regs);
level_layout = MR_find_nth_ancestor(top_layout, ancestor_level,
&base_sp, &base_curfr, &problem);
if (level_layout == NULL) {
printf("%s\n", problem);
return;
}
var_count = (int) level_layout->MR_sll_var_count;
if (var_count < 0) {
printf("mdb: there is no information about live variables\n");
return;
} else if (var_count == 0) {
printf("mdb: there are no live variables\n");
return;
}
vars = &level_layout->MR_sll_var_info;
for (i = 0; i < var_count; i++) {
printf("%9d %s\n", i, MR_name_if_present(vars, i));
}
}
static const char *
MR_trace_browse_check_level(const MR_Stack_Layout_Label *top_layout,
Word *saved_regs, int ancestor_level)
{
Word *base_sp;
Word *base_curfr;
const char *problem;
base_sp = MR_saved_sp(saved_regs);
base_curfr = MR_saved_curfr(saved_regs);
if (MR_find_nth_ancestor(top_layout, ancestor_level,
&base_sp, &base_curfr, &problem) == NULL)
{
return problem;
} else {
return NULL;
}
}
static void
MR_trace_browse_one(const MR_Stack_Layout_Label *top_layout,
Word *saved_regs, int ancestor_level, int which_var)
{
const MR_Stack_Layout_Label *level_layout;
Word *base_sp;
Word *base_curfr;
Word *type_params;
Word *valid_saved_regs;
int var_count;
const MR_Stack_Layout_Vars *vars;
const char *problem;
base_sp = MR_saved_sp(saved_regs);
base_curfr = MR_saved_curfr(saved_regs);
level_layout = MR_find_nth_ancestor(top_layout, ancestor_level,
&base_sp, &base_curfr, &problem);
if (level_layout == NULL) {
printf("%s\n", problem);
return;
}
var_count = (int) level_layout->MR_sll_var_count;
if (var_count < 0) {
printf("mdb: there is no information about live variables\n");
return;
} else if (which_var >= var_count) {
printf("mdb: there is no such variable\n");
return;
}
vars = &level_layout->MR_sll_var_info;
if (ancestor_level == 0) {
valid_saved_regs = saved_regs;
} else {
valid_saved_regs = NULL;
}
type_params = MR_materialize_typeinfos_base(vars,
valid_saved_regs, base_sp, base_curfr);
MR_trace_browse_var(MR_name_if_present(vars, which_var),
&vars->MR_slvs_pairs[which_var], valid_saved_regs,
base_sp, base_curfr, type_params);
free(type_params);
}
static void
MR_trace_browse_all(const MR_Stack_Layout_Label *top_layout,
Word *saved_regs, int ancestor_level)
{
const MR_Stack_Layout_Label *level_layout;
Word *base_sp;
Word *base_curfr;
Word *type_params;
Word *valid_saved_regs;
int var_count;
const MR_Stack_Layout_Vars *vars;
const char *problem;
int i;
base_sp = MR_saved_sp(saved_regs);
base_curfr = MR_saved_curfr(saved_regs);
level_layout = MR_find_nth_ancestor(top_layout, ancestor_level,
&base_sp, &base_curfr, &problem);
if (level_layout == NULL) {
printf("%s\n", problem);
return;
}
var_count = (int) level_layout->MR_sll_var_count;
if (var_count < 0) {
printf("mdb: there is no information about live variables\n");
return;
} else if (var_count == 0) {
printf("mdb: there are no live variables\n");
return;
}
vars = &level_layout->MR_sll_var_info;
if (ancestor_level == 0) {
valid_saved_regs = saved_regs;
} else {
valid_saved_regs = NULL;
}
type_params = MR_materialize_typeinfos_base(vars,
valid_saved_regs, base_sp, base_curfr);
for (i = 0; i < var_count; i++) {
MR_trace_browse_var(MR_name_if_present(vars, i),
&vars->MR_slvs_pairs[i], valid_saved_regs,
base_sp, base_curfr, type_params);
}
free(type_params);
}
static void
MR_trace_browse_var(const char *name, const MR_Stack_Layout_Var *var,
Word *saved_regs, Word *base_sp, Word *base_curfr, Word *type_params)
{
Word value;
Word type_info;
bool print_value;
int i;
/*
** XXX The printing of type_infos is buggy at the moment
** due to the fake arity of the type private_builtin:typeinfo/1.
**
** XXX The printing of large data structures is painful
** at the moment due to the lack of a true browser.
*/
if ((strncmp(name, "TypeInfo", 8) == 0)
|| (strncmp(name, "ModuleInfo", 10) == 0)
|| (strncmp(name, "HLDS", 4) == 0))
return;
/* The initial blanks are to visually separate */
/* the variable names from the prompt. */
if (name != NULL) {
printf("%7s%-21s\t", "", name);
} else {
printf("%7s%-21s\t", "", "anonymous variable");
}
fflush(stdout);
/*
** "variables" representing the saved values of succip, hp etc,
** which are the "variables" for which get_type_and_value fails,
** are not of interest to the user.
*/
if (MR_get_type_and_value_base(var, saved_regs,
base_sp, base_curfr, type_params, &type_info, &value))
{
printf("\t");
MR_write_variable(type_info, value);
}
printf("\n");
}
/*
** Read lines until we find one that contains only "end".
** Return the lines concatenated together.
*/
static const char *
MR_trace_read_help_text(void)
{
char *text;
char *doc_chars = NULL;
int doc_char_max = 0;
int next_char_slot;
int line_len;
int i;
next_char_slot = 0;
while ((text = MR_trace_getline("cat> ", stdin)) != NULL) {
if (streq(text, "end")) {
free(text);
break;
}
line_len = strlen(text);
MR_ensure_big_enough(next_char_slot + line_len + 2,
doc_char, char, MR_INIT_DOC_CHARS);
for (i = 0; i < line_len; i++) {
doc_chars[next_char_slot + i] = text[i];
}
next_char_slot += line_len;
doc_chars[next_char_slot] = '\n';
next_char_slot += 1;
free(text);
}
doc_chars[next_char_slot] = '\0';
return doc_chars;
}
/*
** Is the string pointed to by word an integer?
** If yes, return its value in *value.
*/
static bool
MR_trace_is_number(char *word, int *value)
{
if (MR_isdigit(*word)) {
*value = *word - '0';
word++;
while (MR_isdigit(*word)) {
*value = (*value * 10) + *word - '0';
word++;
}
if (*word == '\0') {
return TRUE;
}
}
return FALSE;
}
/*
** Given a text line, break it up into words composed of non-space characters
** separated by space characters. Make each word a NULL-terminated string,
** overwriting some spaces in the line array in the process.
**
** If the first word is a number but the second is not, swap the two.
** If the first word has a number prefix, separate it out.
**
** On return *words will point to an array of strings, with space for
** *words_max strings. The number of strings (words) filled in will be
** given by the return value.
**
** The lifetime of the elements of the *words array expires when
** the line array is freed or further modified or when MR_trace_parse_line
** is called again, whichever comes first.
*/
/* If a number is more than 80 chars long, the user is in trouble. */
#define MR_NUMBER_LEN 80
static const char *
MR_trace_parse_line(char *line, char ***words, int *word_max, int *word_count)
{
char **raw_words;
int raw_word_max;
char raw_word_count;
static char count_buf[MR_NUMBER_LEN];
char *s;
int i;
/*
** Handle a possible number prefix on the first word on the line,
** separating it out into a word on its own.
*/
raw_word_count = MR_trace_break_into_words(line,
&raw_words, &raw_word_max);
if (raw_word_count > 0 && MR_isdigit(*raw_words[0])) {
i = 0;
s = raw_words[0];
while (MR_isdigit(*s)) {
if (i >= MR_NUMBER_LEN) {
return "too large a number";
}
count_buf[i] = *s;
i++;
s++;
}
count_buf[i] = '\0';
if (*s != '\0') {
/* Only part of the first word constitutes a number. */
/* Put it in an extra word at the start. */
MR_ensure_big_enough(raw_word_count, raw_word,
char **, MR_INIT_WORD_COUNT);
for (i = raw_word_count; i > 0; i--) {
raw_words[i] = raw_words[i-1];
}
raw_words[0] = count_buf;
raw_words[1] = s;
raw_word_count++;
}
}
/*
** If the first word is a number, try to exchange it
** with the command word, to put the command word first.
*/
if (raw_word_count > 1 && MR_trace_is_number(raw_words[0], &i)
&& ! MR_trace_is_number(raw_words[1], &i)) {
s = raw_words[0];
raw_words[0] = raw_words[1];
raw_words[1] = s;
}
*words = raw_words;
*word_max = raw_word_max;
*word_count = raw_word_count;
return NULL;
}
/*
** Given a text line, break it up into words composed of non-space characters
** separated by space characters. Make each word a NULL-terminated string,
** overwriting some spaces in the line array in the process.
**
** On return *words will point to an array of strings, with space for
** *words_max strings. The number of strings filled in will be given by
** the return value.
*/
static int
MR_trace_break_into_words(char *line, char ***words_ptr, int *word_max_ptr)
{
int word_max;
char **words;
int token_number;
int char_pos;
int int_val;
token_number = 0;
char_pos = 0;
word_max = 0;
words = NULL;
/* each iteration of this loop processes one token, or end of line */
for (;;) {
while (line[char_pos] != '\0' && MR_isspace(line[char_pos])) {
char_pos++;
}
if (line[char_pos] == '\0') {
*words_ptr = words;
*word_max_ptr = word_max;
return token_number;
}
MR_ensure_big_enough(token_number, word, char **,
MR_INIT_WORD_COUNT);
words[token_number] = line + char_pos;
while (line[char_pos] != '\0' && !MR_isspace(line[char_pos])) {
char_pos++;
}
if (line[char_pos] != '\0') {
line[char_pos] = '\0';
char_pos++;
}
token_number++;
}
}
static void
MR_trace_source(const char *filename)
{
FILE *fp;
if ((fp = fopen(filename, "r")) != NULL) {
MR_trace_source_from_open_file(fp);
fclose(fp);
} else {
perror(filename);
/*
** We actually want to write to stdout, but the following
** is too Unix-specific:
if (errno < sys_nerr) {
printf("%s: %s\n", filename, sys_errlist[errno]);
} else {
printf("Cannot open %s: unknown error\n", filename);
}
*/
}
}
static void
MR_trace_source_from_open_file(FILE *fp)
{
char *line;
while ((line = MR_trace_getline_raw(fp)) != NULL) {
MR_insert_line_at_tail(line);
}
}
/*
** If there any lines waiting in the queue, return the first of these.
** If not, print the prompt, read a line from the given file, and return it
** in a malloc'd buffer holding the line (without the final newline).
** If EOF occurs on a nonempty line, treat the EOF as a newline; if EOF
** occurs on an empty line, return NULL.
*/
static char *
MR_trace_getline(const char *prompt, FILE *fp)
{
char *line;
line = MR_trace_getline_queue();
if (line != NULL) {
return line;
}
printf("%s", prompt);
fflush(stdout);
return MR_trace_getline_raw(fp);
}
/*
** If there any lines waiting in the queue, return the first of these.
*/
static char *
MR_trace_getline_queue(void)
{
if (MR_line_head != NULL) {
MR_Line *old;
char *contents;
old = MR_line_head;
contents = MR_line_head->MR_line_contents;
MR_line_head = MR_line_head->MR_line_next;
if (MR_line_head == NULL) {
MR_line_tail = NULL;
}
free(old);
return contents;
} else {
return NULL;
}
}
/*
** Read a line from a file, and return a pointer to a malloc'd buffer
** holding the line (without the final newline). If EOF occurs on a
** nonempty line, treat the EOF as a newline; if EOF occurs on an empty
** line, return NULL.
*/
static char *
MR_trace_getline_raw(FILE *fp)
{
char *contents;
int content_max;
int c;
int i;
contents = NULL;
content_max = 0;
i = 0;
while ((c = getc(fp)) != EOF && c != '\n') {
MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN);
contents[i++] = c;
}
if (c == '\n' || i > 0) {
MR_ensure_big_enough(i, content, char, MR_INIT_BUF_LEN);
contents[i] = '\0';
return contents;
} else {
free(contents);
return NULL;
}
}
static void
MR_insert_line_at_head(const char *contents)
{
MR_Line *line;
line = checked_malloc(sizeof(MR_Line));
line->MR_line_contents = MR_copy_string(contents);
line->MR_line_next = MR_line_head;
MR_line_head = line;
if (MR_line_tail == NULL) {
MR_line_tail = MR_line_head;
}
}
static void
MR_insert_line_at_tail(const char *contents)
{
MR_Line *line;
char *copy;
int len;
len = strlen(contents);
copy = checked_malloc(len + 1);
strcpy(copy, contents);
line = checked_malloc(sizeof(MR_Line));
line->MR_line_contents = copy;
line->MR_line_next = NULL;
if (MR_line_tail == NULL) {
MR_line_tail = line;
MR_line_head = line;
} else {
MR_line_tail->MR_line_next = line;
MR_line_tail = line;
}
}
static Code *
MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
const MR_Stack_Layout_Label *layout, Word *saved_regs,
MR_Trace_Port port, int seqno, int depth, const char *path,
int *max_mr_num)
{
char *buf;
int i;
/* We try to leave one line for the prompt itself. */
if (MR_scroll_control && MR_scroll_next >= MR_scroll_limit - 1) {
try_again:
buf = MR_trace_getline("--more-- ", stdin);
if (buf != NULL) {
for (i = 0; buf[i] != '\0' && MR_isspace(buf[i]); i++)
;
if (buf[i] != '\0' && !MR_isspace(buf[i])) {
switch (buf[i]) {
case 'a':
cmd->MR_trace_print_level =
MR_PRINT_LEVEL_ALL;
break;
case 'n':
cmd->MR_trace_print_level =
MR_PRINT_LEVEL_NONE;
break;
case 's':
cmd->MR_trace_print_level =
MR_PRINT_LEVEL_SOME;
break;
case 'q':
free(buf);
return MR_trace_event_internal(
cmd, TRUE,
layout,
saved_regs,
port,
seqno, depth,
path,
max_mr_num);
default:
printf("unknown command, "
"try again\n");
free(buf);
goto try_again;
}
}
free(buf);
}
MR_scroll_next = 0;
}
MR_trace_event_print_internal_report(layout, port, seqno, depth, path);
MR_scroll_next++;
return NULL;
}
void
MR_trace_event_print_internal_report(const MR_Stack_Layout_Label *layout,
MR_Trace_Port port, int seqno, int depth, const char *path)
{
printf("%8ld: %6ld %2ld ",
(long) MR_trace_event_number, (long) seqno, (long) depth);
MR_trace_print_port(port);
/*
** The following should be a full identification of the procedure
** provided (a) there was no intermodule optimization and (b) we are
** not interested in tracing compiler-generated procedures.
*/
MR_print_proc_id(stdout, layout->MR_sll_entry, path);
}
static void
MR_trace_print_port(MR_Trace_Port port)
{
switch (port) {
case MR_PORT_CALL:
printf("CALL ");
break;
case MR_PORT_EXIT:
printf("EXIT ");
break;
case MR_PORT_REDO:
printf("REDO ");
break;
case MR_PORT_FAIL:
printf("FAIL ");
break;
case MR_PORT_THEN:
printf("THEN ");
break;
case MR_PORT_ELSE:
printf("ELSE ");
break;
case MR_PORT_DISJ:
printf("DISJ ");
break;
case MR_PORT_SWITCH:
printf("SWTC ");
break;
case MR_PORT_PRAGMA_FIRST:
printf("FRST ");
break;
case MR_PORT_PRAGMA_LATER:
printf("LATR ");
break;
default:
fatal_error("MR_trace_event_internal called "
"with bad port");
}
}
typedef struct
{
const char *cat;
const char *item;
} MR_trace_cmd_cat_item;
static MR_trace_cmd_cat_item MR_trace_valid_command_list[] =
{
/* The following block is a verbatim copy of doc/mdb_command_list. */
/* We do not use a #include to avoid adding a dependency. */
{ "forward", "step" },
{ "forward", "goto" },
{ "forward", "finish" },
{ "forward", "return" },
{ "forward", "forward" },
{ "forward", "mindepth" },
{ "forward", "maxdepth" },
{ "forward", "continue" },
{ "backward", "retry" },
{ "browsing", "vars" },
{ "browsing", "print" },
{ "browsing", "stack" },
{ "browsing", "up" },
{ "browsing", "down" },
{ "browsing", "level" },
{ "browsing", "current" },
{ "breakpoint", "break" },
{ "breakpoint", "disable" },
{ "breakpoint", "enable" },
{ "breakpoint", "modules" },
{ "breakpoint", "procedures" },
{ "breakpoint", "register" },
{ "parameter", "printlevel" },
{ "parameter", "echo" },
{ "parameter", "scroll" },
{ "parameter", "alias" },
{ "parameter", "unalias" },
{ "help", "document_category" },
{ "help", "document" },
{ "help", "help" },
{ "exp", "histogram_all" },
{ "exp", "histogram_exp" },
{ "exp", "clear_histogram" },
{ "developer", "nondet_stack" },
{ "developer", "stack_regs" },
{ "misc", "source" },
{ "misc", "quit" },
/* End of doc/mdb_command_list. */
{ NULL, "NUMBER" },
{ NULL, "EMPTY" },
{ NULL, NULL },
};
static bool
MR_trace_valid_command(const char *word)
{
int i;
for (i = 0; MR_trace_valid_command_list[i].item != NULL; i++) {
if (streq(MR_trace_valid_command_list[i].item, word)) {
return TRUE;
}
}
return FALSE;
}
Index: trace/mercury_trace_internal.h
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.h,v
retrieving revision 1.1
diff -u -u -r1.1 mercury_trace_internal.h
--- mercury_trace_internal.h 1998/09/29 05:11:57 1.1
+++ mercury_trace_internal.h 1998/09/29 06:58:58
@@ -7,16 +7,11 @@
SUPPORT RETRY
USE FIXED STACK SLOTS FOR TRACE INFO
#ifndef MERCURY_TRACE_INTERNAL_H
#define MERCURY_TRACE_INTERNAL_H
-extern void MR_trace_event_internal(MR_trace_cmd_info *cmd,
+extern Code *MR_trace_event_internal(MR_Trace_Cmd_Info *cmd,
+ bool interactive,
const MR_Stack_Layout_Label *layout,
- MR_trace_port port, int seqno, int depth,
- const char *path);
-
-extern void MR_trace_event_internal_report(
- const MR_Stack_Layout_Label *layout,
- MR_trace_port port, int seqno, int depth,
- const char *path);
-
-extern bool MR_event_matches_spy_point(const MR_Stack_Layout_Label *layout);
+ Word *saved_regs, MR_Trace_Port port,
+ int seqno, int depth,
+ const char *path, int *max_mr_num);
#endif /* MERCURY_TRACE_INTERNAL_H */
Index: trace/mercury_trace_spy.c
===================================================================
RCS file: mercury_trace_spy.c
diff -N mercury_trace_spy.c
--- /dev/null Wed May 28 10:49:58 1997
+++ mercury_trace_spy.c Mon Sep 21 20:03:43 1998
IMPLEMENT NEW DEBUGGER COMMAND SET
@@ -0,0 +1,181 @@
+/*
+** Copyright (C) 1998 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 file contains code to manage spy points for both
+** the internal and external debuggers.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#undef USE_GCC_GLOBAL_REGISTERS
+#include "mercury_imp.h"
+#include "mercury_trace_base.h"
+#include "mercury_trace.h"
+#include "mercury_trace_spy.h"
+#include "mercury_macros.h"
+
+typedef struct {
+ const MR_Stack_Layout_Entry *spy_proc;
+ MR_Spy_Point *spy_points;
+} MR_Spied_Proc;
+
+static MR_Spied_Proc *MR_spied_procs;
+static int MR_spied_proc_next = 0;
+static int MR_spied_proc_max = 0;
+
+#define INIT_SPY_TABLE_SIZE 10
+
+ /* Return the index of the entry in MR_spied_procs whose */
+ /* spy_proc field is entry, or a negative number if absent */
+static int MR_search_spy_table_for_proc(const MR_Stack_Layout_Entry
+ *entry);
+
+static int
+MR_search_spy_table_for_proc(const MR_Stack_Layout_Entry *entry)
+{
+ int lo;
+ int hi;
+ int mid;
+
+ lo = 0;
+ hi = MR_spied_proc_next - 1;
+ while (lo <= hi) {
+ mid = (lo + hi) / 2;
+ if (MR_spied_procs[mid].spy_proc == entry) {
+ return mid;
+ } else if (MR_spied_procs[mid].spy_proc < entry) {
+ lo = mid + 1;
+ } else {
+ hi = mid - 1;
+ }
+ }
+
+ return -1;
+}
+
+bool
+MR_event_matches_spy_point(const MR_Stack_Layout_Label *layout,
+ MR_Trace_Port port, MR_Spy_Action *action_ptr)
+{
+ int slot;
+ bool enabled;
+ MR_Spy_Point *point;
+ MR_Spy_Action action;
+
+ slot = MR_search_spy_table_for_proc(layout->MR_sll_entry);
+ if (slot < 0) {
+ return FALSE;
+ }
+
+ enabled = FALSE;
+ action = MR_SPY_PRINT;
+ for (point = MR_spied_procs[slot].spy_points; point != NULL;
+ point = point->spy_next) {
+ if (! point->spy_enabled) {
+ continue;
+ }
+
+ switch (point->spy_when) {
+
+ case MR_SPY_ALL:
+ enabled = TRUE;
+ action = max(action, point->spy_action);
+ break;
+
+ case MR_SPY_ENTRY:
+ if (MR_port_is_entry(port)) {
+ enabled = TRUE;
+ action = max(action, point->spy_action);
+ } else {
+ continue;
+ }
+
+ break;
+
+ case MR_SPY_INTERFACE:
+ if (MR_port_is_interface(port)) {
+ enabled = TRUE;
+ action = max(action, point->spy_action);
+ } else {
+ continue;
+ }
+
+ break;
+
+ case MR_SPY_SPECIFIC:
+ if (layout == point->spy_label) {
+ enabled = TRUE;
+ action = max(action, point->spy_action);
+ } else {
+ continue;
+ }
+
+ break;
+
+ default:
+ fatal_error("bad spy point when in "
+ "MR_event_matches_spy_point");
+ }
+ }
+
+ if (enabled) {
+ *action_ptr = action;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static bool MR_need_move(int i, const MR_Stack_Layout_Entry *entry);
+
+MR_Spy_Point *
+MR_add_spy_point(MR_Spy_When when, MR_Spy_Action action,
+ const MR_Stack_Layout_Entry *entry, const MR_Stack_Layout_Label *label,
+ const char *path)
+{
+ MR_Spy_Point *point;
+ int i;
+ int slot;
+ bool found;
+
+ slot = MR_search_spy_table_for_proc(entry);
+ if (slot < 0) {
+ MR_ensure_room_for_next(MR_spied_proc, MR_Spied_Proc,
+ INIT_SPY_TABLE_SIZE);
+ MR_prepare_insert_into_sorted(MR_spied_procs,
+ MR_spied_proc_next, slot, MR_need_move(i, entry));
+ MR_spied_procs[slot].spy_proc = entry;
+ MR_spied_procs[slot].spy_points = NULL;
+ }
+
+ /* Insert the spy point at the head of the list for the proc. */
+ point = checked_malloc(sizeof(MR_Spy_Point));
+ point->spy_when = when;
+ point->spy_enabled = TRUE;
+ point->spy_action = action;
+ point->spy_proc = entry;
+ point->spy_label = label;
+ point->spy_next = MR_spied_procs[slot].spy_points;
+ MR_spied_procs[slot].spy_points = point;
+
+ return point;
+}
+
+/*
+** The only reason why MR_need_move is a function is that gcc version 2.7.2.3
+** on i686-pc-linux-gnu gets an internal error ("fixed or forbidden register
+** was spilled") if it isn't a function.
+*/
+
+static bool
+MR_need_move(int i, const MR_Stack_Layout_Entry *entry)
+{
+ if (MR_spied_procs[i].spy_proc > entry)
+ return TRUE;
+ else
+ return FALSE;
+}
Index: trace/mercury_trace_spy.h
===================================================================
RCS file: mercury_trace_spy.h
diff -N mercury_trace_spy.h
--- /dev/null Wed May 28 10:49:58 1997
+++ mercury_trace_spy.h Tue Sep 22 12:30:04 1998
IMPLEMENT NEW DEBUGGER COMMAND SET
@@ -0,0 +1,56 @@
+/*
+** Copyright (C) 1998 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 file contains the declarations of the types and functions that
+** the internal and external debuggers can use to manipulate spy points.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#ifndef MERCURY_TRACE_SPY_H
+#define MERCURY_TRACE_SPY_H
+
+typedef enum {
+ MR_SPY_PRINT, MR_SPY_STOP
+} MR_Spy_Action;
+
+#define MR_spy_action_string(a) ((a == MR_SPY_STOP) ? "stop" : \
+ (a == MR_SPY_PRINT) ? "print" : \
+ "weird spy action")
+
+typedef enum {
+ MR_SPY_ALL, MR_SPY_INTERFACE, MR_SPY_ENTRY, MR_SPY_SPECIFIC
+} MR_Spy_When;
+
+#define MR_spy_when_string(w) ((w == MR_SPY_ALL) ? "all" : \
+ (w == MR_SPY_INTERFACE) ? "interface":\
+ (w == MR_SPY_ENTRY) ? "entry" : \
+ (w == MR_SPY_SPECIFIC) ? "specific" : \
+ "weird spy when")
+
+typedef struct struct_mr_spy_point MR_Spy_Point;
+
+struct struct_mr_spy_point {
+ MR_Spy_When spy_when;
+ bool spy_enabled;
+ MR_Spy_Action spy_action;
+ const MR_Stack_Layout_Entry *spy_proc;
+ const MR_Stack_Layout_Label *spy_label; /* if MR_SPY_SPECIFIC */
+ MR_Spy_Point *spy_next;
+};
+
+extern bool MR_event_matches_spy_point(const MR_Stack_Layout_Label
+ *layout, MR_Trace_Port port,
+ MR_Spy_Action *action);
+
+extern MR_Spy_Point *MR_add_spy_point(MR_Spy_When when,
+ MR_Spy_Action action,
+ const MR_Stack_Layout_Entry *entry,
+ const MR_Stack_Layout_Label *label,
+ const char *path);
+
+#endif /* not MERCURY_TRACE_SPY_H */
Index: trace/mercury_trace_tables.c
===================================================================
RCS file: mercury_trace_tables.c
diff -N mercury_trace_tables.c
--- /dev/null Wed May 28 10:49:58 1997
+++ mercury_trace_tables.c Mon Sep 21 20:03:43 1998
IMPLEMENT NEW DEBUGGER COMMAND SET
@@ -0,0 +1,376 @@
+/*
+** Copyright (C) 1998 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 file manages a table listing the debuggable modules of the program,
+** and subsidiary tables listing the procedures of each of those modules.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#undef USE_GCC_GLOBAL_REGISTERS
+#include "mercury_imp.h"
+#include "mercury_label.h"
+#include "mercury_macros.h"
+#include "mercury_trace_tables.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+static MR_Module_Info *MR_module_infos;
+static int MR_module_info_next = 0;
+static int MR_module_info_max = 0;
+static int MR_module_info_proc_count = 0;
+
+#define INIT_MODULE_TABLE_SIZE 10
+
+static void MR_register_from_internal_label(const void *info);
+static void MR_ensure_proc_node_is_present(MR_Module_Info *module,
+ const MR_Stack_Layout_Entry *entry);
+static MR_Module_Info *MR_search_module_info(const char *name);
+static MR_Module_Info *MR_insert_module_info(const char *name);
+static MR_Module_Info *MR_ensure_module_info_is_present(const char *name);
+
+static void MR_process_matching_procedures_in_module(
+ MR_Module_Info *module, MR_Proc_Spec *spec,
+ void f(const MR_Stack_Layout_Entry *));
+
+void
+MR_register_all_modules_and_procs(FILE *fp, bool verbose)
+{
+ static bool done = FALSE;
+
+ if (! done) {
+ if (verbose) {
+ fprintf(fp, "Registering debuggable procedures... ");
+ fflush(fp);
+ }
+
+ do_init_modules();
+ MR_process_all_internal_labels(MR_register_from_internal_label);
+ done = TRUE;
+ if (verbose) {
+ fprintf(fp, "done.\n");
+ if (MR_module_info_next == 0) {
+ fprintf(fp, "There are no debuggable modules.");
+ } else if (MR_module_info_next == 1) {
+ fprintf(fp, "There is one debuggable module, "
+ "with %d procedures.\n",
+ MR_module_info_proc_count);
+ } else {
+ fprintf(fp, "There are %d debuggable modules, "
+ "with a total of %d procedures.\n",
+ MR_module_info_next,
+ MR_module_info_proc_count);
+ }
+ }
+ }
+}
+
+static void
+MR_register_from_internal_label(const void *info)
+{
+ const MR_Stack_Layout_Label *label;
+ const MR_Stack_Layout_Entry *entry;
+ MR_Module_Info *module;
+
+ label = ((const MR_Internal *) info)->i_layout;
+
+ if (label == NULL) {
+ /* some labels have no layout structure */
+ return;
+ }
+
+ if (label->MR_sll_entry == NULL) {
+ /* some hand-crafted label structures have no entry */
+ return;
+ }
+
+ entry = label->MR_sll_entry;
+
+ if (MR_ENTRY_LAYOUT_HAS_EXEC_TRACE(entry) &&
+ ! MR_ENTRY_LAYOUT_COMPILER_GENERATED(entry))
+ {
+ module = MR_ensure_module_info_is_present(
+ entry->MR_sle_def_module);
+ MR_ensure_proc_node_is_present(module, entry);
+ }
+}
+
+static void
+MR_ensure_proc_node_is_present(MR_Module_Info *module,
+ const MR_Stack_Layout_Entry *entry)
+{
+ MR_Proc_Node *cur;
+
+ for (cur = module->MR_module_procs; cur != NULL;
+ cur = cur->MR_proc_next) {
+ if (entry == cur->MR_proc_layout) {
+ return;
+ }
+ }
+
+ cur = checked_malloc(sizeof(MR_Proc_Node));
+ cur->MR_proc_layout = entry;
+ cur->MR_proc_next = module->MR_module_procs;
+ module->MR_module_procs = cur;
+ MR_module_info_proc_count++;
+}
+
+static MR_Module_Info *
+MR_search_module_info(const char *name)
+{
+ int slot;
+ bool found;
+
+ MR_bsearch(MR_module_info_next, slot, found,
+ strcmp(MR_module_infos[slot].MR_module_name, name));
+ if (found) {
+ return &MR_module_infos[slot];
+ } else {
+ return NULL;
+ }
+}
+
+static MR_Module_Info *
+MR_insert_module_info(const char *name)
+{
+ int slot;
+
+ MR_ensure_room_for_next(MR_module_info, MR_Module_Info,
+ INIT_MODULE_TABLE_SIZE);
+ MR_prepare_insert_into_sorted(MR_module_infos, MR_module_info_next,
+ slot, strcmp(MR_module_infos[slot].MR_module_name, name));
+
+ MR_module_infos[slot].MR_module_name = name;
+ MR_module_infos[slot].MR_module_procs = NULL;
+ return &MR_module_infos[slot];
+}
+
+static MR_Module_Info *
+MR_ensure_module_info_is_present(const char *name)
+{
+ MR_Module_Info *module;
+
+ module = MR_search_module_info(name);
+ if (module != NULL) {
+ return module;
+ } else {
+ return MR_insert_module_info(name);
+ }
+}
+
+void
+MR_dump_module_tables(FILE *fp)
+{
+ const MR_Proc_Node *cur;
+ int i;
+
+ for (i = 0; i < MR_module_info_next; i++) {
+ fprintf(fp, "====================\n");
+ fprintf(fp, "module %s\n", MR_module_infos[i].MR_module_name);
+ fprintf(fp, "====================\n");
+ for (cur = MR_module_infos[i].MR_module_procs; cur != NULL;
+ cur = cur->MR_proc_next) {
+ MR_print_proc_id(fp, cur->MR_proc_layout, NULL);
+ }
+ }
+}
+
+void
+MR_dump_module_list(FILE *fp)
+{
+ int i;
+
+ fprintf(fp, "List of debuggable modules\n\n");
+ for (i = 0; i < MR_module_info_next; i++) {
+ fprintf(fp, "%s\n", MR_module_infos[i].MR_module_name);
+ }
+}
+
+void
+MR_dump_module_procs(FILE *fp, const char *name)
+{
+ MR_Module_Info *module;
+ const MR_Proc_Node *cur;
+
+ module = MR_search_module_info(name);
+ if (module == NULL) {
+ fprintf(fp, "There is no debugging info about module %s\n",
+ name);
+ } else {
+ fprintf(fp, "List of procedures in module %s\n\n", name);
+ for (cur = module->MR_module_procs; cur != NULL;
+ cur = cur->MR_proc_next) {
+ MR_print_proc_id(fp, cur->MR_proc_layout, NULL);
+ }
+ }
+}
+
+bool
+MR_parse_proc_spec(char *str, MR_Proc_Spec *spec)
+{
+ char *dash;
+ char *slash;
+ char *s;
+ int n;
+ bool found;
+
+ spec->MR_proc_module = NULL;
+ spec->MR_proc_name = NULL;
+ spec->MR_proc_arity = -1;
+ spec->MR_proc_mode = -1;
+ spec->MR_proc_pf = (MR_PredFunc) -1;
+
+ if (strneq(str, "pred*", 5)) {
+ spec->MR_proc_pf = MR_PREDICATE;
+ str += 5;
+ } else if (strneq(str, "func*", 5)) {
+ spec->MR_proc_pf = MR_FUNCTION;
+ str += 5;
+ }
+
+ if ((dash = strrchr(str, '-')) != NULL) {
+ found = FALSE;
+ n = 0;
+ for (s = dash + 1; *s != '\0'; s++) {
+ if (MR_isdigit(*s)) {
+ found = TRUE;
+ n = n * 10 + *s - '0';
+ } else {
+ /* a dash followed by a nondigit is an error */
+ return FALSE;
+ }
+ }
+
+ if (! found) {
+ /* a dash with no following digit is an error */
+ return FALSE;
+ }
+
+ spec->MR_proc_mode = n;
+ *dash = '\0';
+ }
+
+ if ((slash = strrchr(str, '/')) != NULL) {
+ found = FALSE;
+ n = 0;
+ for (s = slash + 1; *s != '\0'; s++) {
+ if (MR_isdigit(*s)) {
+ found = TRUE;
+ n = n * 10 + *s - '0';
+ } else {
+ /* a slash followed by a nondigit is an error */
+ return FALSE;
+ }
+ }
+
+ if (! found) {
+ /* a slash with no following digit is an error */
+ return FALSE;
+ }
+
+ spec->MR_proc_arity = n;
+ *slash = '\0';
+ }
+
+ for (s = str; *s != '\0'; s++) {
+ if (*s == ':' || (*s == '_' && *(s+1) == '_')) {
+ if (*s == ':') {
+ spec->MR_proc_name = s+1;
+ } else {
+ spec->MR_proc_name = s+2;
+ }
+
+ *s = '\0';
+ spec->MR_proc_module = str;
+
+ return TRUE;
+ }
+ }
+
+ spec->MR_proc_name = str;
+ return TRUE;
+}
+
+/* These two variables are for communication between */
+/* MR_register_match and MR_search_for_matching_procedure. */
+static const MR_Stack_Layout_Entry *matching_entry;
+static bool match_unique;
+
+static void
+MR_register_match(const MR_Stack_Layout_Entry *entry)
+{
+ if (matching_entry == NULL) {
+ matching_entry = entry;
+ } else {
+ match_unique = FALSE;
+ }
+}
+
+const MR_Stack_Layout_Entry *
+MR_search_for_matching_procedure(MR_Proc_Spec *spec, bool *unique)
+{
+ matching_entry = NULL;
+ match_unique = TRUE;
+ MR_process_matching_procedures(spec, MR_register_match);
+ *unique = match_unique;
+ return matching_entry;
+}
+
+void
+MR_process_matching_procedures(MR_Proc_Spec *spec,
+ void f(const MR_Stack_Layout_Entry *))
+{
+ if (spec->MR_proc_module != NULL) {
+ MR_Module_Info *module;
+
+ module = MR_search_module_info(spec->MR_proc_module);
+ if (module != NULL) {
+ MR_process_matching_procedures_in_module(
+ module, spec, f);
+ }
+ } else {
+ int i;
+
+ for (i = 0; i < MR_module_info_next; i++) {
+ MR_process_matching_procedures_in_module(
+ &MR_module_infos[i], spec, f);
+ }
+ }
+}
+
+#define match_name(spec, cur) (((spec)->MR_proc_name == NULL) || \
+ streq((spec)->MR_proc_name, cur->MR_sle_name))
+
+#define match_arity(spec, cur) (((spec)->MR_proc_arity < 0) || \
+ (spec)->MR_proc_arity == cur->MR_sle_arity)
+
+#define match_mode(spec, cur) (((spec)->MR_proc_mode < 0) || \
+ (spec)->MR_proc_mode == cur->MR_sle_mode)
+
+#define match_pf(spec, cur) (((int) (spec)->MR_proc_pf < 0) || \
+ (spec)->MR_proc_pf == cur->MR_sle_pred_or_func)
+
+static void
+MR_process_matching_procedures_in_module(MR_Module_Info *module,
+ MR_Proc_Spec *spec, void f(const MR_Stack_Layout_Entry *))
+{
+ MR_Proc_Node *cur;
+ const MR_Stack_Layout_Entry *cur_entry;
+
+ for (cur = module->MR_module_procs; cur != NULL;
+ cur = cur->MR_proc_next) {
+ cur_entry = cur->MR_proc_layout;
+ if (match_name(spec, cur_entry) &&
+ match_arity(spec, cur_entry) &&
+ match_mode(spec, cur_entry) &&
+ match_pf(spec, cur_entry))
+ {
+ f(cur_entry);
+ }
+ }
+}
Index: trace/mercury_trace_tables.h
===================================================================
RCS file: mercury_trace_tables.h
diff -N mercury_trace_tables.h
--- /dev/null Wed May 28 10:49:58 1997
+++ mercury_trace_tables.h Tue Sep 22 12:30:04 1998
IMPLEMENT NEW DEBUGGER COMMAND SET
@@ -0,0 +1,120 @@
+/*
+** Copyright (C) 1998 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 file contains the declarations of the tables that contain
+** the identities of the debuggable modules and their procedures.
+**
+** Main author: Zoltan Somogyi.
+*/
+
+#ifndef MERCURY_TRACE_TABLES_H
+#define MERCURY_TRACE_TABLES_H
+
+#include "mercury_stack_layout.h"
+#include <stdio.h>
+
+/*
+** The module info table is an array with one element for each module
+** that has procedures with execution tracing information. This element
+** gives the module's name and points to a list of the procedure layouts
+** of the traceable procedures of the module.
+*/
+
+typedef struct struct_mr_proc_node MR_Proc_Node;
+
+struct struct_mr_proc_node {
+ const MR_Stack_Layout_Entry *MR_proc_layout;
+ MR_Proc_Node *MR_proc_next;
+};
+
+typedef struct {
+ const char *MR_module_name;
+ MR_Proc_Node *MR_module_procs;
+} MR_Module_Info;
+
+/*
+** MR_register_all_modules_and_procs gathers all available debugging info
+** about the modules and procedures of the program into the module info table.
+** If verbose is TRUE, print progress and summary messages.
+*/
+
+extern void MR_register_all_modules_and_procs(FILE *fp,
+ bool verbose);
+
+/*
+** These functions print (parts of) the module info table.
+**
+** MR_dump_module_tables lists all procedures in all modules.
+** Its output can be very big; it should be used only by developers,
+** for debugging the debugger.
+**
+** MR_dump_module_list lists the names of all the modules,
+** while MR_dump_module_procs lists the names of all the procs in the named
+** module. These are intended for ordinary, non-developer users.
+*/
+
+extern void MR_dump_module_tables(FILE *fp);
+extern void MR_dump_module_list(FILE *fp);
+extern void MR_dump_module_procs(FILE *fp, const char *name);
+
+/*
+** A procedure specification gives some or all of
+**
+** the name of the module defining the procedure
+** the name of the predicate or function
+** the arity of the predicate or function
+** the mode of the predicate or function
+** whether the procedure belongs to a predicate or function
+**
+** A NULL pointer for the string fields, and a negative number for the other
+** fields signifies the absence of information about that field, which should
+** therefore be treated as a wildcard.
+*/
+
+typedef struct {
+ const char *MR_proc_module;
+ const char *MR_proc_name;
+ int MR_proc_arity;
+ int MR_proc_mode;
+ MR_PredFunc MR_proc_pf;
+} MR_Proc_Spec;
+
+/*
+** Given a string containing the specification of a procedure in the form
+**
+** [`pred*'|`func*']module:name/arity-mode
+**
+** in which some of the five components (but not the name) may be missing,
+** parse it into the more usable form of a MR_Proc_Spec. The original string
+** may be overwritten in the process.
+**
+** Returns TRUE if the string was correctly formed, and FALSE otherwise.
+*/
+
+extern bool MR_parse_proc_spec(char *str, MR_Proc_Spec *spec);
+
+/*
+** Search the tables for a procedure that matches the given specification.
+** If no procedure matches, return NULL.
+** If one procedure matches, return its layout structure,
+** and set *unique to TRUE.
+** If more than one procedure matches, return the layout structure of one
+** and set *unique to FALSE.
+*/
+
+extern const MR_Stack_Layout_Entry *MR_search_for_matching_procedure(
+ MR_Proc_Spec *spec, bool *unique);
+
+/*
+** Call f(entry) on the layout of every procedure that matches
+** the given specification.
+*/
+
+extern void MR_process_matching_procedures(MR_Proc_Spec *spec,
+ void f(const MR_Stack_Layout_Entry *));
+
+#endif /* not MERCURY_TRACE_TABLES_H */
cvs diff: Diffing trial
cvs diff: Diffing util
Index: util/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/util/Mmakefile,v
retrieving revision 1.3
diff -u -u -r1.3 Mmakefile
--- Mmakefile 1998/09/29 05:12:05 1.3
+++ Mmakefile 1998/09/29 06:52:28
DOCUMENT NEW DEBUG COMMAND SET
@@ -20,7 +20,7 @@
# we need -I ../runtime for "mercury_getopt.h"
# the -O0 is to get around a stupid compiler bug in gcc 2.7.2.3 on cyclone
-PROGS=mkinit mdemangle
+PROGS=mkinit mdemangle info_to_mdb
#-----------------------------------------------------------------------------#
Index: util/info_to_mdb.c
===================================================================
RCS file: info_to_mdb.c
diff -N info_to_mdb.c
--- /dev/null Wed May 28 10:49:58 1997
+++ info_to_mdb.c Wed Sep 9 20:29:47 1998
DOCUMENT NEW DEBUG COMMAND SET
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define TRUE 1
+#define FALSE 0
+#define bool char
+
+#define MAXLINELEN 160
+
+static bool is_empty(char *line);
+static bool is_all_same_char(char *line, char what);
+static bool is_command(char *line, bool *is_concept);
+static bool diff_command(char *line, char *command);
+static void print_command_line(char *line, bool is_concept);
+
+static char *get_next_line(FILE *infp);
+static void put_line_back(char *line);
+
+#define concept_char(c) (isupper(c) ? tolower(c) : (isspace(c) ? '_' : (c)))
+#define isalnumunder(c) (isalnum(c) || (c) == '_')
+
+int
+main(int argc, char **argv)
+{
+ FILE *infp;
+ char *line;
+ char command[MAXLINELEN];
+ int slot = 0;
+ int len;
+ int i;
+ bool is_concept;
+ bool next_concept;
+
+ if (argc != 3) {
+ printf("usage: info_to_mdb section_name section_info_file\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((infp = fopen(argv[2], "r")) == NULL) {
+ printf("cannot read %s\n", argv[2]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* skip the top part of the node, up to and including */
+ /* the underlined heading */
+
+ while ((line = get_next_line(infp)) != NULL) {
+ if (is_all_same_char(line, '-') || is_all_same_char(line, '='))
+ {
+ break;
+ }
+ }
+
+ while (TRUE) {
+ line = get_next_line(infp);
+ while (line != NULL && is_empty(line)) {
+ line = get_next_line(infp);
+ }
+
+ if (line == NULL) {
+ return 0;
+ }
+
+ if (! is_command(line, &is_concept)) {
+ continue;
+ }
+
+ slot += 100;
+ printf("document %s %d ", argv[1], slot);
+ if (is_concept) {
+ for (i = 0; line[i] != '\n'; i++) {
+ command[i] = concept_char(line[i]);
+ putchar(concept_char(line[i]));
+ }
+ putchar('\n');
+ command[i] = '\0';
+ } else {
+ for (i = 1; isalnumunder(line[i]); i++) {
+ command[i-1] = line[i];
+ putchar(line[i]);
+ }
+ putchar('\n');
+ command[i-1] = '\0';
+ }
+
+ print_command_line(line, is_concept);
+
+ while ((line = get_next_line(infp)) != NULL) {
+ if (is_command(line, &next_concept)) {
+ if (diff_command(line, command)) {
+ put_line_back(line);
+ break;
+ } else {
+ print_command_line(line, next_concept);
+ }
+ } else {
+ printf("%s", line);
+ }
+ }
+
+ printf("end\n");
+ }
+}
+
+static bool
+is_empty(char *line)
+{
+ int i = 0;
+
+ while (line[i] != '\0') {
+ if (!isspace(line[i])) {
+ return FALSE;
+ }
+
+ i++;
+ }
+
+ return TRUE;
+}
+
+static bool
+is_all_same_char(char *line, char what)
+{
+ int i = 0;
+
+ while (line[i] != '\0') {
+ if (line[i] != what && line[i] != '\n') {
+ return FALSE;
+ }
+
+ i++;
+ }
+
+ return i > 1;
+}
+
+static bool
+is_command(char *line, bool *is_concept)
+{
+ int len;
+
+ len = strlen(line);
+ if ((line[0] == '`') && (line[len-2] == '\'')) {
+ *is_concept = FALSE;
+ return TRUE;
+ } else if (isupper(line[0]) && isupper(line[1])) {
+ *is_concept = TRUE;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static bool
+diff_command(char *line, char *command)
+{
+ int i;
+
+ for (i = 0; command[i] != '\0' && line[i + 1] == command[i]; i++)
+ ;
+
+ if (command[i] == '\0' && ! isalnumunder(line[i+1])) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+static void
+print_command_line(char *line, bool is_concept)
+{
+ int len;
+ int i;
+
+ if (is_concept) {
+ for (i = 0; line[i] != '\n'; i++) {
+ putchar(concept_char(line[i]));
+ }
+ putchar('\n');
+ } else {
+ len = strlen(line);
+ for (i = 1; i < len - 2; i++) {
+ putchar(line[i]);
+ }
+ putchar('\n');
+ }
+}
+
+static char *putback_line = NULL;
+static char line_buf[MAXLINELEN];
+
+static char *
+get_next_line(FILE *infp)
+{
+ char *tmp;
+
+ if (putback_line != NULL) {
+ tmp = putback_line;
+ putback_line = NULL;
+ return tmp;
+ } else {
+ if (fgets(line_buf, MAXLINELEN, infp) == NULL) {
+ return NULL;
+ } else {
+ /* printf("read %s", line_buf); */
+ return line_buf;
+ }
+ }
+}
+
+static void
+put_line_back(char *line)
+{
+ if (putback_line != NULL) {
+ printf("trying to put back more than one line\n");
+ exit(EXIT_FAILURE);
+ }
+
+ putback_line = line;
+}
Index: util/mkinit.c
===================================================================
RCS file: /home/mercury1/repository/mercury/util/mkinit.c,v
retrieving revision 1.41
diff -u -u -r1.41 mkinit.c
--- mkinit.c 1998/09/29 05:12:06 1.41
+++ mkinit.c 1998/09/29 06:52:29
FIX BUG: MAKE THE DEBUGGER PRINT TO STDOUT, NOT THE CURRENT STREAM
@@ -81,7 +81,7 @@
static const char mercury_funcs[] =
"\n"
"Declare_entry(%s);\n"
- "Declare_entry(mercury__io__print_3_0);\n"
+ "Declare_entry(mercury__io__print_4_0);\n"
"\n"
"#ifdef CONSERVATIVE_GC\n"
"extern char *GC_stackbottom;\n"
@@ -135,7 +135,11 @@
"#endif\n"
" MR_library_initializer = ML_io_init_state;\n"
" MR_library_finalizer = ML_io_finalize_state;\n"
- " MR_library_trace_browser = ENTRY(mercury__io__print_3_0);\n"
+ " MR_io_stdin_stream = ML_io_stdin_stream;\n"
+ " MR_io_stdout_stream = ML_io_stdout_stream;\n"
+ " MR_io_stderr_stream = ML_io_stderr_stream;\n"
+ " MR_io_print_to_cur_stream = ML_io_print_to_cur_stream;\n"
+ " MR_io_print_to_stream = ML_io_print_to_stream;\n"
"#ifdef MR_USE_EXTERNAL_DEBUGGER\n"
" MR_type_name = ML_type_name;\n"
" MR_DI_output_current_vars = ML_DI_output_current_vars;\n"
More information about the developers
mailing list