Annotation of freem/src/mdebug.c, revision 1.5

1.1       snw         1: /*
1.5     ! snw         2:  *   $Id: mdebug.c,v 1.4 2025/04/28 19:38:55 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.5     ! snw        27:  *   Revision 1.4  2025/04/28 19:38:55  snw
        !            28:  *   Add trace mode
        !            29:  *
1.4       snw        30:  *   Revision 1.3  2025/03/09 19:50:47  snw
                     31:  *   Second phase of REUSE compliance and header reformat
                     32:  *
1.3       snw        33:  *
                     34:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
                     35:  * SPDX-License-Identifier: AGPL-3.0-or-later
1.1       snw        36:  **/
                     37: 
                     38: #include <stdio.h>
                     39: #include <stdlib.h>
                     40: #include <string.h>
1.5     ! snw        41: #include <unistd.h>
        !            42: 
        !            43: #include "config.h"
        !            44: 
        !            45: #ifdef HAVE_LIBREADLINE
        !            46: #  if defined(HAVE_READLINE_READLINE_H)
        !            47: #    include <readline/readline.h>
        !            48: #  elif defined(HAVE_READLINE_H)
        !            49: #    include <readline.h>
        !            50: #  else /* !defined(HAVE_READLINE_H) */
        !            51: extern char *readline ();
        !            52: #  endif /* !defined(HAVE_READLINE_H) */
        !            53: /*char *cmdline = NULL;*/
        !            54: #else /* !defined(HAVE_READLINE_READLINE_H) */
        !            55:   /* no readline */
        !            56: #endif /* HAVE_LIBREADLINE */
        !            57: 
        !            58: #ifdef HAVE_READLINE_HISTORY
        !            59: #  if defined(HAVE_READLINE_HISTORY_H)
        !            60: #    include <readline/history.h>
        !            61: #  elif defined(HAVE_HISTORY_H)
        !            62: #    include <history.h>
        !            63: #  else /* !defined(HAVE_HISTORY_H) */
        !            64: extern void add_history ();
        !            65: extern int write_history ();
        !            66: extern int read_history ();
        !            67: #  endif /* defined(HAVE_READLINE_HISTORY_H) */
        !            68:   /* no history */
        !            69: #endif /* HAVE_READLINE_HISTORY */
        !            70: 
1.1       snw        71: 
                     72: #include "mpsdef.h"
                     73: #include "mdebug.h"
                     74: #include "freem.h"
                     75: #include "mref.h"
                     76: 
                     77: dbg_watch dbg_watchlist[MAXWATCH];    /* list of watchpoints */
                     78: short dbg_enable_watch;               /* 0 = watches disabled, 1 = watches enabled */
                     79: int dbg_pending_watches;
                     80: 
                     81: 
                     82: void dbg_init (void)
                     83: {
                     84:     register int i;
                     85: 
                     86:     dbg_enable_watch = 0;
                     87:     dbg_pending_watches = 0;
                     88: 
                     89:     for (i = 0; i < MAXWATCH; i++) {
                     90: 
                     91:         dbg_watchlist[i].varnam = NULL;
                     92:         dbg_watchlist[i].chgct = 0;
                     93: 
                     94:     }
                     95: 
                     96: }
                     97: 
1.5     ! snw        98: int debugger (void)
        !            99: {
        !           100:     
        !           101: #if defined(HAVE_LIBREADLINE)    
        !           102:     static int first_entry = TRUE;
        !           103:     char *dbg_buf;
        !           104:     char dbg_prompt[256];
        !           105:     HIST_ENTRY **dbg_hist;
        !           106:     int dbg_hist_idx;
        !           107:     HIST_ENTRY *dbg_hist_ent;
        !           108:     char rouname_buf[256];
        !           109:     
        !           110:     set_io (UNIX);
        !           111:     
        !           112:     if (first_entry) {
        !           113:         first_entry = FALSE;
        !           114:         
        !           115:         printf ("\nEntering debug mode; M commands unavailable.\n");
        !           116:         printf ("Type 'exit' to return to direct mode; 'help' for help.\n\n");
        !           117:     }
        !           118: 
        !           119:     while (1) {
        !           120:         stcpy (rouname_buf, rou_name);
        !           121:         stcnv_m2c (rouname_buf);
        !           122:         
        !           123:         snprintf (dbg_prompt, sizeof (dbg_prompt) - 1, "%s $STACK=%d [DEBUG]> ", rouname_buf, nstx);
        !           124: 
        !           125:         dbg_buf = readline (dbg_prompt);
        !           126: 
        !           127:         if (!dbg_buf) continue;
        !           128: 
        !           129:         if (strcmp (dbg_buf, "exit") == 0) {
        !           130:             first_entry = TRUE;
        !           131:             printf ("\n\nExiting debug mode.\n\n");
        !           132:             set_io (MUMPS);
        !           133:             return FALSE;
        !           134:         }
        !           135:         else {
        !           136:             printf ("DEBUG:  invalid command\r\n");
        !           137:         }
        !           138:         
        !           139:     }
        !           140: 
        !           141:     return TRUE;
        !           142: #else
        !           143:     return FALSE;
        !           144: #endif
        !           145: 
        !           146: }
        !           147: 
1.1       snw       148: dbg_watch *dbg_add_watch (char *varnam)
                    149: {
                    150:     register int i;
                    151:     int index = -1;
                    152:     short found = 0;
                    153:     dbg_watch *w;
                    154: 
                    155:     if ((w = dbg_find_watch (varnam)) != NULL) {
                    156:         set_io (UNIX);
                    157:         fprintf (stderr, "You are already watching '%s' (changed %d times).\n", dbg_get_watch_name (w->varnam), w->chgct);
                    158:         set_io (MUMPS);
                    159:         return NULL;
                    160:     }
                    161: 
                    162:     for (i = 0; i < MAXWATCH; i++) {
                    163:         if (dbg_watchlist[i].varnam == NULL) {
                    164:             found++;
                    165:             index = i;
                    166:             break;
                    167:         }
                    168:     }
                    169: 
                    170:     if (!found) {
                    171:         set_io (UNIX);
                    172:         fprintf (stderr, "No free watchlist entries available. Try removing an existing watchpoint first.\n");
                    173:         set_io (MUMPS);
                    174: 
                    175:         return NULL;
                    176:     }
                    177: 
                    178:     if ((dbg_watchlist[index].varnam = (char *) malloc (256 * sizeof (char))) == NULL) {
                    179:         set_io (UNIX);
                    180:         fprintf (stderr, "Could not allocate memory for the new watchlist entry.\n");
                    181:         set_io (MUMPS);
                    182: 
                    183:         return NULL;
                    184:     }
                    185: 
                    186:     strcpy (dbg_watchlist[index].varnam, varnam);
                    187:     dbg_watchlist[index].chgct = 0;
                    188: 
                    189:     set_io (UNIX);
                    190:     fprintf (stderr, "Added '%s' to the watchlist.\n", dbg_get_watch_name (varnam));
                    191:     set_io (MUMPS);
                    192: 
                    193:     return NULL;
                    194:     
                    195: }
                    196: 
                    197: void dbg_dump_watchlist (void) 
                    198: {
                    199:        register int i;
                    200: 
                    201:        for (i = 0; i < MAXWATCH; i++) {
                    202:                if (dbg_watchlist[i].firect) {
                    203:                        dbg_dump_watch (dbg_watchlist[i].varnam);
                    204:                }
                    205:        }
                    206: 
                    207:        dbg_pending_watches = 0;
                    208: }
                    209: 
                    210: 
                    211: void dbg_remove_watch (char *varnam)
                    212: {
                    213:     dbg_watch *w;
                    214: 
                    215:     if ((w = dbg_find_watch (varnam)) == NULL) {
                    216:         set_io (UNIX);
                    217:         fprintf (stderr, "'%s' is not being watched.\n", dbg_get_watch_name (varnam));
                    218:         set_io (MUMPS);
                    219: 
                    220:         return;
                    221:     }
                    222: 
                    223:     free (w->varnam);
                    224:     
                    225:     w->chgct = 0;
                    226:     w->firect = 0;
                    227: 
                    228:     set_io (UNIX);
                    229:     printf ("Removed '%s' from the watchlist.\n", dbg_get_watch_name (varnam));
                    230:     set_io (MUMPS);
                    231:     
                    232:     return;
                    233: }
                    234: 
                    235: void dbg_dump_watch (char *varnam)
                    236: {
                    237:     char *ddwbuf;
                    238:     dbg_watch *w;
                    239: 
                    240:     ddwbuf = (char *) malloc (STRLEN * sizeof (char));
                    241:     NULLPTRCHK(ddwbuf,"dbg_dump_watch");
                    242: 
                    243:     if ((w = dbg_find_watch (varnam)) == NULL) {
                    244:         set_io (UNIX);
                    245:         fprintf (stderr, "'%s' is not being watched.\n", dbg_get_watch_name (varnam));
                    246:         set_io (MUMPS);
                    247: 
                    248:         return;
                    249:     }
                    250: 
                    251:     w->firect = 0;
                    252: 
                    253:     if (varnam[0] != '^') {
                    254:        symtab (get_sym, varnam, ddwbuf);
                    255:     }
                    256:     else {
                    257:        if (varnam[1] == '$') {
                    258:                ssvn (get_sym, varnam, ddwbuf);
                    259:        }
                    260:        else {
                    261:                global (get_sym, varnam, ddwbuf);
                    262:        }
                    263:     }
                    264: 
                    265:     stcnv_m2c (ddwbuf);
                    266: 
                    267:     set_io (UNIX);
                    268:     printf (">> WATCHPOINT:  %s => '%s' (changed %d times)\n", dbg_get_watch_name (varnam), ddwbuf, w->chgct);
                    269:     set_io (MUMPS);
                    270: 
                    271:     free (ddwbuf);
                    272: 
                    273: }
                    274: 
                    275: dbg_watch *dbg_find_watch (char *varnam)
                    276: {
                    277:     register int i;
                    278:     
                    279: 
                    280:     for (i = 0; i < MAXWATCH; i++) {
                    281:         if (dbg_watchlist[i].varnam != NULL) {
                    282:             if (strcmp (varnam, dbg_watchlist[i].varnam) == 0) {
                    283:                 return &(dbg_watchlist[i]);
                    284:             }
                    285: 
                    286:         }
                    287:     }
                    288: 
                    289:     return NULL;
                    290: }
                    291: 
                    292: char *dbg_get_watch_name (char *varnam)
                    293: {
                    294:     freem_ref_t *r;
                    295:     char *s;
                    296:     
                    297:     r = (freem_ref_t *) malloc (sizeof (freem_ref_t));
                    298:     NULLPTRCHK(r,"dbg_get_watch_name");
                    299:     
                    300:     s = (char *) malloc (STRLEN * sizeof (char));
                    301:     NULLPTRCHK(s,"dbg_get_watch_name");
                    302:     
                    303:     mref_init (r, MREF_RT_LOCAL, "");
                    304:     internal_to_mref (r, varnam);
                    305:     mref_to_external (r, s);
                    306:         
                    307:     free (r);
                    308:         
                    309:     return s;
                    310:         
                    311: }
                    312: 
                    313: void dbg_fire_watch (char *varnam) {
                    314: 
                    315:        dbg_watch *w;
                    316: 
                    317:        if ((w = dbg_find_watch (varnam)) == NULL) {
                    318:                return;
                    319:        }
                    320: 
                    321:        w->chgct++;
                    322:        w->firect++;
                    323:        dbg_pending_watches++;
1.4       snw       324:         
1.1       snw       325: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>