version 1.10, 2025/05/01 04:45:15
|
version 1.13, 2025/05/20 18:07:41
|
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.13 2025/05/20 18:07:41 snw |
|
* Add completion to debugger |
|
* |
|
* Revision 1.12 2025/05/01 21:02:31 snw |
|
* Documentation updates |
|
* |
|
* Revision 1.11 2025/05/01 17:02:30 snw |
|
* Further debugging improvements |
|
* |
* Revision 1.10 2025/05/01 04:45:15 snw |
* Revision 1.10 2025/05/01 04:45:15 snw |
* Improve backtraces |
* Improve backtraces |
* |
* |
Line 92 extern int read_history ();
|
Line 101 extern int read_history ();
|
#include "freem.h" |
#include "freem.h" |
#include "mref.h" |
#include "mref.h" |
|
|
|
#ifdef HAVE_LIBREADLINE |
|
char *dbg_commands[] = { |
|
"backtrace", |
|
"continue", |
|
"examine", |
|
"exit", |
|
"halt", |
|
"next", |
|
"quit", |
|
"step", |
|
"trace", |
|
"watch", |
|
NULL |
|
}; |
|
|
|
char **dbg_completion(const char *, int, int); |
|
char *dbg_generator(const char *, int); |
|
|
|
char **dbg_completion(const char *text, int start, int end) |
|
{ |
|
if (start > 0) return NULL; |
|
rl_attempted_completion_over = 1; |
|
return rl_completion_matches (text, dbg_generator); |
|
} |
|
|
|
char *dbg_generator(const char *text, int state) |
|
{ |
|
static int list_index, len; |
|
char *name; |
|
|
|
if (!state) { |
|
list_index = 0; |
|
len = strlen(text); |
|
} |
|
|
|
while ((name = dbg_commands[list_index++])) { |
|
if (strncmp (name, text, len) == 0) { |
|
return strdup (name); |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
#endif |
|
|
dbg_watch dbg_watchlist[MAXWATCH]; /* list of watchpoints */ |
dbg_watch dbg_watchlist[MAXWATCH]; /* list of watchpoints */ |
short dbg_enable_watch; /* 0 = watches disabled, 1 = watches enabled */ |
short dbg_enable_watch; /* 0 = watches disabled, 1 = watches enabled */ |
int dbg_pending_watches; |
int dbg_pending_watches; |
Line 113 void dbg_init (void)
|
Line 167 void dbg_init (void)
|
|
|
} |
} |
|
|
int debugger (int entry_mode, char *curcode) |
int debugger (int entry_mode, char *entryref) |
{ |
{ |
|
|
#if defined(HAVE_LIBREADLINE) |
#if defined(HAVE_LIBREADLINE) |
Line 122 int debugger (int entry_mode, char *curc
|
Line 176 int debugger (int entry_mode, char *curc
|
|
|
char *dbg_buf; |
char *dbg_buf; |
char dbg_prompt[256]; |
char dbg_prompt[256]; |
|
int dbg_argc; |
HIST_ENTRY **dbg_hist; |
HIST_ENTRY **dbg_hist; |
int dbg_hist_idx; |
int dbg_hist_idx; |
HIST_ENTRY *dbg_hist_ent; |
HIST_ENTRY *dbg_hist_ent; |
char rouname_buf[256]; |
char rouname_buf[256]; |
char *savptr; |
char *savptr; |
char *dbg_cmd; |
char *dbg_cmd; |
|
char *dbarg; |
int do_prompt = FALSE; |
int do_prompt = FALSE; |
|
char cur_code[512]; |
|
char tbuf[512]; |
|
char tbuf2[512]; |
register int i; |
register int i; |
register int j; |
register int j; |
|
|
|
rl_attempted_completion_function = dbg_completion; |
set_io (UNIX); |
set_io (UNIX); |
|
|
if (first_entry) { |
if (first_entry) { |
Line 183 int debugger (int entry_mode, char *curc
|
Line 243 int debugger (int entry_mode, char *curc
|
stcpy (rouname_buf, rou_name); |
stcpy (rouname_buf, rou_name); |
} |
} |
else { |
else { |
char tbuf[256]; |
|
|
|
getraddress (tbuf, nstx); |
getraddress (tbuf, nstx); |
stcpy (rouname_buf, &(tbuf[3])); |
stcpy (rouname_buf, &(tbuf[3])); |
} |
} |
stcnv_m2c (rouname_buf); |
stcnv_m2c (rouname_buf); |
|
|
snprintf (dbg_prompt, sizeof (dbg_prompt) - 1, "%s $STACK=%d [DEBUG]> ", rouname_buf, nstx); |
if (stepmode != STEPMODE_NONE) { |
|
getraddress (tbuf, nstx); |
|
stcnv_m2c (tbuf); |
|
strcpy (tbuf2, &(tbuf[3])); |
|
routine_get_line (tbuf2, cur_code); |
|
|
if ((stepmode == STEPMODE_LINE) || (stepmode == STEPMODE_CMD)) { |
printf ("%s\n", cur_code); |
char codbuf[512]; |
|
stcpy (codbuf, curcode); |
|
stcnv_m2c (codbuf); |
|
|
|
printf ("%s\n", codbuf); |
|
} |
} |
|
|
|
snprintf (dbg_prompt, sizeof (dbg_prompt) - 1, "%s $STACK=%d [DEBUG]> ", rouname_buf, nstx); |
|
if (dbg_enable_watch && dbg_pending_watches) dbg_dump_watchlist (); |
dbg_buf = readline (dbg_prompt); |
dbg_buf = readline (dbg_prompt); |
|
|
if (!dbg_buf) continue; |
if (!dbg_buf) continue; |
|
if (strlen (dbg_buf) < 1) continue; |
|
|
|
dbg_argc = 1; |
|
for (i = 0; i < strlen (dbg_buf); i++) { |
|
if (dbg_buf[i] == ' ') dbg_argc++; |
|
} |
|
dbarg = dbg_buf; |
savptr = dbg_buf; |
savptr = dbg_buf; |
dbg_cmd = strtok_r (dbg_buf, " ", &savptr); |
dbg_cmd = strtok_r (dbg_buf, " ", &savptr); |
|
|
|
dbarg += strlen (dbg_cmd) + 1; |
|
|
if ((strcmp (dbg_cmd, "exit") == 0) || (strcmp (dbg_cmd, "quit") == 0)) { |
if ((strcmp (dbg_cmd, "exit") == 0) || (strcmp (dbg_cmd, "quit") == 0)) { |
first_entry = TRUE; |
first_entry = TRUE; |
stepmode = STEPMODE_NONE; |
stepmode = STEPMODE_NONE; |
Line 213 int debugger (int entry_mode, char *curc
|
Line 281 int debugger (int entry_mode, char *curc
|
set_io (MUMPS); |
set_io (MUMPS); |
return FALSE; |
return FALSE; |
} |
} |
|
else if ((strcmp (dbg_cmd, "examine") == 0) || (strcmp (dbg_cmd, "e") == 0)) { |
|
char *glvn; |
|
char key[STRLEN]; |
|
char res[STRLEN]; |
|
|
|
if (dbg_argc < 2) { |
|
printf ("debug: syntax error\n"); |
|
} |
|
else { |
|
glvn = dbarg; |
|
name_to_key (key, glvn, STRLEN - 1); |
|
if (key[0] != '^') { |
|
symtab (get_sym, key, res); |
|
} |
|
else { |
|
if (key[1] != '$') { |
|
global (get_sym, key, res); |
|
} |
|
else { |
|
ssvn (get_sym, key, res); |
|
} |
|
} |
|
|
|
if (merr () != OK) { |
|
if (merr () == M6) { |
|
printf ("examine: local variable %s is not defined\n", glvn); |
|
merr_clear (); |
|
} |
|
else if (merr () == M7) { |
|
printf ("examine: global variable %s is not defined\n", glvn); |
|
merr_clear (); |
|
} |
|
else { |
|
printf ("examine: error retrieving %s\n", glvn); |
|
merr_clear (); |
|
} |
|
} |
|
else { |
|
stcnv_m2c (res); |
|
printf ("%s=\"%s\"\n", glvn, res); |
|
} |
|
|
|
} |
|
} |
|
else if ((strcmp (dbg_cmd, "trace") == 0) || (strcmp (dbg_cmd, "t") == 0)) { |
|
if (trace_mode == 0) { |
|
trace_mode = 1; |
|
printf ("debug: trace on\n"); |
|
} |
|
else { |
|
trace_mode = 0; |
|
printf ("debug: trace off\n"); |
|
} |
|
ssvn_job_update (); |
|
} |
else if ((strcmp (dbg_cmd, "step") == 0) || (strcmp (dbg_cmd, "s") == 0)) { |
else if ((strcmp (dbg_cmd, "step") == 0) || (strcmp (dbg_cmd, "s") == 0)) { |
stepmode = STEPMODE_CMD; |
stepmode = STEPMODE_CMD; |
return TRUE; |
return TRUE; |
Line 276 int debugger (int entry_mode, char *curc
|
Line 399 int debugger (int entry_mode, char *curc
|
printf ("ZTRAP:\t%s\n", ecbuf); |
printf ("ZTRAP:\t%s\n", ecbuf); |
|
|
} |
} |
|
else if ((strcmp (dbg_cmd, "halt") == 0) || (strcmp (dbg_cmd, "h") == 0)) { |
|
printf ("debug: forcing halt\n"); |
|
exit (0); |
|
} |
|
else if ((strcmp (dbg_cmd, "watch") == 0) || (strcmp (dbg_cmd, "w") == 0)) { |
|
char watchmode; |
|
char *glvn; |
|
|
|
if (dbg_argc == 1) { |
|
switch (dbg_enable_watch) { |
|
case 0: |
|
dbg_enable_watch = 1; |
|
printf ("debug: watchpoints enabled\n"); |
|
break; |
|
case 1: |
|
dbg_enable_watch = 0; |
|
printf ("debug: watchpoints disabled\n"); |
|
break; |
|
} |
|
} |
|
else { |
|
watchmode = dbarg[0]; |
|
glvn = &(dbarg[1]); |
|
|
|
switch (watchmode) { |
|
case '+': |
|
dbg_add_watch (glvn); |
|
break; |
|
case '-': |
|
dbg_remove_watch (glvn); |
|
break; |
|
case '?': |
|
dbg_dump_watch (glvn); |
|
break; |
|
default: |
|
printf ("debug: watch mode must be +, -, or ?\n"); |
|
break; |
|
} |
|
|
|
set_io (UNIX); |
|
} |
|
} |
else { |
else { |
printf ("DEBUG: invalid command\r\n"); |
printf ("DEBUG: invalid command\r\n"); |
} |
} |
Line 319 dbg_watch *dbg_add_watch (char *varnam)
|
Line 484 dbg_watch *dbg_add_watch (char *varnam)
|
return NULL; |
return NULL; |
} |
} |
|
|
if ((dbg_watchlist[index].varnam = (char *) malloc (256 * sizeof (char))) == NULL) { |
if ((dbg_watchlist[index].varnam = (char *) calloc (256, sizeof (char))) == NULL) { |
set_io (UNIX); |
set_io (UNIX); |
fprintf (stderr, "Could not allocate memory for the new watchlist entry.\n"); |
fprintf (stderr, "Could not allocate memory for the new watchlist entry.\n"); |
set_io (MUMPS); |
set_io (MUMPS); |
Line 331 dbg_watch *dbg_add_watch (char *varnam)
|
Line 496 dbg_watch *dbg_add_watch (char *varnam)
|
dbg_watchlist[index].chgct = 0; |
dbg_watchlist[index].chgct = 0; |
|
|
set_io (UNIX); |
set_io (UNIX); |
fprintf (stderr, "Added '%s' to the watchlist.\n", dbg_get_watch_name (varnam)); |
fprintf (stderr, "Added '%s' to the watchlist.\n", varnam); |
set_io (MUMPS); |
set_io (MUMPS); |
|
|
return NULL; |
return NULL; |
Line 343 void dbg_dump_watchlist (void)
|
Line 508 void dbg_dump_watchlist (void)
|
register int i; |
register int i; |
|
|
for (i = 0; i < MAXWATCH; i++) { |
for (i = 0; i < MAXWATCH; i++) { |
if (dbg_watchlist[i].firect) { |
if (dbg_watchlist[i].firect) { |
dbg_dump_watch (dbg_watchlist[i].varnam); |
dbg_dump_watch (dbg_watchlist[i].varnam); |
} |
} |
} |
} |
|
|
dbg_pending_watches = 0; |
dbg_pending_watches = 0; |
Line 456 char *dbg_get_watch_name (char *varnam)
|
Line 621 char *dbg_get_watch_name (char *varnam)
|
|
|
void dbg_fire_watch (char *varnam) { |
void dbg_fire_watch (char *varnam) { |
|
|
dbg_watch *w; |
dbg_watch *w; |
|
|
if ((w = dbg_find_watch (varnam)) == NULL) { |
if ((w = dbg_find_watch (varnam)) == NULL) { |
return; |
return; |
} |
} |
|
|
w->chgct++; |
w->chgct++; |
w->firect++; |
w->firect++; |
dbg_pending_watches++; |
dbg_pending_watches++; |
|
|
} |
} |