Annotation of freem/src/mdebug.c, revision 1.6
1.1 snw 1: /*
1.6 ! snw 2: * $Id: mdebug.c,v 1.5 2025/04/29 18:46:17 snw Exp $
1.1 snw 3: * debugger enhancements
4: *
5: *
1.2 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.3 snw 8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
1.1 snw 9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
1.4 snw 26: * $Log: mdebug.c,v $
1.6 ! snw 27: * Revision 1.5 2025/04/29 18:46:17 snw
! 28: * Begin work on interactive debugger
! 29: *
1.5 snw 30: * Revision 1.4 2025/04/28 19:38:55 snw
31: * Add trace mode
32: *
1.4 snw 33: * Revision 1.3 2025/03/09 19:50:47 snw
34: * Second phase of REUSE compliance and header reformat
35: *
1.3 snw 36: *
37: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
38: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 39: **/
40:
41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
1.5 snw 44: #include <unistd.h>
45:
46: #include "config.h"
47:
48: #ifdef HAVE_LIBREADLINE
49: # if defined(HAVE_READLINE_READLINE_H)
50: # include <readline/readline.h>
51: # elif defined(HAVE_READLINE_H)
52: # include <readline.h>
53: # else /* !defined(HAVE_READLINE_H) */
54: extern char *readline ();
55: # endif /* !defined(HAVE_READLINE_H) */
56: /*char *cmdline = NULL;*/
57: #else /* !defined(HAVE_READLINE_READLINE_H) */
58: /* no readline */
59: #endif /* HAVE_LIBREADLINE */
60:
61: #ifdef HAVE_READLINE_HISTORY
62: # if defined(HAVE_READLINE_HISTORY_H)
63: # include <readline/history.h>
64: # elif defined(HAVE_HISTORY_H)
65: # include <history.h>
66: # else /* !defined(HAVE_HISTORY_H) */
67: extern void add_history ();
68: extern int write_history ();
69: extern int read_history ();
70: # endif /* defined(HAVE_READLINE_HISTORY_H) */
71: /* no history */
72: #endif /* HAVE_READLINE_HISTORY */
73:
1.1 snw 74:
75: #include "mpsdef.h"
76: #include "mdebug.h"
77: #include "freem.h"
78: #include "mref.h"
79:
80: dbg_watch dbg_watchlist[MAXWATCH]; /* list of watchpoints */
81: short dbg_enable_watch; /* 0 = watches disabled, 1 = watches enabled */
82: int dbg_pending_watches;
83:
84:
85: void dbg_init (void)
86: {
87: register int i;
88:
89: dbg_enable_watch = 0;
90: dbg_pending_watches = 0;
91:
92: for (i = 0; i < MAXWATCH; i++) {
93:
94: dbg_watchlist[i].varnam = NULL;
95: dbg_watchlist[i].chgct = 0;
96:
97: }
98:
99: }
100:
1.6 ! snw 101: int debugger (int entry_mode, char *curcode)
1.5 snw 102: {
103:
104: #if defined(HAVE_LIBREADLINE)
105: static int first_entry = TRUE;
1.6 ! snw 106: static int stepmode = STEPMODE_NONE;
! 107:
1.5 snw 108: char *dbg_buf;
109: char dbg_prompt[256];
110: HIST_ENTRY **dbg_hist;
111: int dbg_hist_idx;
112: HIST_ENTRY *dbg_hist_ent;
113: char rouname_buf[256];
1.6 ! snw 114: char *savptr;
! 115: char *dbg_cmd;
! 116: int do_prompt = FALSE;
! 117: register int i;
1.5 snw 118:
119: set_io (UNIX);
120:
121: if (first_entry) {
122: first_entry = FALSE;
123:
124: printf ("\nEntering debug mode; M commands unavailable.\n");
125: printf ("Type 'exit' to return to direct mode; 'help' for help.\n\n");
1.6 ! snw 126:
! 127: do_prompt = TRUE;
1.5 snw 128: }
1.6 ! snw 129: else {
! 130: switch (entry_mode) {
! 131:
! 132: case DEBENTRY_CMD:
! 133: if (stepmode == STEPMODE_CMD) {
! 134: do_prompt = TRUE;
! 135: }
! 136: else {
! 137: do_prompt = FALSE;
! 138: }
! 139:
! 140: break;
! 141:
! 142: case DEBENTRY_LINE:
! 143: if (stepmode == STEPMODE_CMD || stepmode == STEPMODE_LINE) {
! 144: do_prompt = TRUE;
! 145: }
! 146: else {
! 147: do_prompt = FALSE;
! 148: }
! 149:
! 150: break;
! 151:
! 152: case DEBENTRY_BREAKPOINT:
! 153: do_prompt = TRUE;
! 154: break;
! 155:
! 156: case DEBENTRY_SIGINT:
! 157: break;
! 158: }
! 159: }
! 160:
! 161:
! 162: if (!do_prompt) return TRUE;
1.5 snw 163:
164: while (1) {
1.6 ! snw 165:
! 166: //stcpy (rouname_buf, rou_name);
! 167: getraddress (rouname_buf, nstx);
1.5 snw 168: stcnv_m2c (rouname_buf);
169:
170: snprintf (dbg_prompt, sizeof (dbg_prompt) - 1, "%s $STACK=%d [DEBUG]> ", rouname_buf, nstx);
171:
1.6 ! snw 172: if ((stepmode == STEPMODE_LINE) || (stepmode == STEPMODE_CMD)) {
! 173: char codbuf[512];
! 174: stcpy (codbuf, curcode);
! 175: stcnv_m2c (codbuf);
! 176:
! 177: printf ("%s\n", codbuf);
! 178: }
1.5 snw 179: dbg_buf = readline (dbg_prompt);
180:
181: if (!dbg_buf) continue;
182:
1.6 ! snw 183: savptr = dbg_buf;
! 184: dbg_cmd = strtok_r (dbg_buf, " ", &savptr);
! 185:
! 186: if ((strcmp (dbg_cmd, "exit") == 0) || (strcmp (dbg_cmd, "quit") == 0)) {
1.5 snw 187: first_entry = TRUE;
1.6 ! snw 188: stepmode = STEPMODE_NONE;
1.5 snw 189: printf ("\n\nExiting debug mode.\n\n");
190: set_io (MUMPS);
191: return FALSE;
192: }
1.6 ! snw 193: else if ((strcmp (dbg_cmd, "step") == 0) || (strcmp (dbg_cmd, "s") == 0)) {
! 194: stepmode = STEPMODE_CMD;
! 195: return TRUE;
! 196: }
! 197: else if ((strcmp (dbg_cmd, "next") == 0) || (strcmp (dbg_cmd, "n") == 0)) {
! 198: stepmode = STEPMODE_LINE;
! 199: return TRUE;
! 200: }
! 201: else if ((strcmp (dbg_cmd, "continue") == 0) || (strcmp (dbg_cmd, "cont") == 0) || (strcmp(dbg_cmd, "c") == 0)) {
! 202: stepmode = STEPMODE_CONT;
! 203: return TRUE;
! 204: }
! 205: else if ((strcmp (dbg_cmd, "backtrace") == 0) || (strcmp (dbg_cmd, "bt") == 0)) {
! 206: char tmpbuf[256];
! 207:
! 208: printf ("%-10s%s\n", "$STACK", "(CMND)ENTRY");
! 209: printf ("%-10s%s\n", "======", "===========");
! 210:
! 211:
! 212: for (i = 1; i <= nstx; i++) getraddress (callerr[i], i);
! 213: for (i = nstx; i > 0; i--) {
! 214: stcpy (tmpbuf, callerr[i]);
! 215: stcnv_m2c (tmpbuf);
! 216: printf ("%-10d%s\n", i, tmpbuf);
! 217: }
! 218: }
1.5 snw 219: else {
220: printf ("DEBUG: invalid command\r\n");
221: }
222:
223: }
224:
225: return TRUE;
226: #else
227: return FALSE;
228: #endif
229:
230: }
231:
1.1 snw 232: dbg_watch *dbg_add_watch (char *varnam)
233: {
234: register int i;
235: int index = -1;
236: short found = 0;
237: dbg_watch *w;
238:
239: if ((w = dbg_find_watch (varnam)) != NULL) {
240: set_io (UNIX);
241: fprintf (stderr, "You are already watching '%s' (changed %d times).\n", dbg_get_watch_name (w->varnam), w->chgct);
242: set_io (MUMPS);
243: return NULL;
244: }
245:
246: for (i = 0; i < MAXWATCH; i++) {
247: if (dbg_watchlist[i].varnam == NULL) {
248: found++;
249: index = i;
250: break;
251: }
252: }
253:
254: if (!found) {
255: set_io (UNIX);
256: fprintf (stderr, "No free watchlist entries available. Try removing an existing watchpoint first.\n");
257: set_io (MUMPS);
258:
259: return NULL;
260: }
261:
262: if ((dbg_watchlist[index].varnam = (char *) malloc (256 * sizeof (char))) == NULL) {
263: set_io (UNIX);
264: fprintf (stderr, "Could not allocate memory for the new watchlist entry.\n");
265: set_io (MUMPS);
266:
267: return NULL;
268: }
269:
270: strcpy (dbg_watchlist[index].varnam, varnam);
271: dbg_watchlist[index].chgct = 0;
272:
273: set_io (UNIX);
274: fprintf (stderr, "Added '%s' to the watchlist.\n", dbg_get_watch_name (varnam));
275: set_io (MUMPS);
276:
277: return NULL;
278:
279: }
280:
281: void dbg_dump_watchlist (void)
282: {
283: register int i;
284:
285: for (i = 0; i < MAXWATCH; i++) {
286: if (dbg_watchlist[i].firect) {
287: dbg_dump_watch (dbg_watchlist[i].varnam);
288: }
289: }
290:
291: dbg_pending_watches = 0;
292: }
293:
294:
295: void dbg_remove_watch (char *varnam)
296: {
297: dbg_watch *w;
298:
299: if ((w = dbg_find_watch (varnam)) == NULL) {
300: set_io (UNIX);
301: fprintf (stderr, "'%s' is not being watched.\n", dbg_get_watch_name (varnam));
302: set_io (MUMPS);
303:
304: return;
305: }
306:
307: free (w->varnam);
308:
309: w->chgct = 0;
310: w->firect = 0;
311:
312: set_io (UNIX);
313: printf ("Removed '%s' from the watchlist.\n", dbg_get_watch_name (varnam));
314: set_io (MUMPS);
315:
316: return;
317: }
318:
319: void dbg_dump_watch (char *varnam)
320: {
321: char *ddwbuf;
322: dbg_watch *w;
323:
324: ddwbuf = (char *) malloc (STRLEN * sizeof (char));
325: NULLPTRCHK(ddwbuf,"dbg_dump_watch");
326:
327: if ((w = dbg_find_watch (varnam)) == NULL) {
328: set_io (UNIX);
329: fprintf (stderr, "'%s' is not being watched.\n", dbg_get_watch_name (varnam));
330: set_io (MUMPS);
331:
332: return;
333: }
334:
335: w->firect = 0;
336:
337: if (varnam[0] != '^') {
338: symtab (get_sym, varnam, ddwbuf);
339: }
340: else {
341: if (varnam[1] == '$') {
342: ssvn (get_sym, varnam, ddwbuf);
343: }
344: else {
345: global (get_sym, varnam, ddwbuf);
346: }
347: }
348:
349: stcnv_m2c (ddwbuf);
350:
351: set_io (UNIX);
352: printf (">> WATCHPOINT: %s => '%s' (changed %d times)\n", dbg_get_watch_name (varnam), ddwbuf, w->chgct);
353: set_io (MUMPS);
354:
355: free (ddwbuf);
356:
357: }
358:
359: dbg_watch *dbg_find_watch (char *varnam)
360: {
361: register int i;
362:
363:
364: for (i = 0; i < MAXWATCH; i++) {
365: if (dbg_watchlist[i].varnam != NULL) {
366: if (strcmp (varnam, dbg_watchlist[i].varnam) == 0) {
367: return &(dbg_watchlist[i]);
368: }
369:
370: }
371: }
372:
373: return NULL;
374: }
375:
376: char *dbg_get_watch_name (char *varnam)
377: {
378: freem_ref_t *r;
379: char *s;
380:
381: r = (freem_ref_t *) malloc (sizeof (freem_ref_t));
382: NULLPTRCHK(r,"dbg_get_watch_name");
383:
384: s = (char *) malloc (STRLEN * sizeof (char));
385: NULLPTRCHK(s,"dbg_get_watch_name");
386:
387: mref_init (r, MREF_RT_LOCAL, "");
388: internal_to_mref (r, varnam);
389: mref_to_external (r, s);
390:
391: free (r);
392:
393: return s;
394:
395: }
396:
397: void dbg_fire_watch (char *varnam) {
398:
399: dbg_watch *w;
400:
401: if ((w = dbg_find_watch (varnam)) == NULL) {
402: return;
403: }
404:
405: w->chgct++;
406: w->firect++;
407: dbg_pending_watches++;
1.4 snw 408:
1.1 snw 409: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>