LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mdb.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 321 35.5 %
Date: 2021-01-13 20:07:21 Functions: 16 33 48.5 %

          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 Martin Kersten
      11             :  * MAL debugger interface
      12             :  * This module provides access to the functionality offered
      13             :  * by the MonetDB debugger and interpreter status.
      14             :  * It is primarilly used in interactive sessions to activate
      15             :  * the debugger at a given point. Furthermore, the instructions
      16             :  * provide the necessary handle to generate information
      17             :  * for post-mortum analysis.
      18             :  *
      19             :  * To enable ease of debugging and performance monitoring, the MAL interpreter
      20             :  * comes with a hardwired gdb-like text-based debugger.
      21             :  * A limited set of instructions can be included in the programs themselves,
      22             :  * but beware that debugging has a global effect. Any concurrent user
      23             :  * will be affected by breakpoints being set.
      24             :  *
      25             :  * The prime scheme to inspect the MAL interpreter status is to use
      26             :  * the MAL debugger directly. However, in case of automatic exception handling
      27             :  * it helps to be able to obtain BAT versions of the critical information,
      28             :  * such as stack frame table, stack trace,
      29             :  * and the instruction(s) where an exception occurred.
      30             :  * The inspection typically occurs in the exception handling part of the
      31             :  * MAL block.
      32             :  *
      33             :  * Beware, a large class of internal errors can not easily captured this way.
      34             :  * For example, bus-errors and segmentation faults lead to premature
      35             :  * termination of the process. Similar, creation of the post-mortum
      36             :  * information may fail due to an inconsistent state or insufficient resources.
      37             :  */
      38             : 
      39             : #include "monetdb_config.h"
      40             : #include "gdk.h"
      41             : #include "mutils.h"
      42             : #include <time.h>
      43             : #include <sys/types.h>
      44             : #ifdef HAVE_DIRENT_H
      45             : #include <dirent.h>
      46             : #endif
      47             : #include "mal_resolve.h"
      48             : #include "mal_linker.h"
      49             : #include "mal_client.h"
      50             : #include "mal_exception.h"
      51             : #include "mal_debugger.h"
      52             : #include "mal_interpreter.h"
      53             : #include "mal_namespace.h"
      54             : #include "mal_authorize.h"
      55             : #include "mal_function.h"
      56             : 
      57             : #define MDBstatus(X) \
      58             :         if( stk->cmd && X==0 ) \
      59             :                 mnstr_printf(cntxt->fdout,"#Monet Debugger off\n"); \
      60             :         else if(stk->cmd==0 && X) \
      61             :                 mnstr_printf(cntxt->fdout,"#Monet Debugger on\n");
      62             : 
      63             : static int
      64           7 : pseudo(bat *ret, BAT *b, const char *X1, const char *X2, const char *X3) {
      65             :         char buf[BUFSIZ];
      66           7 :         snprintf(buf,BUFSIZ,"%s_%s_%s", X1,X2,X3);
      67           7 :         if (BBPindex(buf) <= 0 && BBPrename(b->batCacheid, buf) != 0)
      68             :                 return -1;
      69           7 :         if (BATroles(b,X2) != GDK_SUCCEED)
      70             :                 return -1;
      71           7 :         *ret = b->batCacheid;
      72           7 :         BBPkeepref(*ret);
      73           7 :         return 0;
      74             : }
      75             : 
      76             : static str
      77           0 : MDBstart(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
      78             : {
      79             :         Client c;
      80             :         int pid;
      81             : 
      82           0 :         if( p->argc == 2){
      83             :                 /* debug running process */
      84           0 :                 pid = *getArgReference_int(stk, p, 1);
      85           0 :                 if( pid< 0 || pid >= MAL_MAXCLIENTS || mal_clients[pid].mode <= FINISHCLIENT)
      86           0 :                         throw(MAL, "mdb.start", ILLEGAL_ARGUMENT " Illegal process id");
      87           0 :                 if( cntxt->user != MAL_ADMIN && mal_clients[pid].user != cntxt->user)
      88           0 :                         throw(MAL, "mdb.start", "Access violation");
      89             :                 c= mal_clients+pid;
      90             :                 /* make client aware of being debugged */
      91             :                 cntxt= c;
      92             :         } else
      93           0 :         if ( stk->cmd == 0)
      94           0 :                 stk->cmd = 'n';
      95           0 :         cntxt->itrace = stk->cmd;
      96             :         (void) mb;
      97             :         (void) p;
      98           0 :         return MAL_SUCCEED;
      99             : }
     100             : 
     101             : static str
     102           0 : MDBstartFactory(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     103             : {
     104             :         (void) cntxt;
     105             :         (void) mb;
     106             :         (void) stk;
     107             :         (void) p;
     108           0 :                 throw(MAL, "mdb.start", SQLSTATE(0A000) PROGRAM_NYI);
     109             : }
     110             : 
     111             : static str
     112           0 : MDBstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     113             : {
     114           0 :         stk->cmd = 0;
     115           0 :         cntxt->itrace = 0;
     116           0 :         mnstr_printf(cntxt->fdout,"mdb>#EOD\n");
     117             :         (void) mb;
     118             :         (void) p;
     119           0 :         return MAL_SUCCEED;
     120             : }
     121             : 
     122             : static void
     123             : MDBtraceFlag(Client cntxt, MalStkPtr stk, int b)
     124             : {
     125             :         if (b) {
     126           0 :                 stk->cmd = b;
     127           0 :                 cntxt->itrace = b;
     128             :         } else {
     129           0 :                 stk->cmd = 0;
     130           0 :                 cntxt->itrace = 0;
     131             :         }
     132             : }
     133             : 
     134             : static str
     135           0 : MDBsetTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     136             : {
     137             :         int b;
     138             : 
     139             :         (void) cntxt;
     140             :         (void) mb;              /* still unused */
     141           0 :         b = *getArgReference_bit(stk, p, 1);
     142           0 :         MDBtraceFlag(cntxt, stk, (b? (int) 't':0));
     143           0 :         return MAL_SUCCEED;
     144             : }
     145             : 
     146             : static str
     147           0 : MDBgetVMsize(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     148             : {
     149           0 :         lng *ret = getArgReference_lng(stk, p, 0);
     150             : 
     151             :         (void) cntxt;
     152             :         (void) mb;              /* still unused */
     153           0 :         *ret = (lng) GDK_vm_maxsize / 1024/1024;
     154           0 :         return MAL_SUCCEED;
     155             : }
     156             : 
     157             : /* Set the max VM in MBs */
     158             : static str
     159           0 : MDBsetVMsize(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     160             : {
     161           0 :         lng *ret = getArgReference_lng(stk, p, 0);
     162             : 
     163             :         (void) cntxt;
     164             :         (void) mb;              /* still unused */
     165           0 :         *ret = (lng) GDK_vm_maxsize;
     166           0 :         if( *getArgReference_lng(stk, p, 1) > 1024 )
     167           0 :                 GDK_vm_maxsize = (size_t) (*getArgReference_lng(stk, p, 1) * 1024 * 1024);
     168           0 :         return MAL_SUCCEED;
     169             : }
     170             : 
     171             : static str
     172           0 : MDBsetVarTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     173             : {
     174             :         str v;
     175             : 
     176             :         (void) cntxt;
     177           0 :         v = *getArgReference_str(stk, p, 1);
     178           0 :         mdbSetBreakRequest(cntxt, mb, v, 't');
     179           0 :         stk->cmd = 'c';
     180           0 :         cntxt->itrace = 'c';
     181           0 :         return MAL_SUCCEED;
     182             : }
     183             : 
     184             : static str
     185          20 : MDBgetDebug(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     186             : {
     187          20 :         int *ret = getArgReference_int(stk,p,0);
     188             : 
     189             :         (void) cntxt;
     190             :         (void) mb;
     191             :         (void) stk;
     192             :         (void) p;
     193          20 :         *ret = GDKdebug;
     194          20 :         return MAL_SUCCEED;
     195             : }
     196             : 
     197             : static str
     198          43 : MDBsetDebug(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     199             : {
     200          43 :         int *ret = getArgReference_int(stk,p,0);
     201          43 :         int *flg = getArgReference_int(stk,p,1);
     202             : 
     203             :         (void) cntxt;
     204             :         (void) mb;
     205             :         (void) stk;
     206             :         (void) p;
     207          43 :         *ret = GDKgetdebug();
     208          43 :         GDKsetdebug(*flg);
     209          43 :         return MAL_SUCCEED;
     210             : }
     211             : 
     212             : #define addFlag(NME, FLG, DSET) \
     213             :         state =  (DSET & FLG)  > 0;\
     214             :         if (BUNappend(flg, (void*) NME, false) != GDK_SUCCEED) goto bailout;\
     215             :         if (BUNappend(val, &state, false) != GDK_SUCCEED) goto bailout;
     216             : 
     217             : static str
     218           0 : MDBgetDebugFlags(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     219             : {
     220           0 :         bat *f = getArgReference_bat(stk,p,0);
     221           0 :         bat *v = getArgReference_bat(stk,p,1);
     222             :         BAT *flg, *val;
     223           0 :         bit state = 0;
     224             : 
     225             :         (void) cntxt;
     226             :         (void) mb;
     227             : 
     228           0 :         flg = COLnew(0, TYPE_str, 256, TRANSIENT);
     229           0 :         val = COLnew(0, TYPE_bit, 256, TRANSIENT);
     230             : 
     231           0 :         if( flg == NULL || val == NULL){
     232           0 :                 BBPreclaim(flg);
     233           0 :                 BBPreclaim(val);
     234           0 :                 throw(MAL, "mdb.getDebugFlags",SQLSTATE(HY013) MAL_MALLOC_FAIL);
     235             :         }
     236           0 :         addFlag("threads", GRPthreads, GDKdebug);
     237           0 :         addFlag("memory", GRPmemory, GDKdebug);
     238           0 :         addFlag("properties", GRPproperties, GDKdebug);
     239           0 :         addFlag("io", GRPio, GDKdebug);
     240           0 :         addFlag("heaps", GRPheaps, GDKdebug);
     241           0 :         addFlag("transactions", GRPtransactions, GDKdebug);
     242           0 :         addFlag("modules", GRPmodules, GDKdebug);
     243           0 :         addFlag("algorithms", GRPalgorithms, GDKdebug);
     244           0 :         addFlag("performance", GRPperformance, GDKdebug);
     245           0 :         addFlag("forcemito", GRPforcemito, GDKdebug);
     246             : 
     247           0 :         BBPkeepref( *f = flg->batCacheid);
     248           0 :         BBPkeepref( *v = val->batCacheid);
     249           0 :         return MAL_SUCCEED;
     250             : 
     251           0 : bailout:
     252           0 :         BBPunfix(flg->batCacheid);
     253           0 :         BBPunfix(val->batCacheid);
     254           0 :         throw(MAL, "mdb.getDebugFlags",SQLSTATE(HY013) "Failed to append");
     255             : }
     256             : 
     257             : /* Toggle the debug flags on/off */
     258             : static str
     259             : MDBsetDebugStr_(int *ret, str *flg)
     260             : {
     261             :         int debug = GDKdebug;
     262             :         if( strcmp("threads",*flg)==0)
     263             :                 debug ^= GRPthreads;
     264             :         else if( strcmp("memory",*flg)==0)
     265             :                 debug ^= GRPmemory;
     266             :         else if( strcmp("properties",*flg)==0)
     267             :                 debug ^= GRPproperties;
     268             :         else if( strcmp("io",*flg)==0)
     269             :                 debug ^= GRPio;
     270             :         else if( strcmp("heaps",*flg)==0)
     271             :                 debug ^= GRPheaps;
     272             :         else if( strcmp("transactions",*flg)==0)
     273             :                 debug ^= GRPtransactions;
     274             :         else if( strcmp("modules",*flg)==0)
     275             :                 debug ^= GRPmodules;
     276             :         else if( strcmp("algorithms",*flg)==0)
     277             :                 debug ^= GRPalgorithms;
     278             :         else if( strcmp("performance",*flg)==0)
     279             :                 debug ^= GRPperformance;
     280             :         else if( strcmp("forcemito",*flg)==0)
     281             :                 debug ^= GRPforcemito;
     282             :         else
     283             :                 throw(MAL, "mdb.setDebugStr", ILLEGAL_ARGUMENT);
     284             :         *ret = GDKgetdebug();
     285             :         GDKsetdebug(debug);
     286             : 
     287             :         return MAL_SUCCEED;
     288             : }
     289             : 
     290             : static str
     291           0 : MDBsetDebugStr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     292             : {
     293           0 :         str *flg = (str*) getArgReference(stk, p, 1);
     294           0 :         int *ret = (int*) getArgReference(stk, p, 0);
     295             : 
     296             :         (void) cntxt;
     297             :         (void) mb;
     298           0 :         return MDBsetDebugStr_(ret, flg);
     299             : }
     300             : 
     301             : static str
     302           0 : MDBsetCatch(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     303             : {
     304             :         int b;
     305             : 
     306             :         (void) mb;              /* still unused */
     307           0 :         b = *getArgReference_bit(stk, p, 1);
     308           0 :         stk->cmd = cntxt->itrace = (b? (int) 'C':0);
     309           0 :         return MAL_SUCCEED;
     310             : }
     311             : 
     312             : static str
     313           0 : MDBinspect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     314             : {
     315             :         str modnme;
     316             :         str fcnnme;
     317             :         Symbol s = NULL;
     318             : 
     319             :         (void) cntxt;
     320           0 :         if (stk != 0) {
     321           0 :                 modnme = *getArgReference_str(stk, p, 1);
     322           0 :                 fcnnme = *getArgReference_str(stk, p, 2);
     323             :         } else {
     324           0 :                 modnme = getArgDefault(mb, p, 1);
     325           0 :                 fcnnme = getArgDefault(mb, p, 2);
     326             :         }
     327             : 
     328           0 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     329             : 
     330           0 :         if (s == NULL)
     331           0 :                 throw(MAL, "mdb.inspect", RUNTIME_SIGNATURE_MISSING);
     332           0 :         return runMALDebugger(cntxt, s->def);
     333             : }
     334             : 
     335             : /*
     336             :  * Variables and stack information
     337             :  * The variable information can be turned into a BAT for inspection as well.
     338             :  */
     339             : 
     340             : static int
     341             : getStkDepth(MalStkPtr s)
     342             : {
     343             :         int i = 0;
     344             : 
     345          12 :         while (s != 0) {
     346           8 :                 i++;
     347           8 :                 s = s->up;
     348             :         }
     349             :         return i;
     350             : }
     351             : 
     352             : static str
     353           1 : MDBStkDepth(Client cntxt, MalBlkPtr mb, MalStkPtr s, InstrPtr p)
     354             : {
     355           1 :         int *ret = getArgReference_int(s, p, 0);
     356             : 
     357             :         (void) cntxt;
     358             :         (void) mb;              /* fool compiler */
     359           1 :         *ret = getStkDepth(s);
     360           1 :         return MAL_SUCCEED;
     361             : }
     362             : 
     363             : static str
     364             : MDBgetFrame(BAT *b, BAT *bn, MalBlkPtr mb, MalStkPtr s, int depth, const char *name)
     365             : {
     366             :         ValPtr v;
     367             :         int i;
     368             :         char *buf = 0;
     369             : 
     370             :         while (depth > 0 && s) {
     371             :                 depth--;
     372             :                 s = s->up;
     373             :         }
     374             :         if (s != 0)
     375             :                 for (i = 0; i < s->stktop; i++, v++) {
     376             :                         v = &s->stk[i];
     377             :                         if ((buf = ATOMformat(v->vtype, VALptr(v))) == NULL ||
     378             :                                 BUNappend(b, getVarName(mb, i), false) != GDK_SUCCEED ||
     379             :                                 BUNappend(bn, buf, false) != GDK_SUCCEED) {
     380             :                                 BBPunfix(b->batCacheid);
     381             :                                 BBPunfix(bn->batCacheid);
     382             :                                 GDKfree(buf);
     383             :                                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     384             :                         }
     385             :                         GDKfree(buf);
     386             :                         buf = NULL;
     387             :                 }
     388             :         return MAL_SUCCEED;
     389             : }
     390             : 
     391             : static str
     392           0 : MDBgetStackFrame(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
     393             : {
     394           0 :         bat *ret = getArgReference_bat(s, p, 0);
     395           0 :         bat *ret2 = getArgReference_bat(s, p, 1);
     396           0 :         BAT *b = COLnew(0, TYPE_str, 256, TRANSIENT);
     397           0 :         BAT *bn = COLnew(0, TYPE_str, 256, TRANSIENT);
     398             :         str err;
     399             : 
     400             :         (void) cntxt;
     401           0 :         if (b == 0 || bn == 0) {
     402           0 :                 BBPreclaim(b);
     403           0 :                 BBPreclaim(bn);
     404           0 :                 throw(MAL, "mdb.getStackFrame", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     405             :         }
     406           0 :         if ((err = MDBgetFrame(b, bn, m, s, 0, "mdb.getStackFrame")) != MAL_SUCCEED) {
     407           0 :                 BBPreclaim(b);
     408           0 :                 BBPreclaim(bn);
     409           0 :                 return err;
     410             :         }
     411           0 :         if (pseudo(ret,b,"view","stk","frame")) {
     412           0 :                 BBPunfix(b->batCacheid);
     413           0 :                 BBPunfix(bn->batCacheid);
     414           0 :                 throw(MAL, "mdb.getStackFrame", GDK_EXCEPTION);
     415             :         }
     416           0 :         if (pseudo(ret2,bn,"view","stk","frame")) {
     417           0 :                 BBPrelease(*ret);
     418           0 :                 BBPunfix(bn->batCacheid);
     419           0 :                 throw(MAL, "mdb.getStackFrame", GDK_EXCEPTION);
     420             :         }
     421             :         return MAL_SUCCEED;
     422             : }
     423             : 
     424             : static str
     425           3 : MDBgetStackFrameN(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
     426             : {
     427             :         int n;
     428           3 :         bat *ret = getArgReference_bat(s, p, 0);
     429           3 :         bat *ret2 = getArgReference_bat(s, p, 1);
     430             :         BAT *b;
     431             :         BAT *bn;
     432             :         str err;
     433             : 
     434             :         (void) cntxt;
     435           3 :         n = *getArgReference_int(s, p, 2);
     436           6 :         if (n < 0 || n >= getStkDepth(s))
     437           1 :                 throw(MAL, "mdb.getStackFrame", ILLEGAL_ARGUMENT " Illegal depth.");
     438             : 
     439           2 :         b = COLnew(0, TYPE_str, 256, TRANSIENT);
     440           2 :         bn = COLnew(0, TYPE_str, 256, TRANSIENT);
     441           2 :         if (b == 0 || bn == 0) {
     442           0 :                 BBPreclaim(b);
     443           0 :                 BBPreclaim(bn);
     444           0 :                 throw(MAL, "mdb.getStackFrame", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     445             :         }
     446             : 
     447           2 :         if ((err = MDBgetFrame(b, bn, m, s, n, "mdb.getStackFrameN")) != MAL_SUCCEED) {
     448           0 :                 BBPreclaim(b);
     449           0 :                 BBPreclaim(bn);
     450           0 :                 return err;
     451             :         }
     452           2 :         if (pseudo(ret,b,"view","stk","frame")) {
     453           0 :                 BBPunfix(b->batCacheid);
     454           0 :                 BBPunfix(bn->batCacheid);
     455           0 :                 throw(MAL, "mdb.getStackFrameN", GDK_EXCEPTION);
     456             :         }
     457           2 :         if (pseudo(ret2,bn,"view","stk","frameB")) {
     458           0 :                 BBPrelease(*ret);
     459           0 :                 BBPunfix(bn->batCacheid);
     460           0 :                 throw(MAL, "mdb.getStackFrameN", GDK_EXCEPTION);
     461             :         }
     462             :         return MAL_SUCCEED;
     463             : }
     464             : 
     465             : static str
     466           1 : MDBStkTrace(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
     467             : {
     468             :         BAT *b, *bn;
     469             :         str msg;
     470             :         char *buf;
     471           1 :         bat *ret = getArgReference_bat(s, p, 0);
     472           1 :         bat *ret2 = getArgReference_bat(s, p, 1);
     473           1 :         int k = 0;
     474             :         size_t len,l;
     475             : 
     476           1 :         b = COLnew(0, TYPE_int, 256, TRANSIENT);
     477           1 :         if ( b== NULL)
     478           0 :                 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     479           1 :         bn = COLnew(0, TYPE_str, 256, TRANSIENT);
     480           1 :         if ( bn== NULL) {
     481           0 :                 BBPreclaim(b);
     482           0 :                 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     483             :         }
     484             :         (void) cntxt;
     485           1 :         if ((msg = instruction2str(s->blk, s, p, LIST_MAL_DEBUG)) == NULL) {
     486           0 :                 BBPreclaim(b);
     487           0 :                 BBPreclaim(bn);
     488           0 :                 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     489             :         }
     490           1 :         len = strlen(msg);
     491           1 :         buf = (char*) GDKmalloc(len +1024);
     492           1 :         if ( buf == NULL){
     493           0 :                 GDKfree(msg);
     494           0 :                 BBPreclaim(b);
     495           0 :                 BBPreclaim(bn);
     496           0 :                 throw(MAL,"mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     497             :         }
     498           1 :         snprintf(buf,len+1024,"%s at %s.%s[%d]", msg,
     499             :                 getModuleId(getInstrPtr(m,0)),
     500           1 :                 getFunctionId(getInstrPtr(m,0)), getPC(m, p));
     501           2 :         if (BUNappend(b, &k, false) != GDK_SUCCEED ||
     502           1 :                 BUNappend(bn, buf, false) != GDK_SUCCEED) {
     503           0 :                 GDKfree(msg);
     504           0 :                 GDKfree(buf);
     505           0 :                 BBPreclaim(b);
     506           0 :                 BBPreclaim(bn);
     507           0 :                 throw(MAL,"mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     508             :         }
     509           1 :         GDKfree(msg);
     510             : 
     511           2 :         for (s = s->up, k++; s != NULL; s = s->up, k++) {
     512           1 :                 if ((msg = instruction2str(s->blk, s, getInstrPtr(s->blk, s->pcup), LIST_MAL_DEBUG)) == NULL){
     513           0 :                         BBPunfix(b->batCacheid);
     514           0 :                         BBPunfix(bn->batCacheid);
     515           0 :                         throw(MAL,"mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     516             :                 }
     517           1 :                 l = strlen(msg);
     518           1 :                 if (l>len){
     519           0 :                         GDKfree(buf);
     520             :                         len=l;
     521           0 :                         buf = (char*) GDKmalloc(len +1024);
     522           0 :                         if ( buf == NULL){
     523           0 :                                 GDKfree(msg);
     524           0 :                                 BBPunfix(b->batCacheid);
     525           0 :                                 BBPunfix(bn->batCacheid);
     526           0 :                                 throw(MAL,"mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     527             :                         }
     528             :                 }
     529           1 :                 snprintf(buf,len+1024,"%s at %s.%s[%d]", msg,
     530             :                         getModuleId(getInstrPtr(s->blk,0)),
     531           1 :                         getFunctionId(getInstrPtr(s->blk,0)), s->pcup);
     532           2 :                 if (BUNappend(b, &k, false) != GDK_SUCCEED ||
     533           1 :                         BUNappend(bn, buf, false) != GDK_SUCCEED) {
     534           0 :                         GDKfree(buf);
     535           0 :                         GDKfree(msg);
     536           0 :                         BBPunfix(b->batCacheid);
     537           0 :                         BBPunfix(bn->batCacheid);
     538           0 :                         throw(MAL, "mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     539             :                 }
     540           1 :                 GDKfree(msg);
     541             :         }
     542           1 :         GDKfree(buf);
     543           1 :         if (pseudo(ret,b,"view","stk","trace")) {
     544           0 :                 BBPunfix(b->batCacheid);
     545           0 :                 BBPunfix(bn->batCacheid);
     546           0 :                 throw(MAL, "mdb.setTrace", GDK_EXCEPTION);
     547             :         }
     548           1 :         if (pseudo(ret2,bn,"view","stk","traceB")) {
     549           0 :                 BBPrelease(*ret);
     550           0 :                 BBPunfix(bn->batCacheid);
     551           0 :                 throw(MAL, "mdb.setTrace", GDK_EXCEPTION);
     552             :         }
     553             :         return MAL_SUCCEED;
     554             : }
     555             : 
     556             : /*
     557             :  * Display routines
     558             :  */
     559             : static str
     560           2 : MDBlist(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     561             : {
     562             :         (void) p;
     563             :         (void) stk;
     564           2 :         printFunction(cntxt->fdout, mb, 0,  LIST_MAL_NAME);
     565           2 :         return MAL_SUCCEED;
     566             : }
     567             : 
     568             : static str
     569           0 : MDBlistMapi(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     570             : {
     571             :         (void) p;
     572             :         (void) stk;
     573           0 :         printFunction(cntxt->fdout, mb, 0,  LIST_MAL_ALL);
     574           0 :         return MAL_SUCCEED;
     575             : }
     576             : 
     577             : static str
     578          27 : MDBlist3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     579             : {
     580          27 :         str modnme = *getArgReference_str(stk, p, 1);
     581          27 :         str fcnnme = *getArgReference_str(stk, p, 2);
     582             :         Symbol s = NULL;
     583             : 
     584          27 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     585          27 :         if (s == NULL)
     586           0 :                 throw(MAL,"mdb.list","Could not find %s.%s", modnme, fcnnme);
     587          27 :         printFunction(cntxt->fdout, s->def, 0,  LIST_MAL_NAME );
     588             :         (void) mb;              /* fool compiler */
     589          27 :         return MAL_SUCCEED;
     590             : }
     591             : 
     592             : static str
     593           2 : MDBlistDetail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     594             : {
     595             :         (void) p;
     596             :         (void) stk;
     597           2 :         printFunction(cntxt->fdout, mb, 0, LIST_MAL_DEBUG);
     598           2 :         return MAL_SUCCEED;
     599             : }
     600             : 
     601             : static str
     602          76 : MDBlist3Detail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     603             : {
     604          76 :         str modnme = *getArgReference_str(stk, p, 1);
     605          76 :         str fcnnme = *getArgReference_str(stk, p, 2);
     606             :         Symbol s = NULL;
     607             : 
     608          76 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     609          76 :         if (s == NULL)
     610           0 :                 throw(MAL,"mdb.list","Could not find %s.%s", modnme, fcnnme);
     611          76 :         printFunction(cntxt->fdout, s->def, 0,  LIST_MAL_DEBUG);
     612             :         (void) mb;              /* fool compiler */
     613          76 :         return NULL;
     614             : }
     615             : 
     616             : static str
     617           1 : MDBvar(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     618             : {
     619             :         (void) p;
     620             :         (void) stk;
     621           1 :         printStack(cntxt->fdout, mb, stk);
     622           1 :         return MAL_SUCCEED;
     623             : }
     624             : 
     625             : static str
     626           1 : MDBvar3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     627             : {
     628           1 :         str modnme = *getArgReference_str(stk, p, 1);
     629           1 :         str fcnnme = *getArgReference_str(stk, p, 2);
     630             :         Symbol s = NULL;
     631             : 
     632           1 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     633           1 :         if (s == NULL)
     634           0 :                 throw(MAL,"mdb.var","Could not find %s.%s", modnme, fcnnme);
     635           2 :         printStack(cntxt->fdout, s->def, (s->def == mb ? stk : 0));
     636             :         (void) mb;
     637           1 :         return NULL;
     638             : }
     639             : 
     640             : /*
     641             :  * It is illustrative to dump the code when you
     642             :  * have encountered an error.
     643             :  */
     644             : static str
     645           1 : MDBgetDefinition(Client cntxt, MalBlkPtr m, MalStkPtr stk, InstrPtr p)
     646             : {
     647             :         int i;
     648           1 :         bat *ret = getArgReference_bat(stk, p, 0);
     649             :         str ps;
     650           1 :         BAT *b = COLnew(0, TYPE_str, 256, TRANSIENT);
     651             : 
     652             :         (void) cntxt;
     653           1 :         if (b == 0)
     654           0 :                 throw(MAL, "mdb.getDefinition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     655             : 
     656           7 :         for (i = 0; i < m->stop; i++) {
     657           6 :                 if((ps = instruction2str(m,0, getInstrPtr(m, i), 1)) == NULL) {
     658           0 :                         BBPreclaim(b);
     659           0 :                         throw(MAL, "mdb.getDefinition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     660             :                 }
     661           6 :                 if (BUNappend(b, ps, false) != GDK_SUCCEED) {
     662           0 :                         GDKfree(ps);
     663           0 :                         BBPreclaim(b);
     664           0 :                         throw(MAL, "mdb.getDefinition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     665             :                 }
     666           6 :                 GDKfree(ps);
     667             :         }
     668           1 :         if (pseudo(ret,b,"view","fcn","stmt")) {
     669           0 :                 BBPreclaim(b);
     670           0 :                 throw(MAL, "mdb.getDefinition", GDK_EXCEPTION);
     671             :         }
     672             : 
     673             :         return MAL_SUCCEED;
     674             : }
     675             : 
     676             : static str
     677           0 : MDBgetExceptionVariable(str *ret, str *msg)
     678             : {
     679             :         str tail;
     680             : 
     681           0 :         tail = strchr(*msg, ':');
     682           0 :         if (tail == 0)
     683           0 :                 throw(MAL, "mdb.getExceptionVariable", OPERATION_FAILED " ':'<name> missing");
     684             : 
     685           0 :         *tail = 0;
     686           0 :         *ret = GDKstrdup(*msg);
     687           0 :         if (*ret == NULL)
     688           0 :                 throw(MAL, "mdb.getExceptionVariable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     689           0 :         *tail = ':';
     690           0 :         return MAL_SUCCEED;
     691             : }
     692             : 
     693             : static str
     694           0 : MDBgetExceptionContext(str *ret, str *msg)
     695             : {
     696             :         str tail, tail2;
     697             : 
     698           0 :         tail = strchr(*msg, ':');
     699           0 :         if (tail == 0)
     700           0 :                 throw(MAL, "mdb.getExceptionContext", OPERATION_FAILED " ':'<name> missing");
     701           0 :         tail2 = strchr(tail + 1, ':');
     702           0 :         if (tail2 == 0)
     703           0 :                 throw(MAL, "mdb.getExceptionContext", OPERATION_FAILED " <name> missing");
     704             : 
     705           0 :         *tail2 = 0;
     706           0 :         *ret = GDKstrdup(tail + 1);
     707           0 :         if (*ret == NULL)
     708           0 :                 throw(MAL, "mdb.getExceptionContext", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     709           0 :         *tail2 = ':';
     710           0 :         return MAL_SUCCEED;
     711             : }
     712             : 
     713             : static str
     714           0 : MDBgetExceptionReason(str *ret, str *msg)
     715             : {
     716             :         str tail;
     717             : 
     718           0 :         tail = strchr(*msg, ':');
     719           0 :         if (tail == 0)
     720           0 :                 throw(MAL, "mdb.getExceptionReason", OPERATION_FAILED " '::' missing");
     721           0 :         tail = strchr(tail + 1, ':');
     722           0 :         if (tail == 0)
     723           0 :                 throw(MAL, "mdb.getExceptionReason", OPERATION_FAILED " ':' missing");
     724             : 
     725           0 :         *ret = GDKstrdup(tail + 1);
     726           0 :         if( *ret == NULL)
     727           0 :                 throw(MAL, "mdb.getExceptionReason", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     728             :         return MAL_SUCCEED;
     729             : }
     730             : 
     731           0 : static str MDBdump(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){
     732             :         (void) cntxt;
     733           0 :         mdbDump(cntxt,mb,stk,pci);
     734           0 :         return MAL_SUCCEED;
     735             : }
     736             : 
     737             : static str
     738           1 : MDBdummy(int *ret)
     739             : {
     740             :         (void) ret;
     741           1 :         throw(MAL, "mdb.dummy", OPERATION_FAILED);
     742             : }
     743             : 
     744             : 
     745             : static str
     746           4 : CMDmodules(bat *bid)
     747             : {
     748           4 :         BAT *b = getModules();
     749             : 
     750           4 :         if (b == NULL)
     751           0 :                 throw(MAL, "mdb.modules", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     752           4 :         *bid = b->batCacheid;
     753           4 :         BBPkeepref(*bid);
     754           4 :         return MAL_SUCCEED;
     755             : }
     756             : 
     757             : #include "mel.h"
     758             : mel_func mdb_init_funcs[] = {
     759             :  pattern("mdb", "start", MDBstart, false, "Start interactive debugger", args(1,1, arg("",void))),
     760             :  pattern("mdb", "start", MDBstart, false, "Start interactive debugger on a client", args(1,2, arg("",void),arg("clientid",int))),
     761             :  pattern("mdb", "start", MDBstartFactory, false, "Start interactive debugger on a running factory", args(1,3, arg("",void),arg("mod",str),arg("fcn",str))),
     762             :  pattern("mdb", "stop", MDBstop, false, "Stop the interactive debugger", args(1,1, arg("",void))),
     763             :  pattern("mdb", "inspect", MDBinspect, false, "Run the debugger on a specific function", args(1,3, arg("",void),arg("mod",str),arg("fcn",str))),
     764             :  command("mdb", "modules", CMDmodules, false, "List available modules", args(1,1, batarg("",str))),
     765             :  pattern("mdb", "getVMsize", MDBgetVMsize, false, "Retrieve the max VM size", args(1,1, arg("",lng))),
     766             :  pattern("mdb", "setVMsize", MDBsetVMsize, false, "Manipulate the VM max size in MBs", args(1,2, arg("",lng),arg("l",lng))),
     767             :  pattern("mdb", "setTrace", MDBsetTrace, false, "Turn on/off tracing of current routine", args(1,2, arg("",void),arg("b",bit))),
     768             :  pattern("mdb", "setTrace", MDBsetVarTrace, false, "Turn on/off tracing of a variable ", args(1,2, arg("",void),arg("b",str))),
     769             :  pattern("mdb", "setCatch", MDBsetCatch, false, "Turn on/off catching exceptions", args(1,2, arg("",void),arg("b",bit))),
     770             :  pattern("mdb", "getDebugFlags", MDBgetDebugFlags, false, "Get the kernel debugging flags bit-set", args(2,2, batarg("flg",str),batarg("val",bit))),
     771             :  pattern("mdb", "getDebug", MDBgetDebug, false, "Get the kernel debugging bit-set.\nSee the MonetDB configuration file for details", args(1,1, arg("",int))),
     772             :  pattern("mdb", "setDebug", MDBsetDebugStr, false, "Set the kernel debugging bit-set and return its previous value.\nThe recognized options are: threads, memory, properties,\nio, transactions, modules, algorithms, estimates.", args(1,2, arg("",int),arg("flg",str))),
     773             :  pattern("mdb", "setDebug", MDBsetDebug, false, "Set the kernel debugging bit-set and return its previous value.", args(1,2, arg("",int),arg("flg",int))),
     774             :  command("mdb", "getException", MDBgetExceptionVariable, false, "Extract the variable name from the exception message", args(1,2, arg("",str),arg("s",str))),
     775             :  command("mdb", "getReason", MDBgetExceptionReason, false, "Extract the reason from the exception message", args(1,2, arg("",str),arg("s",str))),
     776             :  command("mdb", "getContext", MDBgetExceptionContext, false, "Extract the context string from the exception message", args(1,2, arg("",str),arg("s",str))),
     777             :  pattern("mdb", "list", MDBlist, false, "Dump the current routine on standard out.", args(1,1, arg("",void))),
     778             :  pattern("mdb", "listMapi", MDBlistMapi, false, "Dump the current routine on standard out with Mapi prefix.", args(1,1, arg("",void))),
     779             :  pattern("mdb", "list", MDBlist3, false, "Dump the routine M.F on standard out.", args(1,3, arg("",void),arg("M",str),arg("F",str))),
     780             :  pattern("mdb", "List", MDBlistDetail, false, "Dump the current routine on standard out.", args(1,1, arg("",void))),
     781             :  pattern("mdb", "List", MDBlist3Detail, false, "Dump the routine M.F on standard out.", args(1,3, arg("",void),arg("M",str),arg("F",str))),
     782             :  pattern("mdb", "var", MDBvar, false, "Dump the symboltable of current routine on standard out.", args(1,1, arg("",void))),
     783             :  pattern("mdb", "var", MDBvar3, false, "Dump the symboltable of routine M.F on standard out.", args(1,3, arg("",void),arg("M",str),arg("F",str))),
     784             :  pattern("mdb", "getStackDepth", MDBStkDepth, false, "Return the depth of the calling stack.", args(1,1, arg("",int))),
     785             :  pattern("mdb", "getStackFrame", MDBgetStackFrameN, false, "", args(2,3, batarg("",str),batarg("",str),arg("i",int))),
     786             :  pattern("mdb", "getStackFrame", MDBgetStackFrame, false, "Collect variable binding of current (n-th) stack frame.", args(2,2, batarg("",str),batarg("",str))),
     787             :  pattern("mdb", "getStackTrace", MDBStkTrace, false, "", args(2,2, batarg("",int),batarg("",str))),
     788             :  pattern("mdb", "dump", MDBdump, false, "Dump instruction, stacktrace, and stack", noargs),
     789             :  pattern("mdb", "getDefinition", MDBgetDefinition, false, "Returns a string representation of the current function \nwith typing information attached", args(1,1, batarg("",str))),
     790             :  command("mdb", "#dummy", MDBdummy, false, "Dummy function for testing", args(1,1, arg("",void))),
     791             :  { .imp=NULL }
     792             : };
     793             : #include "mal_import.h"
     794             : #ifdef _MSC_VER
     795             : #undef read
     796             : #pragma section(".CRT$XCU",read)
     797             : #endif
     798         255 : LIB_STARTUP_FUNC(init_mdb_mal)
     799         255 : { mal_module("mdb", NULL, mdb_init_funcs); }

Generated by: LCOV version 1.14