version 1.4, 2025/04/28 19:38:55
|
version 1.10, 2025/05/01 04:45:15
|
Line 24
|
Line 24
|
* along with FreeM. If not, see <https://www.gnu.org/licenses/>. |
* along with FreeM. If not, see <https://www.gnu.org/licenses/>. |
* |
* |
* $Log$ |
* $Log$ |
|
* Revision 1.10 2025/05/01 04:45:15 snw |
|
* Improve backtraces |
|
* |
|
* Revision 1.9 2025/05/01 03:56:29 snw |
|
* -m |
|
* |
|
* Revision 1.8 2025/04/30 20:03:09 snw |
|
* Work on entryref parser |
|
* |
|
* Revision 1.7 2025/04/30 17:19:16 snw |
|
* Improve backtraces in debugger |
|
* |
|
* Revision 1.6 2025/04/30 14:41:03 snw |
|
* Further debugger work |
|
* |
|
* Revision 1.5 2025/04/29 18:46:17 snw |
|
* Begin work on interactive debugger |
|
* |
* Revision 1.4 2025/04/28 19:38:55 snw |
* Revision 1.4 2025/04/28 19:38:55 snw |
* Add trace mode |
* Add trace mode |
* |
* |
Line 38
|
Line 56
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <unistd.h> |
|
|
|
#include "config.h" |
|
|
|
#ifdef HAVE_LIBREADLINE |
|
# if defined(HAVE_READLINE_READLINE_H) |
|
# include <readline/readline.h> |
|
# elif defined(HAVE_READLINE_H) |
|
# include <readline.h> |
|
# else /* !defined(HAVE_READLINE_H) */ |
|
extern char *readline (); |
|
# endif /* !defined(HAVE_READLINE_H) */ |
|
/*char *cmdline = NULL;*/ |
|
#else /* !defined(HAVE_READLINE_READLINE_H) */ |
|
/* no readline */ |
|
#endif /* HAVE_LIBREADLINE */ |
|
|
|
#ifdef HAVE_READLINE_HISTORY |
|
# if defined(HAVE_READLINE_HISTORY_H) |
|
# include <readline/history.h> |
|
# elif defined(HAVE_HISTORY_H) |
|
# include <history.h> |
|
# else /* !defined(HAVE_HISTORY_H) */ |
|
extern void add_history (); |
|
extern int write_history (); |
|
extern int read_history (); |
|
# endif /* defined(HAVE_READLINE_HISTORY_H) */ |
|
/* no history */ |
|
#endif /* HAVE_READLINE_HISTORY */ |
|
|
|
|
#include "mpsdef.h" |
#include "mpsdef.h" |
#include "mdebug.h" |
#include "mdebug.h" |
Line 65 void dbg_init (void)
|
Line 113 void dbg_init (void)
|
|
|
} |
} |
|
|
|
int debugger (int entry_mode, char *curcode) |
|
{ |
|
|
|
#if defined(HAVE_LIBREADLINE) |
|
static int first_entry = TRUE; |
|
static int stepmode = STEPMODE_NONE; |
|
|
|
char *dbg_buf; |
|
char dbg_prompt[256]; |
|
HIST_ENTRY **dbg_hist; |
|
int dbg_hist_idx; |
|
HIST_ENTRY *dbg_hist_ent; |
|
char rouname_buf[256]; |
|
char *savptr; |
|
char *dbg_cmd; |
|
int do_prompt = FALSE; |
|
register int i; |
|
register int j; |
|
|
|
set_io (UNIX); |
|
|
|
if (first_entry) { |
|
first_entry = FALSE; |
|
|
|
printf ("\nEntering debug mode; M commands unavailable.\n"); |
|
printf ("Type 'exit' to return to direct mode; 'help' for help.\n\n"); |
|
|
|
do_prompt = TRUE; |
|
} |
|
else { |
|
switch (entry_mode) { |
|
|
|
case DEBENTRY_CMD: |
|
if (stepmode == STEPMODE_CMD) { |
|
do_prompt = TRUE; |
|
} |
|
else { |
|
do_prompt = FALSE; |
|
} |
|
|
|
break; |
|
|
|
case DEBENTRY_LINE: |
|
if (stepmode == STEPMODE_CMD || stepmode == STEPMODE_LINE) { |
|
do_prompt = TRUE; |
|
} |
|
else { |
|
do_prompt = FALSE; |
|
} |
|
|
|
break; |
|
|
|
case DEBENTRY_BREAKPOINT: |
|
do_prompt = TRUE; |
|
break; |
|
|
|
case DEBENTRY_SIGINT: |
|
break; |
|
} |
|
} |
|
|
|
|
|
if (!do_prompt) return TRUE; |
|
|
|
while (1) { |
|
|
|
if (nstx == 0) { |
|
stcpy (rouname_buf, rou_name); |
|
} |
|
else { |
|
char tbuf[256]; |
|
|
|
getraddress (tbuf, nstx); |
|
stcpy (rouname_buf, &(tbuf[3])); |
|
} |
|
stcnv_m2c (rouname_buf); |
|
|
|
snprintf (dbg_prompt, sizeof (dbg_prompt) - 1, "%s $STACK=%d [DEBUG]> ", rouname_buf, nstx); |
|
|
|
if ((stepmode == STEPMODE_LINE) || (stepmode == STEPMODE_CMD)) { |
|
char codbuf[512]; |
|
stcpy (codbuf, curcode); |
|
stcnv_m2c (codbuf); |
|
|
|
printf ("%s\n", codbuf); |
|
} |
|
dbg_buf = readline (dbg_prompt); |
|
|
|
if (!dbg_buf) continue; |
|
|
|
savptr = dbg_buf; |
|
dbg_cmd = strtok_r (dbg_buf, " ", &savptr); |
|
|
|
if ((strcmp (dbg_cmd, "exit") == 0) || (strcmp (dbg_cmd, "quit") == 0)) { |
|
first_entry = TRUE; |
|
stepmode = STEPMODE_NONE; |
|
printf ("\n\nExiting debug mode.\n\n"); |
|
set_io (MUMPS); |
|
return FALSE; |
|
} |
|
else if ((strcmp (dbg_cmd, "step") == 0) || (strcmp (dbg_cmd, "s") == 0)) { |
|
stepmode = STEPMODE_CMD; |
|
return TRUE; |
|
} |
|
else if ((strcmp (dbg_cmd, "next") == 0) || (strcmp (dbg_cmd, "n") == 0)) { |
|
stepmode = STEPMODE_LINE; |
|
return TRUE; |
|
} |
|
else if ((strcmp (dbg_cmd, "continue") == 0) || (strcmp (dbg_cmd, "cont") == 0) || (strcmp(dbg_cmd, "c") == 0)) { |
|
stepmode = STEPMODE_CONT; |
|
return TRUE; |
|
} |
|
else if ((strcmp (dbg_cmd, "backtrace") == 0) || (strcmp (dbg_cmd, "bt") == 0)) { |
|
char tmpbuf[1024]; |
|
char ecbuf[256]; |
|
char m_cmd[10]; |
|
char lref[1024]; |
|
char bt_mcode[1024]; |
|
|
|
printf ("%-10s%-10s%s\n", "$STACK", "COMMAND", "PLACE"); |
|
printf ("%-10s%-10s%s\n", "======", "=======", "====="); |
|
|
|
|
|
for (i = 1; i <= nstx; i++) getraddress (callerr[i], i); |
|
for (i = nstx; i > 0; i--) { |
|
|
|
stcpy (tmpbuf, callerr[i]); |
|
stcnv_m2c (tmpbuf); |
|
strcpy (ecbuf, &(tmpbuf[1])); |
|
|
|
for (j = 0; j < strlen (ecbuf); j++) { |
|
if (ecbuf[j] == ')') { |
|
ecbuf[j] = '\0'; |
|
break; |
|
} |
|
} |
|
|
|
switch (ecbuf[0]) { |
|
case 'F': |
|
sprintf (m_cmd, "FOR"); |
|
break; |
|
case 'D': |
|
sprintf (m_cmd, "DO"); |
|
break; |
|
} |
|
|
|
|
|
printf ("%-10d%-10s%s\n", i, m_cmd, &(tmpbuf[3])); |
|
stcpy (lref, &(tmpbuf[3])); |
|
stcnv_m2c (lref); |
|
if (routine_get_line (lref, bt_mcode) != NULL) { |
|
stcnv_m2c (bt_mcode); |
|
printf ("%-20s%s\n", " ", bt_mcode); |
|
} |
|
} |
|
stcpy (ecbuf, etrap); |
|
stcnv_m2c (ecbuf); |
|
printf ("ETRAP:\t%s\n", ecbuf); |
|
stcpy (ecbuf, ztrap[nstx]); |
|
stcnv_m2c (ecbuf); |
|
printf ("ZTRAP:\t%s\n", ecbuf); |
|
|
|
} |
|
else { |
|
printf ("DEBUG: invalid command\r\n"); |
|
} |
|
|
|
} |
|
|
|
return TRUE; |
|
#else |
|
return FALSE; |
|
#endif |
|
|
|
} |
|
|
dbg_watch *dbg_add_watch (char *varnam) |
dbg_watch *dbg_add_watch (char *varnam) |
{ |
{ |
register int i; |
register int i; |