LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_debugger.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 15 831 1.8 %
Date: 2021-09-14 22:17:06 Functions: 3 30 10.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (author) M.L. Kersten
      11             :  * For documentation see website.
      12             :  */
      13             : #include "monetdb_config.h"
      14             : #include "mal.h"
      15             : #include "mal_debugger.h"
      16             : #include "mal_interpreter.h"  /* for getArgReference() */
      17             : #include "mal_listing.h"
      18             : #include "mal_function.h"
      19             : #include "mal_parser.h"
      20             : #include "mal_namespace.h"
      21             : #include "mal_private.h"
      22             : 
      23             : typedef struct {
      24             :         MalBlkPtr brkBlock[MAXBREAKS];
      25             :         int brkPc[MAXBREAKS];
      26             :         int brkVar[MAXBREAKS];
      27             :         const char *brkMod[MAXBREAKS];
      28             :         const char *brkFcn[MAXBREAKS];
      29             :         char brkCmd[MAXBREAKS];
      30             :         str brkRequest[MAXBREAKS];
      31             :         int brkTop;
      32             : } mdbStateRecord, *mdbState;
      33             : 
      34             : typedef struct MDBSTATE{
      35             :         MalBlkPtr mb;
      36             :         MalStkPtr stk;
      37             :         InstrPtr p;
      38             :         int pc;
      39             : } MdbState;
      40             : 
      41             : #define skipBlanc(c, X)    while (*(X) && isspace((unsigned char) *X)) { X++; }
      42             : #define skipNonBlanc(c, X) while (*(X) && !isspace((unsigned char) *X)) { X++; }
      43             : #define skipWord(c, X)     while (*(X) && (isalnum((unsigned char) *X))) { X++; } \
      44             :         skipBlanc(c, X);
      45             : 
      46             : #define skipModule(C,B)\
      47             : {\
      48             :                 skipWord(C, B); \
      49             :                 skipBlanc(C, B);        \
      50             :                 c = strchr(B,'.');      \
      51             :                 if( c ){        \
      52             :                         B = c + 1;      \
      53             :                         skipWord(cntxt, B);     \
      54             :                         skipBlanc(cntxt, B);    \
      55             :                 }       \
      56             :                 c = strchr(B,']');      \
      57             :                 if (c)  \
      58             :                         B = c + 1;      \
      59             : }
      60             : 
      61             : /* Utilities
      62             :  * Dumping a stack on a file is primarilly used for debugging.
      63             :  * Printing the stack requires access to both the symbol table and
      64             :  * the stackframes in most cases.
      65             :  * Beware that a stack frame need not be initialized with null values.
      66             :  * It has been zeroed upon creation.
      67             :  *
      68             :  * The routine  can also be used to inspect the symbol table of
      69             :  * arbitrary functions.
      70             :  */
      71             : static void
      72           0 : printStackHdr(stream *f, MalBlkPtr mb, ValPtr v, int index)
      73             : {
      74           0 :         if (v == 0 && isVarConstant(mb, index))
      75           0 :                 v = &getVarConstant(mb, index);
      76           0 :         mnstr_printf(f, "#[%2d] %5s", index, getVarName(mb,index));
      77           0 :         mnstr_printf(f, " (%d,%d,%d) = ", getBeginScope(mb,index), getLastUpdate(mb,index),getEndScope(mb, index));
      78           0 :         if (v)
      79           0 :                 ATOMprint(v->vtype, VALptr(v), f);
      80           0 : }
      81             : 
      82             : static void
      83           0 : printBATproperties(stream *f, BAT *b)
      84             : {
      85           0 :         mnstr_printf(f, " count=" BUNFMT " lrefs=%d ",
      86           0 :                         BATcount(b), BBP_lrefs(b->batCacheid));
      87           0 :         if (BBP_refs(b->batCacheid) - 1)
      88           0 :                 mnstr_printf(f, " refs=%d ", BBP_refs(b->batCacheid));
      89           0 :         if (b->batSharecnt)
      90           0 :                 mnstr_printf(f, " views=%d", b->batSharecnt);
      91           0 :         if (b->theap->parentid != b->batCacheid)
      92           0 :                 mnstr_printf(f, "view on %s ", BBP_logical(b->theap->parentid));
      93           0 : }
      94             : 
      95             : static void
      96           0 : printBATelm(stream *f, bat i, BUN cnt, BUN first)
      97             : {
      98             :         BAT *b, *bs = NULL;
      99             :         str tpe;
     100             : 
     101           0 :         b = BATdescriptor(i);
     102           0 :         if (b) {
     103           0 :                 tpe = getTypeName(newBatType(b->ttype));
     104           0 :                 mnstr_printf(f, ":%s ", tpe);
     105           0 :                 GDKfree(tpe);
     106           0 :                 printBATproperties(f, b);
     107             :                 /* perform property checking */
     108           0 :                 BATassertProps(b);
     109           0 :                 mnstr_printf(f, "\n");
     110           0 :                 if (cnt && BATcount(b) > 0) {
     111           0 :                         if (cnt < BATcount(b)) {
     112           0 :                                 mnstr_printf(f, "Sample " BUNFMT " out of " BUNFMT "\n", cnt, BATcount(b));
     113             :                         }
     114             :                         /* cut out a portion of the BAT for display */
     115           0 :                         bs = BATslice(b, first, first + cnt);
     116             :                         /* get the void values */
     117           0 :                         if (bs == NULL)
     118           0 :                                 mnstr_printf(f, "Failed to take chunk\n");
     119             :                         else {
     120           0 :                                 if (BATprint(f, bs) != GDK_SUCCEED)
     121           0 :                                         mnstr_printf(f, "Failed to print chunk\n");
     122           0 :                                 BBPunfix(bs->batCacheid);
     123             :                         }
     124             :                 }
     125             : 
     126           0 :                 BBPunfix(b->batCacheid);
     127             :         } else
     128           0 :                 mnstr_printf(f, "\n");
     129           0 : }
     130             : 
     131             : static void
     132           0 : printStackElm(stream *f, MalBlkPtr mb, ValPtr v, int index, BUN cnt, BUN first)
     133             : {
     134             :         str nme, nmeOnStk;
     135           0 :         VarPtr n = getVar(mb, index);
     136             : 
     137           0 :         printStackHdr(f, mb, v, index);
     138             : 
     139           0 :         if (v && v->vtype == TYPE_bat) {
     140           0 :                 bat i = v->val.bval;
     141           0 :                 BAT *b = BBPquickdesc(i);
     142             : 
     143           0 :                 if (b) {
     144           0 :                         nme = getTypeName(newBatType(b->ttype));
     145           0 :                         mnstr_printf(f, " :%s rows="BUNFMT, nme, BATcount(b));
     146             :                 } else {
     147           0 :                         nme = getTypeName(n->type);
     148           0 :                         mnstr_printf(f, " :%s", nme);
     149             :                 }
     150             :         } else {
     151           0 :                 nme = getTypeName(n->type);
     152           0 :                 mnstr_printf(f, " :%s", nme);
     153             :         }
     154           0 :         nmeOnStk = v ? getTypeName(v->vtype) : GDKstrdup(nme);
     155             :         /* check for type errors */
     156           0 :         if (nmeOnStk && strcmp(nmeOnStk, nme) && strncmp(nmeOnStk, "BAT", 3))
     157           0 :                 mnstr_printf(f, "!%s ", nmeOnStk);
     158           0 :         mnstr_printf(f, " %s", (isVarConstant(mb, index) ? " constant" : ""));
     159           0 :         mnstr_printf(f, " %s", (isVarTypedef(mb, index) ? " type variable" : ""));
     160           0 :         GDKfree(nme);
     161           0 :         mnstr_printf(f, "\n");
     162           0 :         GDKfree(nmeOnStk);
     163             : 
     164           0 :         if (cnt && v && (isaBatType(n->type) || v->vtype == TYPE_bat) && !is_bat_nil(v->val.bval)) {
     165           0 :                 printBATelm(f,v->val.bval,cnt,first);
     166             :         }
     167           0 : }
     168             : 
     169             : void
     170           0 : printStack(stream *f, MalBlkPtr mb, MalStkPtr s)
     171             : {
     172             :         int i = 0;
     173             : 
     174           0 :         setVariableScope(mb);
     175           0 :         if (s) {
     176           0 :                 mnstr_printf(f, "#Stack '%s' size=%d top=%d\n",
     177           0 :                                 getInstrPtr(mb, 0)->fcnname, s->stksize, s->stktop);
     178           0 :                 for (; i < mb->vtop; i++)
     179           0 :                         printStackElm(f, mb, s->stk + i, i, 0, 0);
     180             :         } else
     181           0 :                 for (; i < mb->vtop; i++)
     182           0 :                         printStackElm(f, mb, 0, i, 0, 0);
     183           0 : }
     184             : 
     185             : /* utility to display an instruction being called and its stack position */
     186             : static void
     187           0 : printCall(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int pc)
     188             : {
     189             :         str msg;
     190           0 :         msg = instruction2str(mb, stk, getInstrPtr(mb, pc), LIST_MAL_CALL);
     191           0 :         mnstr_printf(cntxt->fdout, "#%s at %s.%s[%d]\n", (msg?msg:"failed instruction2str()") ,
     192             :                         getModuleId(getInstrPtr(mb, 0)),
     193           0 :                         getFunctionId(getInstrPtr(mb, 0)), pc);
     194           0 :         GDKfree(msg);
     195           0 : }
     196             : 
     197             : static void
     198           0 : mdbBacktrace(Client cntxt, MalStkPtr stk, int pci)
     199             : {
     200           0 :         for (; stk != NULL; stk = stk->up) {
     201           0 :                 printCall(cntxt, stk->blk, stk, pci);
     202           0 :                 if (stk->up)
     203           0 :                         pci = stk->up->pcup;
     204             :         }
     205           0 : }
     206             : 
     207             : void
     208           0 : mdbDump(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     209             : {
     210           0 :         int i = getPC(mb, pci);
     211           0 :         mnstr_printf(cntxt->fdout, "!MDB dump of instruction %d\n", i);
     212           0 :         if( i < 0)
     213             :                 return;
     214           0 :         printFunction(cntxt->fdout, mb, stk, LIST_MAL_ALL);
     215           0 :         mdbBacktrace(cntxt, stk, i);
     216           0 :         printStack(cntxt->fdout, mb, stk);
     217             : }
     218             : 
     219             : static inline char *
     220             : pre(const char *s1, const char *s2, char *buf)
     221             : {
     222           0 :         snprintf(buf, 64, "%s%s", s1, s2);
     223             :         return buf;
     224             : }
     225             : 
     226             : static inline char *
     227             : local_itoa(ssize_t i, char *buf)
     228             : {
     229           0 :         snprintf(buf, 32, "%zd", i);
     230             :         return buf;
     231             : }
     232             : static inline char *
     233             : local_utoa(size_t i, char *buf)
     234             : {
     235           0 :         snprintf(buf, 32, "%zu", i);
     236             :         return buf;
     237             : }
     238             : 
     239             : static inline char *
     240           0 : oidtostr(oid i, char *p, size_t len)
     241             : {
     242           0 :         if (OIDtoStr(&p, &len, &i, false) < 0)
     243             :                 return NULL;
     244           0 :         return p;
     245             : }
     246             : 
     247             : static gdk_return
     248           0 : infoHeap(BAT *bk, BAT*bv, Heap *hp, str nme)
     249             : {
     250             :         char buf[1024], *p = buf;
     251             : 
     252           0 :         if (!hp)
     253             :                 return GDK_SUCCEED;
     254           0 :         while (*nme)
     255           0 :                 *p++ = *nme++;
     256           0 :         strcpy(p, "free");
     257           0 :         if (BUNappend(bk, buf, false) != GDK_SUCCEED ||
     258           0 :                 BUNappend(bv, local_utoa(hp->free, buf), false) != GDK_SUCCEED)
     259           0 :                 return GDK_FAIL;
     260           0 :         strcpy(p, "size");
     261           0 :         if (BUNappend(bk, buf, false) != GDK_SUCCEED ||
     262           0 :                 BUNappend(bv, local_utoa(hp->size, buf), false) != GDK_SUCCEED)
     263           0 :                 return GDK_FAIL;
     264           0 :         strcpy(p, "storage");
     265           0 :         if (BUNappend(bk, buf, false) != GDK_SUCCEED ||
     266           0 :                 BUNappend(bv, (hp->base == NULL || hp->base == (char*)1) ? "absent" : (hp->storage == STORE_MMAP) ? (hp->filename[0] ? "memory mapped" : "anonymous vm") : (hp->storage == STORE_PRIV) ? "private map" : "malloced", false) != GDK_SUCCEED)
     267           0 :                 return GDK_FAIL;
     268           0 :         strcpy(p, "newstorage");
     269           0 :         if (BUNappend(bk, buf, false) != GDK_SUCCEED ||
     270           0 :                 BUNappend(bv, (hp->newstorage == STORE_MEM) ? "malloced" : (hp->newstorage == STORE_PRIV) ? "private map" : "memory mapped", false) != GDK_SUCCEED)
     271           0 :                 return GDK_FAIL;
     272           0 :         strcpy(p, "filename");
     273           0 :         if (BUNappend(bk, buf, false) != GDK_SUCCEED ||
     274           0 :                 BUNappend(bv, hp->filename[0] ? hp->filename : "no file", false) != GDK_SUCCEED)
     275           0 :                 return GDK_FAIL;
     276             :         return GDK_SUCCEED;
     277             : }
     278             : 
     279             : #define COLLISION (8 * sizeof(size_t))
     280             : 
     281             : static gdk_return
     282           0 : HASHinfo(BAT *bk, BAT *bv, Hash *h, str s)
     283             : {
     284             :         BUN i;
     285             :         BUN j;
     286             :         BUN k;
     287             :         BUN cnt[COLLISION + 1];
     288             :         char buf[32];
     289             :         char prebuf[64];
     290             : 
     291           0 :         if (BUNappend(bk, pre(s, "type", prebuf), false) != GDK_SUCCEED ||
     292           0 :             BUNappend(bv, ATOMname(h->type),false) != GDK_SUCCEED ||
     293           0 :             BUNappend(bk, pre(s, "mask", prebuf), false) != GDK_SUCCEED ||
     294           0 :             BUNappend(bv, local_utoa(h->nbucket, buf),false) != GDK_SUCCEED)
     295           0 :                 return GDK_FAIL;
     296             : 
     297           0 :         for (i = 0; i < COLLISION + 1; i++) {
     298           0 :                 cnt[i] = 0;
     299             :         }
     300           0 :         for (i = 0; i < h->nbucket; i++) {
     301           0 :                 j = HASHlist(h, i);
     302           0 :                 for (k = 0; j; k++)
     303           0 :                         j >>= 1;
     304           0 :                 cnt[k]++;
     305             :         }
     306             : 
     307           0 :         for (i = 0; i < COLLISION + 1; i++)
     308           0 :                 if (cnt[i]) {
     309           0 :                         if (BUNappend(bk, pre(s, local_utoa(i?(((size_t)1)<<(i-1)):0, buf), prebuf), false) != GDK_SUCCEED ||
     310           0 :                             BUNappend(bv, local_utoa((size_t) cnt[i], buf), false) != GDK_SUCCEED)
     311           0 :                                 return GDK_FAIL;
     312             :                 }
     313             :         return GDK_SUCCEED;
     314             : }
     315             : 
     316             : str
     317           0 : BATinfo(BAT **key, BAT **val, const bat bid)
     318             : {
     319             :         const char *mode, *accessmode;
     320             :         BAT *bk = NULL, *bv= NULL, *b;
     321             :         char bf[oidStrlen];
     322             :         char buf[32];
     323             : 
     324           0 :         if ((b = BATdescriptor(bid)) == NULL) {
     325           0 :                 throw(MAL, "BATinfo", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     326             :         }
     327             : 
     328           0 :         bk = COLnew(0, TYPE_str, 128, TRANSIENT);
     329           0 :         bv = COLnew(0, TYPE_str, 128, TRANSIENT);
     330           0 :         if (bk == NULL || bv == NULL) {
     331           0 :                 BBPreclaim(bk);
     332           0 :                 BBPreclaim(bv);
     333           0 :                 BBPunfix(b->batCacheid);
     334           0 :                 throw(MAL, "bat.getInfo", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     335             :         }
     336             : 
     337           0 :         if (b->batTransient) {
     338             :                 mode = "transient";
     339             :         } else {
     340             :                 mode = "persistent";
     341             :         }
     342             : 
     343           0 :         switch (b->batRestricted) {
     344             :         case BAT_READ:
     345             :                 accessmode = "read-only";
     346             :                 break;
     347           0 :         case BAT_WRITE:
     348             :                 accessmode = "updatable";
     349           0 :                 break;
     350           0 :         case BAT_APPEND:
     351             :                 accessmode = "append-only";
     352           0 :                 break;
     353           0 :         default:
     354             :                 accessmode = "unknown";
     355             :         }
     356             : 
     357           0 :         if (BUNappend(bk, "batId", false) != GDK_SUCCEED ||
     358           0 :             BUNappend(bv, BATgetId(b), false) != GDK_SUCCEED ||
     359           0 :             BUNappend(bk, "batCacheid", false) != GDK_SUCCEED ||
     360           0 :             BUNappend(bv, local_itoa((ssize_t) b->batCacheid, buf), false) != GDK_SUCCEED ||
     361           0 :             BUNappend(bk, "tparentid", false) != GDK_SUCCEED ||
     362           0 :             BUNappend(bv, local_itoa((ssize_t) b->theap->parentid, buf), false) != GDK_SUCCEED ||
     363           0 :             BUNappend(bk, "batSharecnt", false) != GDK_SUCCEED ||
     364           0 :             BUNappend(bv, local_itoa((ssize_t) b->batSharecnt, buf), false) != GDK_SUCCEED ||
     365           0 :             BUNappend(bk, "batCount", false) != GDK_SUCCEED ||
     366           0 :             BUNappend(bv, local_utoa((size_t) b->batCount, buf), false) != GDK_SUCCEED ||
     367           0 :             BUNappend(bk, "batCapacity", false) != GDK_SUCCEED ||
     368           0 :             BUNappend(bv, local_utoa((size_t) b->batCapacity, buf), false) != GDK_SUCCEED ||
     369           0 :             BUNappend(bk, "head", false) != GDK_SUCCEED ||
     370           0 :             BUNappend(bv, ATOMname(TYPE_void), false) != GDK_SUCCEED ||
     371           0 :             BUNappend(bk, "tail", false) != GDK_SUCCEED ||
     372           0 :             BUNappend(bv, ATOMname(b->ttype), false) != GDK_SUCCEED ||
     373           0 :             BUNappend(bk, "batPersistence", false) != GDK_SUCCEED ||
     374           0 :             BUNappend(bv, mode, false) != GDK_SUCCEED ||
     375           0 :             BUNappend(bk, "batRestricted", false) != GDK_SUCCEED ||
     376           0 :             BUNappend(bv, accessmode, false) != GDK_SUCCEED ||
     377           0 :             BUNappend(bk, "batRefcnt", false) != GDK_SUCCEED ||
     378           0 :             BUNappend(bv, local_itoa((ssize_t) BBP_refs(b->batCacheid), buf), false) != GDK_SUCCEED ||
     379           0 :             BUNappend(bk, "batLRefcnt", false) != GDK_SUCCEED ||
     380           0 :             BUNappend(bv, local_itoa((ssize_t) BBP_lrefs(b->batCacheid), buf), false) != GDK_SUCCEED ||
     381           0 :             BUNappend(bk, "batDirty", false) != GDK_SUCCEED ||
     382           0 :             BUNappend(bv, BATdirty(b) ? "dirty" : "clean", false) != GDK_SUCCEED ||
     383             : 
     384           0 :             BUNappend(bk, "hseqbase", false) != GDK_SUCCEED ||
     385           0 :             BUNappend(bv, oidtostr(b->hseqbase, bf, sizeof(bf)), FALSE) != GDK_SUCCEED ||
     386             : 
     387           0 :             BUNappend(bk, "tident", false) != GDK_SUCCEED ||
     388           0 :             BUNappend(bv, b->tident, false) != GDK_SUCCEED ||
     389           0 :             BUNappend(bk, "tdense", false) != GDK_SUCCEED ||
     390           0 :             BUNappend(bv, local_itoa((ssize_t) BATtdense(b), buf), false) != GDK_SUCCEED ||
     391           0 :             BUNappend(bk, "tseqbase", false) != GDK_SUCCEED ||
     392           0 :             BUNappend(bv, oidtostr(b->tseqbase, bf, sizeof(bf)), FALSE) != GDK_SUCCEED ||
     393           0 :             BUNappend(bk, "tsorted", false) != GDK_SUCCEED ||
     394           0 :             BUNappend(bv, local_itoa((ssize_t) BATtordered(b), buf), false) != GDK_SUCCEED ||
     395           0 :             BUNappend(bk, "trevsorted", false) != GDK_SUCCEED ||
     396           0 :             BUNappend(bv, local_itoa((ssize_t) BATtrevordered(b), buf), false) != GDK_SUCCEED ||
     397           0 :             BUNappend(bk, "tkey", false) != GDK_SUCCEED ||
     398           0 :             BUNappend(bv, local_itoa((ssize_t) b->tkey, buf), false) != GDK_SUCCEED ||
     399           0 :             BUNappend(bk, "tvarsized", false) != GDK_SUCCEED ||
     400           0 :             BUNappend(bv, local_itoa((ssize_t) b->tvarsized, buf), false) != GDK_SUCCEED ||
     401           0 :             BUNappend(bk, "tnosorted", false) != GDK_SUCCEED ||
     402           0 :             BUNappend(bv, local_utoa(b->tnosorted, buf), false) != GDK_SUCCEED ||
     403           0 :             BUNappend(bk, "tnorevsorted", false) != GDK_SUCCEED ||
     404           0 :             BUNappend(bv, local_utoa(b->tnorevsorted, buf), false) != GDK_SUCCEED ||
     405           0 :             BUNappend(bk, "tnokey[0]", false) != GDK_SUCCEED ||
     406           0 :             BUNappend(bv, local_utoa(b->tnokey[0], buf), false) != GDK_SUCCEED ||
     407           0 :             BUNappend(bk, "tnokey[1]", false) != GDK_SUCCEED ||
     408           0 :             BUNappend(bv, local_utoa(b->tnokey[1], buf), false) != GDK_SUCCEED ||
     409           0 :             BUNappend(bk, "tnonil", false) != GDK_SUCCEED ||
     410           0 :             BUNappend(bv, local_utoa(b->tnonil, buf), false) != GDK_SUCCEED ||
     411           0 :             BUNappend(bk, "tnil", false) != GDK_SUCCEED ||
     412           0 :             BUNappend(bv, local_utoa(b->tnil, buf), false) != GDK_SUCCEED ||
     413             : 
     414           0 :             BUNappend(bk, "batInserted", false) != GDK_SUCCEED ||
     415           0 :             BUNappend(bv, local_utoa(b->batInserted, buf), false) != GDK_SUCCEED ||
     416           0 :             BUNappend(bk, "ttop", false) != GDK_SUCCEED ||
     417           0 :             BUNappend(bv, local_utoa(b->theap->free, buf), false) != GDK_SUCCEED ||
     418           0 :             BUNappend(bk, "batCopiedtodisk", false) != GDK_SUCCEED ||
     419           0 :             BUNappend(bv, local_itoa((ssize_t) b->batCopiedtodisk, buf), false) != GDK_SUCCEED ||
     420           0 :             BUNappend(bk, "batDirtydesc", false) != GDK_SUCCEED ||
     421           0 :             BUNappend(bv, b->batDirtydesc ? "dirty" : "clean", false) != GDK_SUCCEED ||
     422             : 
     423           0 :             BUNappend(bk, "theap.dirty", false) != GDK_SUCCEED ||
     424           0 :             BUNappend(bv, b->theap->dirty ? "dirty" : "clean", false) != GDK_SUCCEED ||
     425           0 :                 infoHeap(bk, bv, b->theap, "tail.") != GDK_SUCCEED ||
     426             : 
     427           0 :             BUNappend(bk, "tvheap->dirty", false) != GDK_SUCCEED ||
     428           0 :             BUNappend(bv, (b->tvheap && b->tvheap->dirty) ? "dirty" : "clean", false) != GDK_SUCCEED ||
     429           0 :                 infoHeap(bk, bv, b->tvheap, "theap.") != GDK_SUCCEED) {
     430           0 :                 BBPreclaim(bk);
     431           0 :                 BBPreclaim(bv);
     432           0 :                 BBPunfix(b->batCacheid);
     433           0 :                 throw(MAL, "bat.getInfo", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     434             :         }
     435             :         /* dump index information */
     436           0 :         MT_rwlock_rdlock(&b->thashlock);
     437           0 :         if (b->thash && HASHinfo(bk, bv, b->thash, "thash->") != GDK_SUCCEED) {
     438           0 :                 MT_rwlock_rdunlock(&b->thashlock);
     439           0 :                 BBPreclaim(bk);
     440           0 :                 BBPreclaim(bv);
     441           0 :                 BBPunfix(b->batCacheid);
     442           0 :                 throw(MAL, "bat.getInfo", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     443             :         }
     444           0 :         MT_rwlock_rdunlock(&b->thashlock);
     445           0 :         *key = bk;
     446           0 :         *val = bv;
     447           0 :         assert(BATcount(bk) == BATcount(bv));
     448           0 :         BBPunfix(bid);
     449           0 :         return MAL_SUCCEED;
     450             : }
     451             : 
     452             : #ifndef NDEBUG
     453             : static void
     454           0 : printBatDetails(stream *f, bat bid)
     455             : {
     456             :         BAT *b[2];
     457             : 
     458             :         /* at this level we don't know bat kernel primitives */
     459           0 :         mnstr_printf(f, "#Show info for %d\n", bid);
     460           0 :         if (BATinfo(&b[0],&b[1], bid) != MAL_SUCCEED)
     461           0 :                 return;
     462           0 :         BATprintcolumns(f, 2, b);
     463           0 :         BBPunfix(b[0]->batCacheid);
     464           0 :         BBPunfix(b[1]->batCacheid);
     465             : }
     466             : 
     467             : static void
     468           0 : printBatInfo(stream *f, VarPtr n, ValPtr v)
     469             : {
     470           0 :         if (isaBatType(n->type) && v->val.ival)
     471           0 :                 printBatDetails(f, v->val.ival);
     472           0 : }
     473             : 
     474             : static void
     475           0 : mdbHelp(stream *f)
     476             : {
     477           0 :         mnstr_printf(f, "next             -- Advance to next statement\n");
     478           0 :         mnstr_printf(f, "continue         -- Continue program being debugged\n");
     479           0 :         mnstr_printf(f, "catch            -- Catch the next exception \n");
     480           0 :         mnstr_printf(f, "break [<var>]    -- set breakpoint on current instruction or <var>\n");
     481           0 :         mnstr_printf(f, "delete [<var>]   -- remove break/trace point <var>\n");
     482           0 :         mnstr_printf(f, "debug <int>      -- set kernel debugging mask\n");
     483           0 :         mnstr_printf(f, "step             -- advance to next MAL instruction\n");
     484           0 :         mnstr_printf(f, "module           -- display a module signatures\n");
     485           0 :         mnstr_printf(f, "atom             -- show atom list\n");
     486           0 :         mnstr_printf(f, "finish           -- finish current call\n");
     487           0 :         mnstr_printf(f, "exit             -- terminate executionr\n");
     488           0 :         mnstr_printf(f, "quit             -- turn off debugging\n");
     489           0 :         mnstr_printf(f, "list <obj>       -- list current program block\n");
     490           0 :         mnstr_printf(f, "list #  [+#],-#  -- list current program block slice\n");
     491           0 :         mnstr_printf(f, "List <obj> [#]   -- list with type information[slice]\n");
     492           0 :         mnstr_printf(f, "list [#] <obj>   -- list program block after optimizer <#>\n");
     493           0 :         mnstr_printf(f, "List #  [+#],-#  -- list current program block slice\n");
     494           0 :         mnstr_printf(f, "var  <obj>       -- print symbol table for module\n");
     495           0 :         mnstr_printf(f, "optimizer <obj>  -- display optimizer steps\n");
     496           0 :         mnstr_printf(f, "print <var>      -- display value of a variable\n");
     497           0 :         mnstr_printf(f, "print <var> <cnt>[<first>] -- display BAT chunk\n");
     498           0 :         mnstr_printf(f, "info <var>       -- display bat variable properties\n");
     499           0 :         mnstr_printf(f, "run              -- restart current procedure\n");
     500           0 :         mnstr_printf(f, "where            -- print stack trace\n");
     501           0 :         mnstr_printf(f, "down             -- go down the stack\n");
     502           0 :         mnstr_printf(f, "up               -- go up the stack\n");
     503           0 :         mnstr_printf(f, "trace <var>      -- trace assignment to variables\n");
     504           0 :         mnstr_printf(f, "trap <mod>.<fcn> -- catch MAL function call in debugger\n");
     505           0 :         mnstr_printf(f, "help             -- this message\n");
     506           0 : }
     507             : 
     508             : /*
     509             :  * The debugger flags overview
     510             :  */
     511             : static mdbStateRecord *mdbTable;
     512             : 
     513             : bool
     514         266 : mdbInit(void)
     515             : {
     516             :         /*
     517             :          * Each client has its own breakpoint administration, kept in a
     518             :          * global table.  Although a little space consumptive, it is the
     519             :          * easiest to maintain and much less expensive as reserving debugger
     520             :          * space in each instruction.
     521             :          */
     522         266 :         mdbTable = GDKzalloc(sizeof(mdbStateRecord) * MAL_MAXCLIENTS);
     523         266 :         return mdbTable != NULL;
     524             : }
     525             : 
     526             : void
     527         264 : mdbExit(void)
     528             : {
     529         264 :         if (mdbTable) {
     530         264 :                 GDKfree(mdbTable);
     531         264 :                 mdbTable = 0;
     532             :         }
     533         264 : }
     534             : 
     535             : static char
     536           0 : isBreakpoint(Client cntxt, MalBlkPtr mb, InstrPtr p, int pc)
     537             : {
     538             :         int i, j;
     539             : 
     540           0 :         for (i = 0; i < mdbTable[cntxt->idx].brkTop; i++) {
     541           0 :                 if (mdbTable[cntxt->idx].brkBlock[i] != mb)
     542           0 :                         continue;
     543           0 :                 if (mdbTable[cntxt->idx].brkPc[i] == pc)
     544           0 :                         return mdbTable[cntxt->idx].brkCmd[i];
     545             : 
     546           0 :                 if (mdbTable[cntxt->idx].brkMod[i] && getModuleId(p) &&
     547           0 :                         mdbTable[cntxt->idx].brkFcn[i] && getFunctionId(p) &&
     548           0 :                         strcmp(mdbTable[cntxt->idx].brkMod[i], getModuleId(p)) == 0 &&
     549           0 :                         strcmp(mdbTable[cntxt->idx].brkFcn[i], getFunctionId(p)) == 0)
     550           0 :                         return mdbTable[cntxt->idx].brkCmd[i];
     551             : 
     552           0 :                 if (mdbTable[cntxt->idx].brkVar[i] >= 0)
     553           0 :                         for (j = 0; j < p->retc; j++)
     554           0 :                                 if (mdbTable[cntxt->idx].brkVar[i] == getArg(p, j))
     555           0 :                                         return mdbTable[cntxt->idx].brkCmd[i];
     556             :         }
     557             :         return 0;
     558             : }
     559             : 
     560             : /*
     561             :  * Break points can be set on assignment to a specific variable,
     562             :  * specific operation, or a instruction line
     563             :  */
     564             : void
     565           0 : mdbSetBreakRequest(Client cntxt, MalBlkPtr mb, str request, char cmd)
     566             : {
     567             :         int i;
     568             :         str modnme, fcnnme;
     569           0 :         mdbState mdb = mdbTable + cntxt->idx;
     570             :         Symbol sym;
     571             : 
     572             :         /* set breakpoint on specific line */
     573           0 :         if (*request == '#') {
     574           0 :                 i = atoi(request + 1);
     575           0 :                 if (i < 0 || i >= mb->stop)
     576           0 :                         mnstr_printf(cntxt->fdout, "breakpoint on #%d (<%d) not set\n",
     577             :                                         i, mb->stop);
     578             :                 else {
     579           0 :                         mdb->brkBlock[mdb->brkTop] = mb;
     580           0 :                         mdb->brkPc[mdb->brkTop] = i;
     581           0 :                         mdb->brkVar[mdb->brkTop] = -1;
     582           0 :                         mdb->brkMod[mdb->brkTop] = 0;
     583           0 :                         mdb->brkFcn[mdb->brkTop] = 0;
     584           0 :                         mdb->brkRequest[mdb->brkTop] = GDKstrdup(request);
     585           0 :                         mdb->brkCmd[mdb->brkTop] = cmd;
     586           0 :                         if (mdb->brkTop + 1 < MAXBREAKS)
     587           0 :                                 mdb->brkTop++;
     588             :                 }
     589           0 :                 return;
     590             :         }
     591             : 
     592             :         /* check for a [module.]function request */
     593           0 :         fcnnme = strchr(request, '.');
     594           0 :         if (fcnnme) {
     595             :                 modnme = request;
     596           0 :                 *fcnnme = 0;
     597           0 :                 fcnnme++;
     598           0 :                 sym = findSymbol(cntxt->usermodule, modnme, fcnnme);
     599           0 :                 mdb->brkBlock[mdb->brkTop] = sym ? sym->def : mb;
     600           0 :                 mdb->brkPc[mdb->brkTop] = -1;
     601           0 :                 mdb->brkVar[mdb->brkTop] = -1;
     602           0 :                 mdb->brkMod[mdb->brkTop] = putName(modnme);
     603           0 :                 mdb->brkFcn[mdb->brkTop] = putName(fcnnme);
     604             :                 fcnnme--;
     605           0 :                 *fcnnme = '.';
     606           0 :                 mdb->brkRequest[mdb->brkTop] = GDKstrdup(request);
     607           0 :                 mdb->brkCmd[mdb->brkTop] = cmd;
     608           0 :                 if (mdb->brkTop + 1 < MAXBREAKS)
     609           0 :                         mdb->brkTop++;
     610           0 :                 return;
     611             :         }
     612             :         /* the final step is to break on a variable */
     613           0 :         i = findVariable(mb, request);
     614           0 :         if ( i < 0)
     615           0 :                 i = findVariable(mb, request+1);
     616           0 :         if (i < 0)
     617           0 :                 mnstr_printf(cntxt->fdout, "breakpoint on %s not set\n", request);
     618             :         else {
     619           0 :                 mdb->brkBlock[mdb->brkTop] = mb;
     620           0 :                 mdb->brkPc[mdb->brkTop] = -1;
     621           0 :                 mdb->brkVar[mdb->brkTop] = i;
     622           0 :                 mdb->brkMod[mdb->brkTop] = 0;
     623           0 :                 mdb->brkFcn[mdb->brkTop] = 0;
     624           0 :                 mdb->brkRequest[mdb->brkTop] = GDKstrdup(request);
     625           0 :                 mdb->brkCmd[mdb->brkTop] = cmd;
     626           0 :                 if (mdb->brkTop + 1 < MAXBREAKS)
     627           0 :                         mdb->brkTop++;
     628             :         }
     629             : }
     630             : 
     631             : /* A breakpoint should be set once for each combination */
     632             : static void
     633           0 : mdbSetBreakpoint(Client cntxt, MalBlkPtr mb, int pc, char cmd)
     634             : {
     635           0 :         mdbState mdb = mdbTable + cntxt->idx;
     636             :         char buf[20];
     637             : 
     638           0 :         snprintf(buf, 20, "#%d", pc);
     639           0 :         mdb->brkBlock[mdb->brkTop] = mb;
     640           0 :         mdb->brkPc[mdb->brkTop] = pc;
     641           0 :         mdb->brkVar[mdb->brkTop] = -1;
     642           0 :         mdb->brkMod[mdb->brkTop] = 0;
     643           0 :         mdb->brkFcn[mdb->brkTop] = 0;
     644           0 :         mdb->brkRequest[mdb->brkTop] = GDKstrdup(buf);
     645           0 :         mdb->brkCmd[mdb->brkTop] = cmd;
     646           0 :         if (mdb->brkTop + 1 < MAXBREAKS)
     647           0 :                 mdb->brkTop++;
     648           0 : }
     649             : 
     650             : static void
     651           0 : mdbShowBreakpoints(Client cntxt)
     652             : {
     653             :         int i;
     654           0 :         mdbState mdb = mdbTable + cntxt->idx;
     655             : 
     656           0 :         for (i = 0; i < mdb->brkTop; i++)
     657           0 :                 mnstr_printf(cntxt->fdout, "breakpoint on '%s'\n", mdb->brkRequest[i]);
     658           0 : }
     659             : 
     660             : static void
     661           0 : mdbClrBreakpoint(Client cntxt, int pc)
     662             : {
     663             :         int i, j = 0;
     664           0 :         mdbState mdb = mdbTable + cntxt->idx;
     665             : 
     666           0 :         for (i = 0; i < mdb->brkTop; i++) {
     667           0 :                 mdb->brkBlock[j] = mdb->brkBlock[i];
     668           0 :                 mdb->brkPc[j] = mdb->brkPc[i];
     669           0 :                 mdb->brkVar[j] = mdb->brkVar[i];
     670           0 :                 mdb->brkMod[j] = mdb->brkMod[i];
     671           0 :                 mdb->brkFcn[j] = mdb->brkFcn[i];
     672           0 :                 mdb->brkRequest[j] = mdb->brkRequest[i];
     673           0 :                 mdb->brkCmd[j] = mdb->brkCmd[i];
     674           0 :                 if (mdb->brkPc[i] != pc)
     675           0 :                         j++;
     676             :                 else {
     677           0 :                         GDKfree(mdb->brkRequest[i]);
     678           0 :                         mdb->brkRequest[i] = 0;
     679             :                 }
     680             :         }
     681           0 :         mdb->brkTop = j;
     682           0 : }
     683             : 
     684             : static void
     685           0 : mdbClrBreakRequest(Client cntxt, str request)
     686             : {
     687             :         int i, j = 0;
     688           0 :         mdbState mdb = mdbTable + cntxt->idx;
     689             : 
     690           0 :         for (i = 0; i < mdb->brkTop; i++) {
     691           0 :                 mdb->brkBlock[j] = mdb->brkBlock[i];
     692           0 :                 mdb->brkPc[j] = mdb->brkPc[i];
     693           0 :                 mdb->brkVar[j] = mdb->brkVar[i];
     694           0 :                 mdb->brkMod[j] = mdb->brkMod[i];
     695           0 :                 mdb->brkFcn[j] = mdb->brkFcn[i];
     696           0 :                 mdb->brkRequest[j] = mdb->brkRequest[i];
     697           0 :                 mdb->brkCmd[j] = mdb->brkCmd[i];
     698           0 :                 if (strcmp(mdb->brkRequest[i], request))
     699           0 :                         j++;
     700             :                 else {
     701           0 :                         GDKfree(mdb->brkRequest[i]);
     702           0 :                         mdb->brkRequest[i] = 0;
     703             :                 }
     704             :         }
     705           0 :         mdb->brkTop = j;
     706           0 : }
     707             : 
     708             : /* utility to display instruction and dispose of structure */
     709             : static void
     710           0 : printTraceCall(stream *out, MalBlkPtr mb, MalStkPtr stk, int pc, int flags)
     711             : {
     712             :         str msg;
     713             :         InstrPtr p;
     714             : 
     715           0 :         p = getInstrPtr(mb, pc);
     716           0 :         msg = instruction2str(mb, stk, p, flags);
     717           0 :         mnstr_printf(out, "#%s%s\n", (mb->errors != MAL_SUCCEED ? "!" : ""), msg?msg:"failed instruction2str()");
     718           0 :         GDKfree(msg);
     719           0 : }
     720             : 
     721             : /* MAL debugger parser
     722             :  * The debugger structure is inherited from GDB.
     723             :  * The routine mdbCommand is called with p=0 after finishing a mal- function call
     724             :  * and before continuing at the next level of invocation.
     725             :  * The commands are self-explanatory.
     726             :  *
     727             :  * The prompt string sent to the user indicates the debugger mode.
     728             :  *
     729             :  * The history of the optimizers is maintained, which can be localized
     730             :  * for inspection.
     731             :  */
     732             : #define MDBstatus(X) if (cntxt->fdout) \
     733             :                 mnstr_printf(cntxt->fdout, "#MonetDB Debugger %s\n", (X ? "on" : "off"));
     734             : 
     735             : static MalBlkPtr
     736           0 : mdbLocateMalBlk(Client cntxt, MalBlkPtr mb, str b)
     737             : {
     738             :         MalBlkPtr m = mb;
     739             :         char *h = 0;
     740             :         int idx = -1;
     741             : 
     742           0 :         skipBlanc(cntxt, b);
     743             :         /* start with function in context */
     744           0 :         if (*b == '[') {
     745           0 :                 if( !isdigit((unsigned char) *(b+1))){
     746           0 :                         m = getMalBlkOptimized(mb, b+1);
     747           0 :                         if( m ==0 )
     748           0 :                                 mnstr_printf(cntxt->fdout,"Integer or optimizer named expected");
     749             :                         else
     750             :                                 return m;
     751             :                 } else
     752           0 :                         idx = atoi(b + 1);
     753           0 :                 if( idx < 0)
     754           0 :                         return NULL;
     755           0 :                 return getMalBlkHistory(mb, idx);
     756           0 :         } else if (isdigit((unsigned char) *b)) {
     757             :                 idx = atoi(b);
     758           0 :                 if( idx < 0)
     759             :                         return NULL;
     760           0 :                 return getMalBlkHistory(mb, idx);
     761           0 :         } else if (*b != 0) {
     762           0 :                 char *fcnname = strchr(b, '.');
     763             :                 Symbol fsym;
     764           0 :                 if (fcnname == NULL)
     765             :                         return NULL;
     766           0 :                 *fcnname = 0;
     767           0 :                 if ((h = strchr(fcnname + 1, '['))) {
     768           0 :                         *h = 0;
     769           0 :                         if( !isdigit((unsigned char) *(h+1))){
     770           0 :                                 m = getMalBlkOptimized(mb, h+1);
     771           0 :                                 if( m ==0 )
     772           0 :                                         mnstr_printf(cntxt->fdout,"Integer or optimizer named expected");
     773             :                                 else
     774             :                                         return m;
     775             :                         } else
     776           0 :                                 idx = atoi(h + 1);
     777           0 :                         if( idx < 0)
     778           0 :                                 return NULL;
     779             :                 }
     780           0 :                 fsym = findSymbolInModule(findModule(cntxt->usermodule, putName(b)), fcnname + 1);
     781           0 :                 *fcnname = '.';
     782           0 :                 if (h)
     783           0 :                         *h = '[';
     784           0 :                 if (fsym == 0) {
     785             :                         return NULL;
     786             :                 }
     787           0 :                 m = fsym->def;
     788           0 :                 return getMalBlkHistory(m, h ? idx : -1);
     789             :         }
     790           0 :         return getMalBlkHistory(mb, -1);
     791             : }
     792             : 
     793             : static void
     794           0 : printBatProperties(stream *f, VarPtr n, ValPtr v, str props)
     795             : {
     796           0 :         if (isaBatType(n->type) && v->val.ival) {
     797             :                 bat bid = v->val.ival;
     798             :                 BAT *b[2];
     799             :                 str res;
     800             :                 BUN p;
     801             : 
     802           0 :                 mnstr_printf(f, "BAT %d %s= ", bid, props);
     803           0 :                 if ((res = BATinfo(&b[0],&b[1], bid)) != MAL_SUCCEED) {
     804           0 :                         GDKfree(res);
     805           0 :                         mnstr_printf(f, "mal.info failed\n");
     806           0 :                         return;
     807             :                 }
     808           0 :                 p = BUNfnd(b[0], props);
     809           0 :                 if (p != BUN_NONE) {
     810           0 :                         BATiter bi = bat_iterator(b[1]);
     811           0 :                         mnstr_printf(f, " %s\n", (str) BUNtvar(bi, p));
     812           0 :                         bat_iterator_end(&bi);
     813             :                 } else {
     814           0 :                         mnstr_printf(f, " not found\n");
     815             :                 }
     816           0 :                 BBPunfix(b[0]->batCacheid);
     817           0 :                 BBPunfix(b[1]->batCacheid);
     818             :         }
     819             : }
     820             : 
     821             : 
     822             : static void
     823           0 : mdbCommand(Client cntxt, MalBlkPtr mb, MalStkPtr stkbase, InstrPtr p, int pc)
     824             : {
     825             :         int m = 1;
     826             :         char *b= 0, *c, lastcmd = 0;
     827           0 :         stream *out = cntxt->fdout;
     828           0 :         char *oldprompt = cntxt->prompt;
     829           0 :         size_t oldpromptlength = cntxt->promptlength;
     830             :         MalStkPtr stk = stkbase;
     831           0 :         int first = pc - ( pc == 1);
     832             :         int stepsize = 1000;
     833           0 :         char oldcmd[1024] = { 0 };
     834             :         str msg = MAL_SUCCEED;
     835             : 
     836             :         do {
     837           0 :                 if (p != NULL) {
     838             :                         /* help mclients with fake prompt */
     839           0 :                         if (lastcmd != 'l' && lastcmd != 'L') {
     840           0 :                                 mnstr_printf(out, "mdb>");
     841           0 :                                 printTraceCall(out, mb, stk, pc, LIST_MAL_CALL);
     842             :                         }
     843             : 
     844             :                 }
     845             : 
     846           0 :                 if (cntxt->phase[MAL_SCENARIO_READER]) {
     847           0 : retryRead:
     848           0 :                         msg = (char *) (*cntxt->phase[MAL_SCENARIO_READER])(cntxt);
     849           0 :                         if (msg != MAL_SUCCEED || cntxt->mode == FINISHCLIENT){
     850           0 :                                 freeException(msg);
     851           0 :                                 break;
     852             :                         }
     853             :                         /* SQL patch, it should only react to Smessages, Xclose requests to be ignored */
     854           0 :                         if (strncmp(cntxt->fdin->buf, "Xclose", 6) == 0) {
     855           0 :                                 cntxt->fdin->pos = cntxt->fdin->len;
     856           0 :                                 goto retryRead;
     857             :                         }
     858             :                 }
     859           0 :                 b = CURRENT(cntxt);
     860             : 
     861             :                 /* terminate the line with zero */
     862           0 :                 c = strchr(b, '\n');
     863           0 :                 if (c) {
     864           0 :                         *c = 0;
     865           0 :                         strcpy_len(oldcmd, b, sizeof(oldcmd));
     866           0 :                         cntxt->fdin->pos += (c - b) + 1;
     867             :                 } else
     868           0 :                         cntxt->fdin->pos = cntxt->fdin->len;
     869             : 
     870           0 :                 skipBlanc(cntxt, b);
     871           0 :                 if (*b)
     872             :                         lastcmd = *b;
     873             :                 else
     874           0 :                         strcpy(b = cntxt->fdin->buf, oldcmd);
     875             :                 b = oldcmd;
     876           0 :                 switch (*b) {
     877             :                 case 0:
     878             :                         m = 0;
     879             :                         break;
     880           0 :                 case 'c':
     881           0 :                         if (strncmp("check",b,5) == 0){
     882             :                                 Symbol fs;
     883             :                                 int i;
     884             :                                 str fcnnme;
     885             : 
     886           0 :                                 skipWord(cntxt,b);
     887           0 :                                 skipBlanc(cntxt, b);
     888           0 :                                 if( (fcnnme = strchr(b,'.')) != NULL ){
     889             :                                         str modnme = b;
     890             : 
     891           0 :                                         *fcnnme++  = 0;
     892             : 
     893           0 :                                         fs = findSymbol(cntxt->usermodule, putName(modnme),putName(fcnnme));
     894           0 :                                         if (fs == 0) {
     895           0 :                                                 mnstr_printf(out, "#'%s.%s' not found\n", modnme,fcnnme);
     896           0 :                                                 continue;
     897             :                                         }
     898           0 :                                         for(; fs; fs = fs->peer){
     899           0 :                                                 for(i=0; i< fs->def->stop; i++)
     900           0 :                                                         fs->def->stmt[i]->typechk = TYPE_UNKNOWN;
     901           0 :                                                 msg = chkProgram(cntxt->usermodule, fs->def);
     902           0 :                                                 if( msg != MAL_SUCCEED){
     903           0 :                                                         mnstr_printf(out, "#<modnme>.<fcnnme> contains errors: %s\n", msg);
     904           0 :                                                         freeException(msg);
     905             :                                                 }
     906             :                                         }
     907             :                                 } else
     908           0 :                                         mnstr_printf(out, "#<modnme>.<fcnnme> expected\n");
     909             :                                 break;
     910             :                         }
     911           0 :                         if (strncmp("catch", b, 3) == 0) {
     912             :                                 /* catch the next exception */
     913           0 :                                 stk->cmd = 'C';
     914           0 :                                 break;
     915             :                         }
     916           0 :                         stk->cmd = 'c';
     917           0 :                         skipWord(cntxt, b);
     918             :                         m = 0;
     919             :                         break;
     920           0 :                 case 'e':
     921             :                 {
     922             :                         /* terminate the execution for ordinary functions only */
     923           0 :                         if (strncmp("exit", b, 4) == 0) {
     924             :                         case 'x':
     925           0 :                                 if (!(getInstrPtr(mb, 0)->token == FACcall)) {
     926           0 :                                         stk->cmd = 'x';
     927           0 :                                         cntxt->prompt = oldprompt;
     928           0 :                                         cntxt->promptlength = oldpromptlength;
     929             :                                 }
     930             :                         }
     931           0 :                         return;
     932             :                 }
     933             :                 case 'q':
     934             :                 {
     935             :                         MalStkPtr su;
     936             : 
     937             :                         /* return from this debugger */
     938           0 :                         for (su = stk; su; su = su->up)
     939           0 :                                 su->cmd = 0;
     940           0 :                         cntxt->itrace = 0;
     941           0 :                         mnstr_printf(out, "mdb>#EOD\n");
     942             :                         /* MDBstatus(0); */
     943           0 :                         cntxt->prompt = oldprompt;
     944           0 :                         cntxt->promptlength = oldpromptlength;
     945           0 :                         return;
     946             :                 }
     947           0 :                 case 'f':   /* finish */
     948             :                 case 'n':   /* next */
     949             :                 case 's':   /* step */
     950           0 :                         if (strncmp("scenarios", b, 9) == 0) {
     951           0 :                                 showAllScenarios(out);
     952           0 :                                 continue;
     953           0 :                         } else if (strncmp("scenario", b, 3) == 0) {
     954           0 :                                 showScenarioByName(out, cntxt->scenario);
     955           0 :                                 continue;
     956             :                         }
     957           0 :                         stk->cmd = *b;
     958             :                         m = 0;
     959           0 :                         break;
     960           0 :                 case 'M':       /* dump all module names */
     961           0 :                         dumpModules(out);
     962           0 :                         break;
     963             :                 case 'm':   /* display a module */
     964             :                 {
     965             :                         str modname, fcnname;
     966             :                         Module fsym;
     967             :                         Symbol fs;
     968             :                         int i;
     969             : 
     970           0 :                         skipWord(cntxt, b);
     971           0 :                         skipBlanc(cntxt, b);
     972           0 :                         if (*b) {
     973             :                                 modname = b;
     974           0 :                                 fcnname = strchr(b, '.');
     975           0 :                                 if (fcnname) {
     976           0 :                                         *fcnname = 0;
     977             :                                         fcnname++;
     978             :                                 }
     979           0 :                                 fsym = findModule(cntxt->usermodule, putName(modname));
     980             : 
     981           0 :                                 if (fsym == cntxt->usermodule && strcmp(modname, "user")) {
     982           0 :                                         mnstr_printf(out, "#module '%s' not found\n", modname);
     983           0 :                                         continue;
     984             :                                 }
     985           0 :                                 for (i = 0; i < MAXSCOPE; i++) {
     986           0 :                                         fs = fsym->space[i];
     987           0 :                                         while (fs != NULL) {
     988           0 :                                                 printSignature(out, fs, 0);
     989           0 :                                                 fs = fs->peer;
     990             :                                         }
     991             :                                 }
     992           0 :                                 continue;
     993             :                         } else {
     994             :                                 Module* list;
     995             :                                 int length;
     996             :                                 int i;
     997           0 :                                 mnstr_printf(out,"#%s ",cntxt->usermodule->name);
     998           0 :                                 getModuleList(&list, &length);
     999           0 :                                 for(i = 0; i < length; i++) {
    1000           0 :                                         mnstr_printf(out, "%s ", list[i]->name);
    1001             :                                 }
    1002           0 :                                 freeModuleList(list);
    1003           0 :                                 mnstr_printf(out,"\n");
    1004             :                         }
    1005             :                 }
    1006           0 :                 break;
    1007           0 :                 case 'T':   /* debug type resolver for a function call */
    1008           0 :                         if (strncmp("Trace", b, 5) == 0) {
    1009             :                                 char *w;
    1010           0 :                                 skipWord(cntxt, b);
    1011           0 :                                 skipBlanc(cntxt, b);
    1012           0 :                                 if ((w = strchr(b, '\n')))
    1013           0 :                                         *w = 0;
    1014             :                         }
    1015             :                         break;
    1016           0 :                 case 't':   /* trace a variable toggle */
    1017           0 :                         if (strncmp("trap", b, 4) == 0) {
    1018             :                                 char *w, *mod, *fcn;
    1019           0 :                                 skipWord(cntxt, b);
    1020           0 :                                 skipBlanc(cntxt, b);
    1021             :                                 mod = b;
    1022           0 :                                 skipWord(cntxt, b);
    1023           0 :                                 *b = 0;
    1024           0 :                                 fcn = b + 1;
    1025           0 :                                 if ((w = strchr(b + 1, '\n')))
    1026           0 :                                         *w = 0;
    1027           0 :                                 mnstr_printf(out, "#trap %s.%s\n", mod, fcn);
    1028             :                         }
    1029           0 :                         if (strncmp("trace", b, 5) == 0) {
    1030             :                                 char *w;
    1031           0 :                                 skipWord(cntxt, b);
    1032           0 :                                 skipBlanc(cntxt, b);
    1033           0 :                                 if ((w = strchr(b, '\n')))
    1034           0 :                                         *w = 0;
    1035           0 :                                 mdbSetBreakRequest(cntxt, mb, b, 't');
    1036             :                         }
    1037             :                         break;
    1038             :                 case 'v':   /* show the symbol table and bindings */
    1039             :                 case 'V': {
    1040             :                         str modname, fcnname;
    1041             :                         Module fsym;
    1042             :                         Symbol fs;
    1043             :                         int i;
    1044             : 
    1045           0 :                         skipWord(cntxt, b);
    1046           0 :                         if (*b != 0) {
    1047             :                                 modname = b;
    1048           0 :                                 fcnname = strchr(b, '.');
    1049           0 :                                 if (fcnname == NULL) {
    1050           0 :                                         fsym = findModule(cntxt->usermodule, putName(modname));
    1051           0 :                                         if (fsym == 0) {
    1052           0 :                                                 mnstr_printf(out, "#%s module not found\n", modname);
    1053           0 :                                                 continue;
    1054             :                                         }
    1055           0 :                                         for (i = 0; i < MAXSCOPE; i++) {
    1056           0 :                                                 fs = fsym->space[i];
    1057           0 :                                                 while (fs != NULL) {
    1058           0 :                                                         printStack(out, fs->def, 0);
    1059           0 :                                                         fs = fs->peer;
    1060             :                                                 }
    1061             :                                         }
    1062           0 :                                         continue;
    1063             :                                 }
    1064           0 :                                 *fcnname = 0;
    1065           0 :                                 fcnname++;
    1066           0 :                                 fsym = findModule(cntxt->usermodule, putName(modname));
    1067           0 :                                 if (fsym == 0) {
    1068           0 :                                         mnstr_printf(out, "#%s module not found\n", modname);
    1069           0 :                                         continue;
    1070             :                                 }
    1071             :                                 /* display the overloaded symbol definition */
    1072           0 :                                 for (i = 0; i < MAXSCOPE; i++) {
    1073           0 :                                         fs = fsym->space[i];
    1074           0 :                                         while (fs != NULL) {
    1075           0 :                                                 if (strcmp(fs->name, fcnname) == 0)
    1076           0 :                                                         printStack(out, fs->def, 0);
    1077           0 :                                                 fs = fs->peer;
    1078             :                                         }
    1079             :                                 }
    1080             :                         } else
    1081           0 :                                 printStack(out, mb, stk);
    1082             :                         break;
    1083             :                 }
    1084           0 :                 case 'b':
    1085           0 :                         if (strncmp(b, "bbp", 3) == 0) {
    1086             :                                 int i, limit, inuse = 0;
    1087             : 
    1088           0 :                                 skipWord(cntxt, b);
    1089           0 :                                 i = BBPindex(b);
    1090           0 :                                 if (i)
    1091           0 :                                         limit = i + 1;
    1092             :                                 else {
    1093           0 :                                         limit = getBBPsize();
    1094             :                                         i = 1;
    1095             :                                 }
    1096             :                                 /* the 'dense' qualification only shows entries with a hard ref */
    1097             :                                 /* watchout, you don't want to wait for locks by others */
    1098           0 :                                 mnstr_printf(out, "BBP contains %d entries\n", limit);
    1099           0 :                                 for (; i < limit; i++)
    1100           0 :                                         if (BBPcheck(i) && (BBP_lrefs(i) || BBP_refs(i)) && BBP_cache(i)) {
    1101           0 :                                                 mnstr_printf(out, "#[%d] %-15s", i, BBP_logical(i));
    1102           0 :                                                 if (BBP_cache(i))
    1103           0 :                                                         printBATproperties(out, BBP_cache(i));
    1104           0 :                                                 if ((*b == 'd' && BBP_refs(i) == 0) || BBP_cache(i) == 0) {
    1105           0 :                                                         mnstr_printf(out, "\n");
    1106           0 :                                                         continue;
    1107             :                                                 }
    1108           0 :                                                 inuse++;
    1109           0 :                                                 if (BATdirty(BBP_cache(i)))
    1110           0 :                                                         mnstr_printf(out, " dirty");
    1111           0 :                                                 if (*BBP_logical(i) == '.')
    1112           0 :                                                         mnstr_printf(out, " zombie ");
    1113           0 :                                                 unsigned status = BBP_status(i);
    1114           0 :                                                 if (status & BBPLOADED)
    1115           0 :                                                         mnstr_printf(out, " loaded ");
    1116           0 :                                                 if (status & BBPSWAPPED)
    1117           0 :                                                         mnstr_printf(out, " swapped ");
    1118           0 :                                                 if (status & BBPTMP)
    1119           0 :                                                         mnstr_printf(out, " tmp ");
    1120           0 :                                                 if (status & BBPDELETED)
    1121           0 :                                                         mnstr_printf(out, " deleted ");
    1122           0 :                                                 if (status & BBPEXISTING)
    1123           0 :                                                         mnstr_printf(out, " existing ");
    1124           0 :                                                 if (status & BBPNEW)
    1125           0 :                                                         mnstr_printf(out, " new ");
    1126           0 :                                                 if (status & BBPPERSISTENT)
    1127           0 :                                                         mnstr_printf(out, " persistent ");
    1128           0 :                                                 mnstr_printf(out, "\n");
    1129             :                                         }
    1130             : 
    1131           0 :                                 mnstr_printf(out, "#Entries displayed %d\n", inuse);
    1132           0 :                                 continue;
    1133             :                         }
    1134           0 :                         if (strncmp(b, "breakpoints", 11) == 0) {
    1135           0 :                                 mdbShowBreakpoints(cntxt);
    1136           0 :                                 continue;
    1137             :                         }
    1138           0 :                         if (strncmp(b, "break", 5) == 0)
    1139             :                                 b += 4;
    1140           0 :                         if (isspace((unsigned char) b[1])) {
    1141           0 :                                 skipWord(cntxt, b);
    1142           0 :                                 if (*b && !isspace((unsigned char) *b) && !isdigit((unsigned char) *b))
    1143             :                                         /* set breakpoints by name */
    1144           0 :                                         mdbSetBreakRequest(cntxt, mb, b, 's');
    1145           0 :                                 else if (*b && isdigit((unsigned char) *b))
    1146             :                                         /* set breakpoint at instruction */
    1147           0 :                                         mdbSetBreakpoint(cntxt, mb, atoi(b), 's');
    1148             :                                 else
    1149             :                                         /* set breakpoint at current instruction */
    1150           0 :                                         mdbSetBreakpoint(cntxt, mb, pc, 's');
    1151           0 :                                 continue;
    1152             :                         }
    1153           0 :                         continue;
    1154           0 :                 case 'd':
    1155           0 :                         if (strncmp(b, "debug", 5) == 0) {
    1156           0 :                                 skipWord(cntxt, b);
    1157           0 :                                 GDKsetdebug(atoi(b));
    1158           0 :                                 mnstr_printf(out, "#Set debug mask to %d\n", GDKdebug);
    1159           0 :                                 break;
    1160             :                         }
    1161           0 :                         if (strncmp(b, "down", 4) == 0) {
    1162             :                                 MalStkPtr ref = stk;
    1163             :                                 /* find the previous one from the base */
    1164             :                                 stk = stkbase;
    1165           0 :                                 while (stk != ref && stk->up && stk->up != ref)
    1166             :                                         stk = stk->up;
    1167           0 :                                 mnstr_printf(out, "#%sgo down the stack\n", "#mdb ");
    1168           0 :                                 mb = stk->blk;
    1169           0 :                                 break;
    1170             :                         }
    1171           0 :                         skipWord(cntxt, b);
    1172             :                         /* get rid of break point */
    1173           0 :                         if (*b && !isspace((unsigned char) *b) && !isdigit((unsigned char) *b))
    1174           0 :                                 mdbClrBreakRequest(cntxt, b);
    1175           0 :                         else if (isdigit((unsigned char) *b))
    1176           0 :                                 mdbClrBreakpoint(cntxt, atoi(b));
    1177             :                         else {
    1178           0 :                                 mdbClrBreakpoint(cntxt, pc);
    1179             :                         }
    1180           0 :                         continue;
    1181           0 :                 case 'I':
    1182             :                 case 'i':
    1183             :                 {
    1184             :                         int i;
    1185             :                         char *t;
    1186             : 
    1187             :                         /* the user wants information about variables */
    1188           0 :                         if (*b == 'I') {
    1189           0 :                                 skipWord(cntxt, b);
    1190           0 :                                 for (i = 0; i < mb->vtop; i++)
    1191           0 :                                         printBatProperties(out, getVar(mb, i), stk->stk + i, b);
    1192           0 :                                 continue;
    1193             :                         }
    1194           0 :                         skipWord(cntxt, b);
    1195             :                         t = b;
    1196           0 :                         skipNonBlanc(cntxt, t);
    1197           0 :                         *t = 0;
    1198             :                         /* search the symbol */
    1199           0 :                         i = findVariable(mb, b);
    1200           0 :                         if (i < 0) {
    1201             :                                 /* could be the name of a BAT */
    1202           0 :                                 i = BBPindex(b);
    1203           0 :                                 if (i != 0)
    1204           0 :                                         printBatDetails(out, i);
    1205             :                                 else
    1206           0 :                                         mnstr_printf(out, "#%s Symbol not found\n", "#mdb ");
    1207             :                         } else {
    1208           0 :                                 printBatInfo(out, getVar(mb, i), stk->stk + i);
    1209             :                         }
    1210           0 :                         continue;
    1211             :                 }
    1212             :                 case 'P':
    1213             :                 case 'p':
    1214             :                 {
    1215             :                         BUN size = 0, first = 0;
    1216             :                         int i;
    1217             :                         char *t;
    1218             :                         char upper = *b;
    1219             : 
    1220           0 :                         skipWord(cntxt, b);
    1221             :                         t = b;
    1222           0 :                         skipNonBlanc(cntxt, t);
    1223           0 :                         *t = 0;
    1224             :                         /* you can identify a start and length */
    1225           0 :                         t++;
    1226           0 :                         skipBlanc(cntxt, t);
    1227           0 :                         if (isdigit((unsigned char) *t)) {
    1228           0 :                                 size = (BUN) atol(t);
    1229           0 :                                 skipWord(cntxt, t);
    1230           0 :                                 if (isdigit((unsigned char) *t))
    1231           0 :                                         first = (BUN) atol(t);
    1232             :                         }
    1233             :                         /* search the symbol */
    1234           0 :                         i = findVariable(mb, b);
    1235           0 :                         if (i < 0) {
    1236             :                                 // deal with temporary
    1237           0 :                                 if( *b == 'X' ) b++;
    1238           0 :                                 i = findVariable(mb, b);
    1239             :                         }
    1240           0 :                         if (i < 0) {
    1241           0 :                                 mnstr_printf(out, "#%s Symbol not found\n", b);
    1242           0 :                                 continue;
    1243             :                         }
    1244           0 :                         if (isaBatType(getVarType(mb, i)) && upper == 'p') {
    1245           0 :                                 printStackHdr(out, mb, stk->stk + i, i);
    1246           0 :                                 printBATelm(out, stk->stk[i].val.bval, size, first);
    1247             :                         } else
    1248           0 :                                 printStackElm(out, mb, stk->stk + i, i, size, first);
    1249           0 :                         continue;
    1250             :                 }
    1251           0 :                 case 'u':
    1252           0 :                         if (stk->up == NULL)
    1253             :                                 break;
    1254           0 :                         mnstr_printf(out, "#%s go up the stack\n", "#mdb ");
    1255           0 :                         stk = stk->up;
    1256           0 :                         mb = stk->blk;
    1257           0 :                         printCall(cntxt, mb, stk, pc);
    1258           0 :                         continue;
    1259           0 :                 case 'w':
    1260             :                 {
    1261           0 :                         mdbBacktrace(cntxt, stk, pc);
    1262           0 :                         continue;
    1263             :                 }
    1264             : /*
    1265             :  * While debugging it should be possible to inspect the symbol
    1266             :  * table using the 'module.function' name. The default is to list all
    1267             :  * signatures satisfying the pattern.
    1268             :  */
    1269           0 :                 case 'L':
    1270             :                 case 'l':   /* list the current MAL block or module */
    1271             :                 {
    1272             :                         int lstng;
    1273             :                         c = b;
    1274             : 
    1275             :                         lstng = LIST_MAL_NAME;
    1276           0 :                         if(*b == 'L')
    1277             :                                 lstng = LIST_MAL_NAME | LIST_MAL_VALUE | LIST_MAL_TYPE | LIST_MAL_PROPS;
    1278           0 :                         skipWord(cntxt, b);
    1279           0 :                         skipBlanc(cntxt, b);
    1280           0 :                         if (*b != 0) {
    1281             :                                 /* debug the block context */
    1282           0 :                                 MalBlkPtr m = mdbLocateMalBlk(cntxt, mb, b);
    1283           0 :                                 mnstr_printf(out, "#Inspect %s\n", c);
    1284             : 
    1285           0 :                                 if ( m )
    1286             :                                         mb = m;
    1287             :                                 else{
    1288           0 :                                         mnstr_printf(out, "#MAL block not found '%s'\n", c);
    1289           0 :                                         break;
    1290             :                                 }
    1291             : 
    1292           0 :                                         skipModule(cntxt, b);
    1293           0 :                                         goto partial;
    1294             :                         } else {
    1295             : /*
    1296             :  * Listing the program starts at the pc last given.
    1297             :  * Repeated use of the list command moves you up and down the program
    1298             :  */
    1299           0 : partial:
    1300           0 :                                 if (isdigit((unsigned char) *b)) {
    1301             :                                         first = (int) atoi(b);
    1302           0 :                                         skipWord(cntxt, b);
    1303           0 :                                         skipBlanc(cntxt, b);
    1304             :                                 }
    1305           0 :                                 if (*b == '-') {
    1306           0 :                                         stepsize = (int) atoi(b + 1);
    1307           0 :                                         first -= stepsize++;
    1308           0 :                                 } else if (*b == '+')
    1309           0 :                                         stepsize = (int) atoi(b + 1);
    1310           0 :                                 else if (atoi(b))
    1311             :                                         stepsize = (int) atoi(b);
    1312           0 :                                 *b = 0;
    1313           0 :                                 if (stepsize < 0)
    1314           0 :                                         first -= stepsize;
    1315           0 :                                 if( first > mb->stop ) {
    1316           0 :                                         mnstr_printf(out, "#line %d out of range (<=%d)\n", first, mb->stop);
    1317             :                                         first = pc;
    1318             :                                 } else {
    1319           0 :                                         debugFunction(out, mb, 0, lstng, first, stepsize);
    1320           0 :                                         first = first + stepsize > mb->stop ? first : first + stepsize;
    1321             :                                 }
    1322             :                         }
    1323           0 :                         continue;
    1324             :                 }
    1325           0 :                 case 'h':
    1326           0 :                         mdbHelp(out);
    1327           0 :                         continue;
    1328             :                 case 'o':
    1329             :                 case 'O':   /* optimizer and scheduler steps */
    1330             :                 {
    1331             :                         c = b;
    1332           0 :                         skipWord(cntxt, b);
    1333           0 :                         skipBlanc(cntxt, b);
    1334           0 :                         if (*b) {
    1335           0 :                                 mnstr_printf(out, "#History of %s\n", b);
    1336           0 :                                 mb = mdbLocateMalBlk(cntxt, mb, b);
    1337           0 :                                 if (mb == NULL){
    1338           0 :                                         mnstr_printf(out, "#'%s' not resolved\n", c);
    1339           0 :                                         break;
    1340             :                                 }
    1341             :                         }
    1342           0 :                         showMalBlkHistory(out, mb);
    1343           0 :                         break;
    1344             :                 }
    1345           0 :                 case 'r':   /* reset program counter */
    1346           0 :                         mnstr_printf(out, "#%s restart with current stack\n", "#mdb ");
    1347           0 :                         stk->cmd = 'r';
    1348           0 :                         break;
    1349           0 :                 default:
    1350           0 :                         mnstr_printf(out, "#%s debugger command expected\n", "#mdb ");
    1351           0 :                         mdbHelp(out);
    1352             :                 }
    1353           0 :         } while (m);
    1354           0 :         cntxt->prompt = oldprompt;
    1355           0 :         cntxt->promptlength = oldpromptlength;
    1356             : }
    1357             : 
    1358             : static str
    1359           0 : mdbTrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
    1360             : {
    1361           0 :         int pc = getPC(mb,p);
    1362             : 
    1363           0 :         mnstr_printf(cntxt->fdout, "#trapped %s.%s[%d]\n",
    1364           0 :                         getModuleId(mb->stmt[0]), getFunctionId(mb->stmt[0]), pc);
    1365           0 :         printInstruction(cntxt->fdout, mb, stk, p, LIST_MAL_DEBUG);
    1366           0 :         cntxt->itrace = 'W';
    1367           0 :         return MAL_SUCCEED;
    1368             : }
    1369             : 
    1370             : void
    1371           1 : mdbStep(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int pc)
    1372             : {
    1373             :         InstrPtr p;
    1374             :         char ch;
    1375           1 :         stream *out = cntxt->fdout;
    1376             : 
    1377             :         /* mdbSanityCheck(cntxt, mb, stk, pc); expensive */
    1378             :         /* process should sleep */
    1379           1 :         if (cntxt->itrace == 'S') {
    1380             :                 MdbState state;
    1381             :                 state.mb = mb;
    1382             :                 state.stk = stk;
    1383           0 :                 state.p = getInstrPtr(mb, pc);
    1384             :                 state.pc = pc;
    1385           0 :                 mnstr_printf(cntxt->fdout, "#Process %d put to sleep\n", (int) (cntxt - mal_clients));
    1386           0 :                 cntxt->itrace = 'W';
    1387           0 :                 mdbTrap(cntxt, mb, stk, state.p);
    1388           0 :                 while (cntxt->itrace == 'W')
    1389           0 :                         MT_sleep_ms(300);
    1390           0 :                 mnstr_printf(cntxt->fdout, "#Process %d woke up\n", (int) (cntxt - mal_clients));
    1391             :                 return;
    1392             :         }
    1393           1 :         if (stk->cmd == 0)
    1394           0 :                 stk->cmd = 'n';
    1395           1 :         p = getInstrPtr(mb, pc);
    1396           1 :         switch (stk->cmd) {
    1397           0 :         case 'c':
    1398           0 :                 ch = isBreakpoint(cntxt, mb, p, pc);
    1399           0 :                 if (ch == 't') {
    1400             :                         /* help mclients with fake prompt */
    1401           0 :                         mnstr_printf(out, "mdb>");
    1402           0 :                         printTraceCall(out, mb, stk, pc, LIST_MAL_CALL);
    1403           0 :                 } else if (ch)
    1404           0 :                         mdbCommand(cntxt, mb, stk, p, pc);
    1405             :                 break;
    1406           0 :         case 's':
    1407             :         case 'n':
    1408           0 :                 mdbCommand(cntxt, mb, stk, p, pc);
    1409           0 :                 break;
    1410           0 :         case 't':
    1411           0 :                 printTraceCall(out, mb, stk, pc, LIST_MAL_CALL);
    1412           0 :                 break;
    1413             :         }
    1414           1 :         if (mb->errors != MAL_SUCCEED) {
    1415             :                 MalStkPtr su;
    1416             : 
    1417             :                 /* return from this debugger */
    1418           0 :                 for (su = stk; su; su = su->up)
    1419           0 :                         su->cmd = 0;
    1420           0 :                 mnstr_printf(out, "mdb>#EOD\n");
    1421           0 :                 stk->cmd = 'x'; /* will force a graceful termination */
    1422             :         }
    1423             : }
    1424             : 
    1425             : /*
    1426             :  * It would come in handy if at any time you could activate
    1427             :  * the debugger on a specific function. This calls for the
    1428             :  * creation of a minimal execution environment first.
    1429             :  */
    1430             : str
    1431           0 : runMALDebugger(Client cntxt, MalBlkPtr mb)
    1432             : {
    1433           0 :         str oldprompt= cntxt->prompt;
    1434           0 :         int oldtrace = cntxt->itrace;
    1435             :         str msg;
    1436             : 
    1437           0 :         cntxt->itrace = 'n';
    1438             : 
    1439           0 :         msg = runMAL(cntxt, mb, 0, 0);
    1440             : 
    1441           0 :         cntxt->prompt =oldprompt;
    1442           0 :         cntxt->itrace = oldtrace;
    1443           0 :         mnstr_printf(cntxt->fdout, "mdb>#EOD\n");
    1444           0 :         removeMalBlkHistory(mb);
    1445           0 :         return msg;
    1446             : }
    1447             : 
    1448             : #else
    1449             : str runMALDebugger(Client cntxt, MalBlkPtr mb)
    1450             : {
    1451             :         (void)cntxt; (void)mb;
    1452             :         return NULL;
    1453             : }
    1454             : void mdbSetBreakRequest(Client cntxt, MalBlkPtr mb, str request, char cmd) {
    1455             :         (void)cntxt; (void)mb; (void)request; (void)cmd;
    1456             : }
    1457             : #endif

Generated by: LCOV version 1.14