mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Estimated hours taken: 5 Branches: main Add a new mdb command, 'shell', that allows users to execute shell commands from within the debugger. Allow the user to give up to nine additional arguments to the 'source' command. Occurrences of the strings "$1" through "$9" in the sourced file are replaced by the corresponding additional arguments, allowing for parameterised scripts. Use the two new features mentioned above to add two more mdb commands: one to open a term, goal or exception in an external editor another command to perform a grep on a term, goal or exception (useful for seeing if a value occurs in a big map, for example). NEWS Mention the new commands. doc/mdb_categories: doc/user_guide.texi: Document the new commands. scripts/Mmakefile: scripts/mdb_open: scripts/mdb_vim: Add scripts for the new commands. scripts/mdbrc.in: Add aliases for the new shell, emacs, grep and vim commands. tests/debugger/completion.exp: tests/debugger/mdb_command_test.inp: Adjust for new commands. tests/debugger/save.exp: tests/debugger/save.exp2: Adjust for new commands. Replace system dependent strings with ZZZ instead of XXX. tests/debugger/Mmakefile: tests/debugger/shell.exp: tests/debugger/shell.inp: tests/debugger/shell.m: tests/debugger/shell_test_script: Test the shell and source commands. trace/mercury_trace_cmd_misc.c: Check if there are extra arguments to the source mdb command and pass them to MR_trace_source if there are. trace/mercury_trace_cmd_misc.h: Add shell command handling function prototype. trace/mercury_trace_declarative.c: Call MR_trace_call_system_display_error_on_failure instead of system when displaying benchmarking statistics for the declarative debugger. trace/mercury_trace_internal.c: trace/mercury_trace_internal.h: Implement the shell command and extend the source command to handle the optional extra arguments. trace/mercury_trace_readline.c: trace/mercury_trace_readline.h: Add a new function to read a line and replace all the occurrences of "$[1-9]" with the corresponding value from an array. Delete comments in the .c file that are duplicated in the .h file. trace/mercury_trace_util.c: trace/mercury_trace_util.h: Implement MR_trace_call_system_display_error_on_failure that executes a system call and displays an error message if the system call terminates abnormally.
228 lines
5.5 KiB
C
228 lines
5.5 KiB
C
/*
|
|
** vim: ts=4 sw=4 expandtab
|
|
*/
|
|
/*
|
|
** Copyright (C) 2000-2002, 2004-2006 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 utility functions that can be used by any or all
|
|
** of the various kinds of Mercury debuggers.
|
|
**
|
|
** Author: zs.
|
|
*/
|
|
|
|
#include "mercury_imp.h"
|
|
#include "mercury_trace_util.h"
|
|
#include "mercury_file.h"
|
|
|
|
#include "string.mh"
|
|
|
|
#include <ctype.h>
|
|
|
|
void
|
|
MR_c_file_to_mercury_file(FILE *c_file, MercuryFile *mercury_file)
|
|
{
|
|
MR_mercuryfile_init(c_file, 1, mercury_file);
|
|
}
|
|
|
|
MR_bool
|
|
MR_trace_is_natural_number(const char *word, int *value)
|
|
{
|
|
if (word != NULL && MR_isdigit(*word)) {
|
|
*value = *word - '0';
|
|
word++;
|
|
while (MR_isdigit(*word)) {
|
|
*value = (*value * 10) + *word - '0';
|
|
word++;
|
|
}
|
|
|
|
if (*word == '\0') {
|
|
return MR_TRUE;
|
|
}
|
|
}
|
|
|
|
return MR_FALSE;
|
|
}
|
|
|
|
MR_bool
|
|
MR_trace_is_unsigned(const char *word, MR_Unsigned *value)
|
|
{
|
|
if (word != NULL && MR_isdigit(*word)) {
|
|
*value = *word - '0';
|
|
word++;
|
|
while (MR_isdigit(*word)) {
|
|
*value = (*value * 10) + *word - '0';
|
|
word++;
|
|
}
|
|
|
|
if (*word == '\0') {
|
|
return MR_TRUE;
|
|
}
|
|
}
|
|
|
|
return MR_FALSE;
|
|
}
|
|
|
|
MR_bool
|
|
MR_trace_is_integer(const char *word, MR_Integer *value)
|
|
{
|
|
int sign;
|
|
|
|
if (*word == '-') {
|
|
sign = -1;
|
|
word++;
|
|
} else {
|
|
sign = 1;
|
|
}
|
|
|
|
if (MR_isdigit(*word)) {
|
|
*value = *word - '0';
|
|
word++;
|
|
while (MR_isdigit(*word)) {
|
|
*value = (*value * 10) + *word - '0';
|
|
word++;
|
|
}
|
|
|
|
if (*word == '\0') {
|
|
*value = *value * sign;
|
|
return MR_TRUE;
|
|
}
|
|
}
|
|
|
|
return MR_FALSE;
|
|
}
|
|
|
|
MR_bool
|
|
MR_trace_is_float(const char *word, MR_Float *value)
|
|
{
|
|
return ML_string_to_float((MR_String) word, value);
|
|
}
|
|
|
|
void
|
|
MR_print_stack_regs(FILE *fp, MR_Word *saved_regs)
|
|
{
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
fprintf(fp, "sp = ");
|
|
MR_print_detstackptr(fp, MR_saved_sp(saved_regs));
|
|
fprintf(fp, "\ncurfr = ");
|
|
MR_print_nondstackptr(fp, MR_saved_curfr(saved_regs));
|
|
fprintf(fp, "\nmaxfr = ");
|
|
MR_print_nondstackptr(fp, MR_saved_maxfr(saved_regs));
|
|
fprintf(fp, "\n");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MR_print_heap_regs(FILE *fp, MR_Word *saved_regs)
|
|
{
|
|
#ifndef MR_CONSERVATIVE_GC
|
|
fprintf(fp, "hp = ");
|
|
MR_print_heapptr(fp, MR_saved_hp(saved_regs));
|
|
fprintf(fp, "\nsol_hp = ");
|
|
MR_print_heapptr(fp, MR_saved_sol_hp(saved_regs));
|
|
fprintf(fp, "\nmin_hp_rec = ");
|
|
MR_print_heapptr(fp, MR_saved_min_hp_rec(saved_regs));
|
|
fprintf(fp, "\nglobal_hp = ");
|
|
MR_print_heapptr(fp, MR_saved_global_hp(saved_regs));
|
|
fprintf(fp, "\n");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MR_print_tabling_regs(FILE *fp, MR_Word *saved_regs)
|
|
{
|
|
#ifdef MR_USE_MINIMAL_MODEL_STACK_COPY
|
|
fprintf(fp, "gen_next = %ld\n", (long) MR_saved_gen_next(saved_regs));
|
|
fprintf(fp, "cut_next = %ld\n", (long) MR_saved_cut_next(saved_regs));
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MR_print_succip_reg(FILE *fp, MR_Word *saved_regs)
|
|
{
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
fprintf(fp, "succip = ");
|
|
MR_print_label(fp, MR_saved_succip(saved_regs));
|
|
fprintf(fp, "\n");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MR_print_r_regs(FILE *fp, MR_Word *saved_regs)
|
|
{
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
fprintf(fp, "r1 = %ld (%lx)\n",
|
|
(long) MR_saved_reg_value(saved_regs, 1),
|
|
(long) MR_saved_reg_value(saved_regs, 1));
|
|
fprintf(fp, "r2 = %ld (%lx)\n",
|
|
(long) MR_saved_reg_value(saved_regs, 2),
|
|
(long) MR_saved_reg_value(saved_regs, 2));
|
|
fprintf(fp, "r3 = %ld (%lx)\n",
|
|
(long) MR_saved_reg_value(saved_regs, 3),
|
|
(long) MR_saved_reg_value(saved_regs, 3));
|
|
fprintf(fp, "r4 = %ld (%lx)\n",
|
|
(long) MR_saved_reg_value(saved_regs, 4),
|
|
(long) MR_saved_reg_value(saved_regs, 4));
|
|
fprintf(fp, "r5 = %ld (%lx)\n",
|
|
(long) MR_saved_reg_value(saved_regs, 5),
|
|
(long) MR_saved_reg_value(saved_regs, 5));
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MR_print_debug_vars(FILE *fp, MR_Event_Info *event_info)
|
|
{
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
fprintf(fp, "from event info:\n");
|
|
fprintf(fp, "call event %ld, call seq %ld, depth %ld\n",
|
|
(long) event_info->MR_event_number,
|
|
(long) event_info->MR_call_seqno,
|
|
(long) event_info->MR_call_depth);
|
|
fprintf(fp, "from global vars:\n");
|
|
fprintf(fp, "call event %ld, call seq %ld, depth %ld\n",
|
|
(long) MR_trace_event_number,
|
|
(long) MR_trace_call_seqno,
|
|
(long) MR_trace_call_depth);
|
|
#endif
|
|
}
|
|
|
|
MR_bool
|
|
MR_trace_proc_layout_is_builtin_catch(const MR_Proc_Layout *layout)
|
|
{
|
|
const MR_User_Proc_Id *user;
|
|
|
|
if (MR_PROC_LAYOUT_HAS_PROC_ID(layout)) {
|
|
if (! MR_PROC_LAYOUT_IS_UCI(layout)) {
|
|
user = &layout->MR_sle_user;
|
|
if (MR_streq(user->MR_user_decl_module, "exception") &&
|
|
MR_streq(user->MR_user_name, "builtin_catch") &&
|
|
(user->MR_user_arity == 3))
|
|
{
|
|
return MR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
return MR_FALSE;
|
|
}
|
|
|
|
void
|
|
MR_trace_call_system_display_error_on_failure(FILE *err_stream, char *command)
|
|
{
|
|
int system_rv;
|
|
|
|
if (system(NULL)) {
|
|
system_rv = system(command);
|
|
if (system_rv != 0) {
|
|
fprintf(err_stream,
|
|
"mdb: the shell command returned a non-zero exit code or was"
|
|
" terminated abnormally.\n",
|
|
system_rv);
|
|
}
|
|
} else {
|
|
fprintf(err_stream, "mdb: no shell found.\n");
|
|
}
|
|
}
|