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

1.1       snw         1: /*
1.13    ! snw         2:  *   $Id: mdebug.c,v 1.12 2025/05/01 21:02:31 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.13    ! snw        27:  *   Revision 1.12  2025/05/01 21:02:31  snw
        !            28:  *   Documentation updates
        !            29:  *
1.12      snw        30:  *   Revision 1.11  2025/05/01 17:02:30  snw
                     31:  *   Further debugging improvements
                     32:  *
1.11      snw        33:  *   Revision 1.10  2025/05/01 04:45:15  snw
                     34:  *   Improve backtraces
                     35:  *
1.10      snw        36:  *   Revision 1.9  2025/05/01 03:56:29  snw
                     37:  *   -m
                     38:  *
1.9       snw        39:  *   Revision 1.8  2025/04/30 20:03:09  snw
                     40:  *   Work on entryref parser
                     41:  *
1.8       snw        42:  *   Revision 1.7  2025/04/30 17:19:16  snw
                     43:  *   Improve backtraces in debugger
                     44:  *
1.7       snw        45:  *   Revision 1.6  2025/04/30 14:41:03  snw
                     46:  *   Further debugger work
                     47:  *
1.6       snw        48:  *   Revision 1.5  2025/04/29 18:46:17  snw
                     49:  *   Begin work on interactive debugger
                     50:  *
1.5       snw        51:  *   Revision 1.4  2025/04/28 19:38:55  snw
                     52:  *   Add trace mode
                     53:  *
1.4       snw        54:  *   Revision 1.3  2025/03/09 19:50:47  snw
                     55:  *   Second phase of REUSE compliance and header reformat
                     56:  *
1.3       snw        57:  *
                     58:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
                     59:  * SPDX-License-Identifier: AGPL-3.0-or-later
1.1       snw        60:  **/
                     61: 
                     62: #include <stdio.h>
                     63: #include <stdlib.h>
                     64: #include <string.h>
1.5       snw        65: #include <unistd.h>
                     66: 
                     67: #include "config.h"
                     68: 
                     69: #ifdef HAVE_LIBREADLINE
                     70: #  if defined(HAVE_READLINE_READLINE_H)
                     71: #    include <readline/readline.h>
                     72: #  elif defined(HAVE_READLINE_H)
                     73: #    include <readline.h>
                     74: #  else /* !defined(HAVE_READLINE_H) */
                     75: extern char *readline ();
                     76: #  endif /* !defined(HAVE_READLINE_H) */
                     77: /*char *cmdline = NULL;*/
                     78: #else /* !defined(HAVE_READLINE_READLINE_H) */
                     79:   /* no readline */
                     80: #endif /* HAVE_LIBREADLINE */
                     81: 
                     82: #ifdef HAVE_READLINE_HISTORY
                     83: #  if defined(HAVE_READLINE_HISTORY_H)
                     84: #    include <readline/history.h>
                     85: #  elif defined(HAVE_HISTORY_H)
                     86: #    include <history.h>
                     87: #  else /* !defined(HAVE_HISTORY_H) */
                     88: extern void add_history ();
                     89: extern int write_history ();
                     90: extern int read_history ();
                     91: #  endif /* defined(HAVE_READLINE_HISTORY_H) */
                     92:   /* no history */
                     93: #endif /* HAVE_READLINE_HISTORY */
                     94: 
1.1       snw        95: 
                     96: #include "mpsdef.h"
                     97: #include "mdebug.h"
                     98: #include "freem.h"
                     99: #include "mref.h"
                    100: 
1.13    ! snw       101: #ifdef HAVE_LIBREADLINE
        !           102: char *dbg_commands[] = {
        !           103:     "backtrace",
        !           104:     "continue",
        !           105:     "examine",
        !           106:     "exit",
        !           107:     "halt",
        !           108:     "next",
        !           109:     "quit",
        !           110:     "step",
        !           111:     "trace",
        !           112:     "watch",
        !           113:     NULL
        !           114: };
        !           115: 
        !           116: char **dbg_completion(const char *, int, int);
        !           117: char *dbg_generator(const char *, int);
        !           118: 
        !           119: char **dbg_completion(const char *text, int start, int end)
        !           120: {
        !           121:     if (start > 0) return NULL;
        !           122:     rl_attempted_completion_over = 1;
        !           123:     return rl_completion_matches (text, dbg_generator);
        !           124: }
        !           125: 
        !           126: char *dbg_generator(const char *text, int state)
        !           127: {
        !           128:     static int list_index, len;
        !           129:     char *name;
        !           130: 
        !           131:     if (!state) {
        !           132:         list_index = 0;
        !           133:         len = strlen(text);
        !           134:     }
        !           135: 
        !           136:     while ((name = dbg_commands[list_index++])) {
        !           137:         if (strncmp (name, text, len) == 0) {
        !           138:             return strdup (name);
        !           139:         }
        !           140:     }
        !           141: 
        !           142:     return NULL;
        !           143: }
        !           144: #endif
        !           145: 
1.1       snw       146: dbg_watch dbg_watchlist[MAXWATCH];    /* list of watchpoints */
                    147: short dbg_enable_watch;               /* 0 = watches disabled, 1 = watches enabled */
                    148: int dbg_pending_watches;
                    149: 
                    150: 
                    151: void dbg_init (void)
                    152: {
                    153:     register int i;
                    154: 
                    155:     dbg_enable_watch = 0;
                    156:     dbg_pending_watches = 0;
                    157: 
                    158:     for (i = 0; i < MAXWATCH; i++) {
                    159: 
                    160:         dbg_watchlist[i].varnam = NULL;
                    161:         dbg_watchlist[i].chgct = 0;
                    162: 
                    163:     }
                    164: 
                    165: }
                    166: 
1.11      snw       167: int debugger (int entry_mode, char *entryref)
1.5       snw       168: {
                    169:     
                    170: #if defined(HAVE_LIBREADLINE)    
                    171:     static int first_entry = TRUE;
1.6       snw       172:     static int stepmode = STEPMODE_NONE;
                    173:     
1.5       snw       174:     char *dbg_buf;
                    175:     char dbg_prompt[256];
1.11      snw       176:     int dbg_argc;
1.5       snw       177:     HIST_ENTRY **dbg_hist;
                    178:     int dbg_hist_idx;
                    179:     HIST_ENTRY *dbg_hist_ent;
                    180:     char rouname_buf[256];
1.6       snw       181:     char *savptr;
                    182:     char *dbg_cmd;
1.11      snw       183:     char *dbarg;
1.6       snw       184:     int do_prompt = FALSE;
1.11      snw       185:     char cur_code[512];
                    186:     char tbuf[512];
                    187:     char tbuf2[512];
1.6       snw       188:     register int i;
1.10      snw       189:     register int j;
1.13    ! snw       190: 
        !           191:     rl_attempted_completion_function = dbg_completion;
1.5       snw       192:     set_io (UNIX);
                    193:     
                    194:     if (first_entry) {
                    195:         first_entry = FALSE;
                    196:         
                    197:         printf ("\nEntering debug mode; M commands unavailable.\n");
                    198:         printf ("Type 'exit' to return to direct mode; 'help' for help.\n\n");
1.6       snw       199: 
                    200:         do_prompt = TRUE;
1.5       snw       201:     }
1.6       snw       202:     else {
                    203:         switch (entry_mode) {
                    204:             
                    205:             case DEBENTRY_CMD:
                    206:                 if (stepmode == STEPMODE_CMD) {
                    207:                     do_prompt = TRUE;
                    208:                 }
                    209:                 else {
                    210:                     do_prompt = FALSE;
                    211:                 }
                    212:                     
                    213:                 break;
                    214:                     
                    215:             case DEBENTRY_LINE:
                    216:                 if (stepmode == STEPMODE_CMD || stepmode == STEPMODE_LINE) {
                    217:                     do_prompt = TRUE;
                    218:                 }
                    219:                 else {
                    220:                     do_prompt = FALSE;
                    221:                 }
                    222:                 
                    223:                 break;
                    224:                 
                    225:             case DEBENTRY_BREAKPOINT:
                    226:                 do_prompt = TRUE;
                    227:                 break;
                    228:                 
                    229:             case DEBENTRY_SIGINT:
                    230:                 break;
                    231:         }
                    232:     }
                    233: 
                    234: 
                    235:     if (!do_prompt) return TRUE;
1.5       snw       236: 
                    237:     while (1) {
1.6       snw       238:         
1.7       snw       239:         if (nstx == 0) {
                    240:             stcpy (rouname_buf, rou_name);
                    241:         }
                    242:         else {
                    243:             getraddress (tbuf, nstx);
                    244:             stcpy (rouname_buf, &(tbuf[3]));
                    245:         }
1.5       snw       246:         stcnv_m2c (rouname_buf);
                    247:         
1.11      snw       248:         if (stepmode != STEPMODE_NONE) {
                    249:             getraddress (tbuf, nstx);
                    250:             stcnv_m2c (tbuf);
                    251:             strcpy (tbuf2, &(tbuf[3]));
                    252:             routine_get_line (tbuf2, cur_code);
                    253: 
                    254:             printf ("%s\n", cur_code);
                    255:         }
                    256:         
1.5       snw       257:         snprintf (dbg_prompt, sizeof (dbg_prompt) - 1, "%s $STACK=%d [DEBUG]> ", rouname_buf, nstx);
1.12      snw       258:         if (dbg_enable_watch && dbg_pending_watches) dbg_dump_watchlist ();
1.5       snw       259:         dbg_buf = readline (dbg_prompt);
1.11      snw       260:         
1.5       snw       261:         if (!dbg_buf) continue;
1.11      snw       262:         if (strlen (dbg_buf) < 1) continue;
1.5       snw       263: 
1.11      snw       264:         dbg_argc = 1;
                    265:         for (i = 0; i < strlen (dbg_buf); i++) {
                    266:             if (dbg_buf[i] == ' ') dbg_argc++;
                    267:         }
                    268:         dbarg = dbg_buf;
1.6       snw       269:         savptr = dbg_buf;
                    270:         dbg_cmd = strtok_r (dbg_buf, " ", &savptr);
1.11      snw       271: 
                    272:         dbarg += strlen (dbg_cmd) + 1;
                    273: 
1.6       snw       274:         if ((strcmp (dbg_cmd, "exit") == 0) || (strcmp (dbg_cmd, "quit") == 0)) {
1.5       snw       275:             first_entry = TRUE;
1.6       snw       276:             stepmode = STEPMODE_NONE;
1.5       snw       277:             printf ("\n\nExiting debug mode.\n\n");
                    278:             set_io (MUMPS);
                    279:             return FALSE;
                    280:         }
1.11      snw       281:         else if ((strcmp (dbg_cmd, "examine") == 0) || (strcmp (dbg_cmd, "e") == 0)) {
                    282:             char *glvn;
                    283:             char key[STRLEN];
                    284:             char res[STRLEN];
                    285:             
                    286:             if (dbg_argc < 2) {
                    287:                 printf ("debug:  syntax error\n");
                    288:             }
                    289:             else {
                    290:                 glvn = dbarg;
                    291:                 name_to_key (key, glvn, STRLEN - 1);
                    292:                 if (key[0] != '^') {
                    293:                     symtab (get_sym, key, res);
                    294:                 }
                    295:                 else {
                    296:                     if (key[1] != '$') {
                    297:                         global (get_sym, key, res);
                    298:                     }
                    299:                     else {
                    300:                         ssvn (get_sym, key, res);
                    301:                     }
                    302:                 }
                    303: 
                    304:                 if (merr () != OK) {
                    305:                     if (merr () == M6) {
                    306:                         printf ("examine:  local variable %s is not defined\n", glvn);
                    307:                         merr_clear ();
                    308:                     }
                    309:                     else if (merr () == M7) {
                    310:                         printf ("examine:  global variable %s is not defined\n", glvn);
                    311:                         merr_clear ();
                    312:                     }
                    313:                     else {
                    314:                         printf ("examine:  error retrieving %s\n", glvn);
                    315:                         merr_clear ();
                    316:                     }
                    317:                 }                
                    318:                 else {
                    319:                     stcnv_m2c (res);
                    320:                     printf ("%s=\"%s\"\n", glvn, res);
                    321:                 }
                    322: 
                    323:             }
                    324:         }
                    325:         else if ((strcmp (dbg_cmd, "trace") == 0) || (strcmp (dbg_cmd, "t") == 0)) {
                    326:             if (trace_mode == 0) {                
                    327:                 trace_mode = 1;
                    328:                 printf ("debug:  trace on\n");
                    329:             }
                    330:             else {
                    331:                 trace_mode = 0;
                    332:                 printf ("debug:  trace off\n");
                    333:             }
                    334:             ssvn_job_update ();
                    335:         }
1.6       snw       336:         else if ((strcmp (dbg_cmd, "step") == 0) || (strcmp (dbg_cmd, "s") == 0)) {
                    337:             stepmode = STEPMODE_CMD;
                    338:             return TRUE;
                    339:         }
                    340:         else if ((strcmp (dbg_cmd, "next") == 0) || (strcmp (dbg_cmd, "n") == 0)) {
                    341:             stepmode = STEPMODE_LINE;
                    342:             return TRUE;
                    343:         }
                    344:         else if ((strcmp (dbg_cmd, "continue") == 0) || (strcmp (dbg_cmd, "cont") == 0) || (strcmp(dbg_cmd, "c") == 0)) {
                    345:             stepmode = STEPMODE_CONT;
                    346:             return TRUE;
                    347:         }
                    348:         else if ((strcmp (dbg_cmd, "backtrace") == 0) || (strcmp (dbg_cmd, "bt") == 0)) {
1.9       snw       349:             char tmpbuf[1024];
1.7       snw       350:             char ecbuf[256];
1.10      snw       351:             char m_cmd[10];
1.9       snw       352:             char lref[1024];
                    353:             char bt_mcode[1024];
1.7       snw       354:             
1.10      snw       355:             printf ("%-10s%-10s%s\n", "$STACK", "COMMAND", "PLACE");
                    356:             printf ("%-10s%-10s%s\n", "======", "=======", "=====");
1.6       snw       357:             
                    358:             
                    359:             for (i = 1; i <= nstx; i++) getraddress (callerr[i], i);
                    360:             for (i = nstx; i > 0; i--) {
1.7       snw       361:                 
1.6       snw       362:                 stcpy (tmpbuf, callerr[i]);
                    363:                 stcnv_m2c (tmpbuf);
1.10      snw       364:                 strcpy (ecbuf, &(tmpbuf[1]));
                    365: 
                    366:                 for (j = 0; j < strlen (ecbuf); j++) {
                    367:                     if (ecbuf[j] == ')') {
                    368:                         ecbuf[j] = '\0';
                    369:                         break;
                    370:                     }
                    371:                 }
                    372: 
                    373:                 switch (ecbuf[0]) {
                    374:                     case 'F':
                    375:                         sprintf (m_cmd, "FOR");
                    376:                         break;
                    377:                     case 'D':
                    378:                         sprintf (m_cmd, "DO");
                    379:                         break;
                    380:                 }
                    381:                             
1.7       snw       382:                 
1.10      snw       383:                 printf ("%-10d%-10s%s\n", i, m_cmd, &(tmpbuf[3]));
1.7       snw       384:                 stcpy (lref, &(tmpbuf[3]));
                    385:                 stcnv_m2c (lref);
1.8       snw       386:                 if (routine_get_line (lref, bt_mcode) != NULL) {
1.7       snw       387:                     stcnv_m2c (bt_mcode);
1.10      snw       388:                     printf ("%-20s%s\n", " ", bt_mcode);
1.7       snw       389:                 }
1.6       snw       390:             }
1.10      snw       391:             stcpy (ecbuf, etrap);
                    392:             stcnv_m2c (ecbuf);
                    393:             printf ("ETRAP:\t%s\n", ecbuf);
                    394:             stcpy (ecbuf, ztrap[nstx]);
                    395:             stcnv_m2c (ecbuf);
                    396:             printf ("ZTRAP:\t%s\n", ecbuf);
                    397:             
1.6       snw       398:         }
1.12      snw       399:         else if ((strcmp (dbg_cmd, "halt") == 0) || (strcmp (dbg_cmd, "h") == 0)) {
                    400:             printf ("debug:  forcing halt\n");          
                    401:             exit (0);
                    402:         }
                    403:         else if ((strcmp (dbg_cmd, "watch") == 0) || (strcmp (dbg_cmd, "w") == 0)) {
                    404:             char watchmode;
                    405:             char *glvn;
                    406:             
                    407:             if (dbg_argc == 1) {
                    408:                 switch (dbg_enable_watch) {
                    409:                     case 0:
                    410:                         dbg_enable_watch = 1;
                    411:                         printf ("debug:  watchpoints enabled\n");
                    412:                         break;
                    413:                     case 1:
                    414:                         dbg_enable_watch = 0;
                    415:                         printf ("debug:  watchpoints disabled\n");
                    416:                         break;
                    417:                 }
                    418:             }
                    419:             else {
                    420:                 watchmode = dbarg[0];
                    421:                 glvn = &(dbarg[1]);
                    422:                 
                    423:                 switch (watchmode) {
                    424:                     case '+':
                    425:                         dbg_add_watch (glvn);
                    426:                         break;
                    427:                     case '-':
                    428:                         dbg_remove_watch (glvn);
                    429:                         break;
                    430:                     case '?':
                    431:                         dbg_dump_watch (glvn);
                    432:                         break;
                    433:                     default:
                    434:                         printf ("debug:  watch mode must be +, -, or ?\n");
                    435:                         break;
                    436:                 }
                    437: 
                    438:                 set_io (UNIX);
                    439:             }               
                    440:         }
1.5       snw       441:         else {
                    442:             printf ("DEBUG:  invalid command\r\n");
                    443:         }
                    444:         
                    445:     }
                    446: 
                    447:     return TRUE;
                    448: #else
                    449:     return FALSE;
                    450: #endif
                    451: 
                    452: }
                    453: 
1.1       snw       454: dbg_watch *dbg_add_watch (char *varnam)
                    455: {
                    456:     register int i;
                    457:     int index = -1;
                    458:     short found = 0;
                    459:     dbg_watch *w;
                    460: 
                    461:     if ((w = dbg_find_watch (varnam)) != NULL) {
                    462:         set_io (UNIX);
                    463:         fprintf (stderr, "You are already watching '%s' (changed %d times).\n", dbg_get_watch_name (w->varnam), w->chgct);
                    464:         set_io (MUMPS);
                    465:         return NULL;
                    466:     }
                    467: 
                    468:     for (i = 0; i < MAXWATCH; i++) {
                    469:         if (dbg_watchlist[i].varnam == NULL) {
                    470:             found++;
                    471:             index = i;
                    472:             break;
                    473:         }
                    474:     }
                    475: 
                    476:     if (!found) {
                    477:         set_io (UNIX);
                    478:         fprintf (stderr, "No free watchlist entries available. Try removing an existing watchpoint first.\n");
                    479:         set_io (MUMPS);
                    480: 
                    481:         return NULL;
                    482:     }
                    483: 
1.12      snw       484:     if ((dbg_watchlist[index].varnam = (char *) calloc (256, sizeof (char))) == NULL) {
1.1       snw       485:         set_io (UNIX);
                    486:         fprintf (stderr, "Could not allocate memory for the new watchlist entry.\n");
                    487:         set_io (MUMPS);
                    488: 
                    489:         return NULL;
                    490:     }
                    491: 
                    492:     strcpy (dbg_watchlist[index].varnam, varnam);
                    493:     dbg_watchlist[index].chgct = 0;
                    494: 
                    495:     set_io (UNIX);
1.12      snw       496:     fprintf (stderr, "Added '%s' to the watchlist.\n", varnam);
1.1       snw       497:     set_io (MUMPS);
                    498: 
                    499:     return NULL;
                    500:     
                    501: }
                    502: 
                    503: void dbg_dump_watchlist (void) 
                    504: {
                    505:        register int i;
                    506: 
                    507:        for (i = 0; i < MAXWATCH; i++) {
1.11      snw       508:             if (dbg_watchlist[i].firect) {
                    509:                 dbg_dump_watch (dbg_watchlist[i].varnam);
                    510:             }
1.1       snw       511:        }
                    512: 
                    513:        dbg_pending_watches = 0;
                    514: }
                    515: 
                    516: 
                    517: void dbg_remove_watch (char *varnam)
                    518: {
                    519:     dbg_watch *w;
                    520: 
                    521:     if ((w = dbg_find_watch (varnam)) == NULL) {
                    522:         set_io (UNIX);
                    523:         fprintf (stderr, "'%s' is not being watched.\n", dbg_get_watch_name (varnam));
                    524:         set_io (MUMPS);
                    525: 
                    526:         return;
                    527:     }
                    528: 
                    529:     free (w->varnam);
                    530:     
                    531:     w->chgct = 0;
                    532:     w->firect = 0;
                    533: 
                    534:     set_io (UNIX);
                    535:     printf ("Removed '%s' from the watchlist.\n", dbg_get_watch_name (varnam));
                    536:     set_io (MUMPS);
                    537:     
                    538:     return;
                    539: }
                    540: 
                    541: void dbg_dump_watch (char *varnam)
                    542: {
                    543:     char *ddwbuf;
                    544:     dbg_watch *w;
                    545: 
                    546:     ddwbuf = (char *) malloc (STRLEN * sizeof (char));
                    547:     NULLPTRCHK(ddwbuf,"dbg_dump_watch");
                    548: 
                    549:     if ((w = dbg_find_watch (varnam)) == NULL) {
                    550:         set_io (UNIX);
                    551:         fprintf (stderr, "'%s' is not being watched.\n", dbg_get_watch_name (varnam));
                    552:         set_io (MUMPS);
                    553: 
                    554:         return;
                    555:     }
                    556: 
                    557:     w->firect = 0;
                    558: 
                    559:     if (varnam[0] != '^') {
                    560:        symtab (get_sym, varnam, ddwbuf);
                    561:     }
                    562:     else {
                    563:        if (varnam[1] == '$') {
                    564:                ssvn (get_sym, varnam, ddwbuf);
                    565:        }
                    566:        else {
                    567:                global (get_sym, varnam, ddwbuf);
                    568:        }
                    569:     }
                    570: 
                    571:     stcnv_m2c (ddwbuf);
                    572: 
                    573:     set_io (UNIX);
                    574:     printf (">> WATCHPOINT:  %s => '%s' (changed %d times)\n", dbg_get_watch_name (varnam), ddwbuf, w->chgct);
                    575:     set_io (MUMPS);
                    576: 
                    577:     free (ddwbuf);
                    578: 
                    579: }
                    580: 
                    581: dbg_watch *dbg_find_watch (char *varnam)
                    582: {
                    583:     register int i;
                    584:     
                    585: 
                    586:     for (i = 0; i < MAXWATCH; i++) {
                    587:         if (dbg_watchlist[i].varnam != NULL) {
                    588:             if (strcmp (varnam, dbg_watchlist[i].varnam) == 0) {
                    589:                 return &(dbg_watchlist[i]);
                    590:             }
                    591: 
                    592:         }
                    593:     }
                    594: 
                    595:     return NULL;
                    596: }
                    597: 
                    598: char *dbg_get_watch_name (char *varnam)
                    599: {
                    600:     freem_ref_t *r;
                    601:     char *s;
                    602:     
                    603:     r = (freem_ref_t *) malloc (sizeof (freem_ref_t));
                    604:     NULLPTRCHK(r,"dbg_get_watch_name");
                    605:     
                    606:     s = (char *) malloc (STRLEN * sizeof (char));
                    607:     NULLPTRCHK(s,"dbg_get_watch_name");
                    608:     
                    609:     mref_init (r, MREF_RT_LOCAL, "");
                    610:     internal_to_mref (r, varnam);
                    611:     mref_to_external (r, s);
                    612:         
                    613:     free (r);
                    614:         
                    615:     return s;
                    616:         
                    617: }
                    618: 
                    619: void dbg_fire_watch (char *varnam) {
                    620: 
1.11      snw       621:     dbg_watch *w;
                    622:     
                    623:     if ((w = dbg_find_watch (varnam)) == NULL) {
                    624:         return;
                    625:     }
                    626:     
                    627:     w->chgct++;
                    628:     w->firect++;
                    629:     dbg_pending_watches++;
                    630:     
1.1       snw       631: }

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