LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mdb.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 142 445 31.9 %
Date: 2024-04-25 20:03:45 Functions: 12 31 38.7 %

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

Generated by: LCOV version 1.14