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