LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - mdb.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 143 446 32.1 %
Date: 2024-04-26 00:35:57 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          19 : MDBsetDebug(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     106             : {
     107          19 :         int *ret = getArgReference_int(stk, p, 0);
     108          19 :         int *flg = getArgReference_int(stk, p, 1);
     109             : 
     110          19 :         (void) cntxt;
     111          19 :         (void) mb;
     112          19 :         (void) stk;
     113          19 :         (void) p;
     114          19 :         *ret = (int) GDKgetdebug();
     115          19 :         GDKsetdebug((unsigned) *flg);
     116          19 :         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, const char *name)
     241             : {
     242           2 :         ValPtr v;
     243           2 :         int i;
     244           2 :         char *buf = 0;
     245             : 
     246           3 :         while (depth > 0 && s) {
     247           1 :                 depth--;
     248           1 :                 s = s->up;
     249             :         }
     250           2 :         if (s != 0) {
     251             :                 char namebuf[IDLENGTH];
     252          22 :                 for (i = 0; i < s->stktop; i++, v++) {
     253          20 :                         v = &s->stk[i];
     254          20 :                         if ((v->bat && (buf = ATOMformat(TYPE_int, &v->val.ival)) == NULL) ||
     255          40 :                             (!v->bat && (buf = ATOMformat(v->vtype, VALptr(v))) == NULL) ||
     256          40 :                                 BUNappend(b, getVarNameIntoBuffer(mb, i, namebuf), false) != GDK_SUCCEED ||
     257          20 :                                 BUNappend(bn, buf, false) != GDK_SUCCEED) {
     258           0 :                                 BBPunfix(b->batCacheid);
     259           0 :                                 BBPunfix(bn->batCacheid);
     260           0 :                                 GDKfree(buf);
     261           0 :                                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     262             :                         }
     263          20 :                         GDKfree(buf);
     264          20 :                         buf = NULL;
     265             :                 }
     266             :         }
     267             :         return MAL_SUCCEED;
     268             : }
     269             : 
     270             : static str
     271           0 : MDBgetStackFrame(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
     272             : {
     273           0 :         bat *ret = getArgReference_bat(s, p, 0);
     274           0 :         bat *ret2 = getArgReference_bat(s, p, 1);
     275           0 :         BAT *b = COLnew(0, TYPE_str, 256, TRANSIENT);
     276           0 :         BAT *bn = COLnew(0, TYPE_str, 256, TRANSIENT);
     277           0 :         str err;
     278             : 
     279           0 :         (void) cntxt;
     280           0 :         if (b == 0 || bn == 0) {
     281           0 :                 BBPreclaim(b);
     282           0 :                 BBPreclaim(bn);
     283           0 :                 throw(MAL, "mdb.getStackFrame", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     284             :         }
     285           0 :         if ((err = MDBgetFrame(b, bn, m, s, 0, "mdb.getStackFrame")) !=MAL_SUCCEED) {
     286           0 :                 BBPreclaim(b);
     287           0 :                 BBPreclaim(bn);
     288           0 :                 return err;
     289             :         }
     290           0 :         *ret = b->batCacheid;
     291           0 :         BBPkeepref(b);
     292           0 :         *ret2 = bn->batCacheid;
     293           0 :         BBPkeepref(bn);
     294           0 :         return MAL_SUCCEED;
     295             : }
     296             : 
     297             : static str
     298           3 : MDBgetStackFrameN(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
     299             : {
     300           3 :         int n;
     301           3 :         bat *ret = getArgReference_bat(s, p, 0);
     302           3 :         bat *ret2 = getArgReference_bat(s, p, 1);
     303           3 :         BAT *b;
     304           3 :         BAT *bn;
     305           3 :         str err;
     306             : 
     307           3 :         (void) cntxt;
     308           3 :         n = *getArgReference_int(s, p, 2);
     309           6 :         if (n < 0 || n >= getStkDepth(s))
     310           1 :                 throw(MAL, "mdb.getStackFrame", ILLEGAL_ARGUMENT " Illegal depth.");
     311             : 
     312           2 :         b = COLnew(0, TYPE_str, 256, TRANSIENT);
     313           2 :         bn = COLnew(0, TYPE_str, 256, TRANSIENT);
     314           2 :         if (b == 0 || bn == 0) {
     315           0 :                 BBPreclaim(b);
     316           0 :                 BBPreclaim(bn);
     317           0 :                 throw(MAL, "mdb.getStackFrame", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     318             :         }
     319             : 
     320           2 :         if ((err = MDBgetFrame(b, bn, m, s, n, "mdb.getStackFrameN")) !=MAL_SUCCEED) {
     321           0 :                 BBPreclaim(b);
     322           0 :                 BBPreclaim(bn);
     323           0 :                 return err;
     324             :         }
     325           2 :         *ret = b->batCacheid;
     326           2 :         BBPkeepref(b);
     327           2 :         *ret2 = bn->batCacheid;
     328           2 :         BBPkeepref(bn);
     329           2 :         return MAL_SUCCEED;
     330             : }
     331             : 
     332             : static str
     333           1 : MDBStkTrace(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
     334             : {
     335           1 :         BAT *b, *bn;
     336           1 :         str msg;
     337           1 :         char *buf;
     338           1 :         bat *ret = getArgReference_bat(s, p, 0);
     339           1 :         bat *ret2 = getArgReference_bat(s, p, 1);
     340           1 :         int k = 0;
     341           1 :         size_t len, l;
     342           1 :         int pcup;
     343             : 
     344           1 :         b = COLnew(0, TYPE_int, 256, TRANSIENT);
     345           1 :         if (b == NULL)
     346           0 :                 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     347           1 :         bn = COLnew(0, TYPE_str, 256, TRANSIENT);
     348           1 :         if (bn == NULL) {
     349           0 :                 BBPreclaim(b);
     350           0 :                 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     351             :         }
     352           1 :         (void) cntxt;
     353           1 :         if ((msg = instruction2str(s->blk, s, p, LIST_MAL_DEBUG)) == NULL) {
     354           0 :                 BBPreclaim(b);
     355           0 :                 BBPreclaim(bn);
     356           0 :                 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     357             :         }
     358           1 :         len = strlen(msg);
     359           1 :         buf = (char *) GDKmalloc(len + 1024);
     360           1 :         if (buf == NULL) {
     361           0 :                 GDKfree(msg);
     362           0 :                 BBPreclaim(b);
     363           0 :                 BBPreclaim(bn);
     364           0 :                 throw(MAL, "mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     365             :         }
     366           1 :         snprintf(buf, len + 1024, "%s at %s.%s[%d]", msg,
     367             :                          getModuleId(getInstrPtr(m, 0)),
     368           1 :                          getFunctionId(getInstrPtr(m, 0)), getPC(m, p));
     369           2 :         if (BUNappend(b, &k, false) != GDK_SUCCEED ||
     370           1 :                 BUNappend(bn, buf, false) != GDK_SUCCEED) {
     371           0 :                 GDKfree(msg);
     372           0 :                 GDKfree(buf);
     373           0 :                 BBPreclaim(b);
     374           0 :                 BBPreclaim(bn);
     375           0 :                 throw(MAL, "mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     376             :         }
     377           1 :         GDKfree(msg);
     378             : 
     379           2 :         for (pcup = s->pcup, s = s->up, k++; s != NULL;
     380           1 :                  pcup = s->pcup, s = s->up, k++) {
     381           1 :                 if ((msg = instruction2str(s->blk, s, getInstrPtr(s->blk, pcup),
     382             :                                                                    LIST_MAL_DEBUG)) == NULL) {
     383           0 :                         BBPunfix(b->batCacheid);
     384           0 :                         BBPunfix(bn->batCacheid);
     385           0 :                         throw(MAL, "mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     386             :                 }
     387           1 :                 l = strlen(msg);
     388           1 :                 if (l > len) {
     389           0 :                         GDKfree(buf);
     390           0 :                         len = l;
     391           0 :                         buf = (char *) GDKmalloc(len + 1024);
     392           0 :                         if (buf == NULL) {
     393           0 :                                 GDKfree(msg);
     394           0 :                                 BBPunfix(b->batCacheid);
     395           0 :                                 BBPunfix(bn->batCacheid);
     396           0 :                                 throw(MAL, "mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     397             :                         }
     398             :                 }
     399           1 :                 snprintf(buf, len + 1024, "%s at %s.%s[%d]", msg,
     400             :                                  getModuleId(getInstrPtr(s->blk, 0)),
     401           1 :                                  getFunctionId(getInstrPtr(s->blk, 0)), pcup);
     402           2 :                 if (BUNappend(b, &k, false) != GDK_SUCCEED ||
     403           1 :                         BUNappend(bn, buf, false) != GDK_SUCCEED) {
     404           0 :                         GDKfree(buf);
     405           0 :                         GDKfree(msg);
     406           0 :                         BBPunfix(b->batCacheid);
     407           0 :                         BBPunfix(bn->batCacheid);
     408           0 :                         throw(MAL, "mdb.setTrace", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     409             :                 }
     410           1 :                 GDKfree(msg);
     411             :         }
     412           1 :         GDKfree(buf);
     413           1 :         *ret = b->batCacheid;
     414           1 :         BBPkeepref(b);
     415           1 :         *ret2 = bn->batCacheid;
     416           1 :         BBPkeepref(bn);
     417           1 :         return MAL_SUCCEED;
     418             : }
     419             : 
     420             : /*
     421             :  * Display routines
     422             :  */
     423             : static str
     424           1 : MDBlist(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     425             : {
     426           1 :         (void) p;
     427           1 :         (void) stk;
     428           1 :         printFunction(cntxt->fdout, mb, 0, LIST_MAL_NAME);
     429           1 :         return MAL_SUCCEED;
     430             : }
     431             : 
     432             : static str
     433           0 : MDBlistMapi(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     434             : {
     435           0 :         (void) p;
     436           0 :         (void) stk;
     437           0 :         printFunction(cntxt->fdout, mb, 0, LIST_MAL_ALL);
     438           0 :         return MAL_SUCCEED;
     439             : }
     440             : 
     441             : static str
     442           2 : MDBlist3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     443             : {
     444           2 :         str modnme = *getArgReference_str(stk, p, 1);
     445           2 :         str fcnnme = *getArgReference_str(stk, p, 2);
     446           2 :         Symbol s = NULL;
     447             : 
     448           2 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     449           2 :         if (s == NULL)
     450           0 :                 throw(MAL, "mdb.list", "Could not find %s.%s", modnme, fcnnme);
     451           2 :         printFunction(cntxt->fdout, s->def, 0, LIST_MAL_NAME);
     452           2 :         (void) mb;                                      /* fool compiler */
     453           2 :         return MAL_SUCCEED;
     454             : }
     455             : 
     456             : static str
     457           0 : MDBlistDetail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     458             : {
     459           0 :         (void) p;
     460           0 :         (void) stk;
     461           0 :         printFunction(cntxt->fdout, mb, 0, LIST_MAL_DEBUG);
     462           0 :         return MAL_SUCCEED;
     463             : }
     464             : 
     465             : static str
     466           1 : MDBlist3Detail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     467             : {
     468           1 :         str modnme = *getArgReference_str(stk, p, 1);
     469           1 :         str fcnnme = *getArgReference_str(stk, p, 2);
     470           1 :         Symbol s = NULL;
     471             : 
     472           1 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     473           1 :         if (s == NULL)
     474           0 :                 throw(MAL, "mdb.list", "Could not find %s.%s", modnme, fcnnme);
     475           1 :         printFunction(cntxt->fdout, s->def, 0, LIST_MAL_DEBUG);
     476           1 :         (void) mb;                                      /* fool compiler */
     477           1 :         return NULL;
     478             : }
     479             : 
     480             : /* Utilities
     481             :  * Dumping a stack on a file is primarilly used for debugging.
     482             :  * Printing the stack requires access to both the symbol table and
     483             :  * the stackframes in most cases.
     484             :  * Beware that a stack frame need not be initialized with null values.
     485             :  * It has been zeroed upon creation.
     486             :  *
     487             :  * The routine  can also be used to inspect the symbol table of
     488             :  * arbitrary functions.
     489             :  */
     490             : static void
     491           0 : printStackHdr(stream *f, MalBlkPtr mb, const ValRecord *v, int index)
     492             : {
     493           0 :         char name[IDLENGTH] = { 0 };
     494           0 :         if (v == 0 && isVarConstant(mb, index))
     495           0 :                 v = &getVarConstant(mb, index);
     496           0 :         mnstr_printf(f, "#[%2d] %5s", index, getVarNameIntoBuffer(mb, index, name));
     497           0 :         mnstr_printf(f, " (%d,%d,%d) = ", getBeginScope(mb, index),
     498           0 :                                  getLastUpdate(mb, index), getEndScope(mb, index));
     499           0 :         if (v)
     500           0 :                 ATOMprint(v->vtype, VALptr(v), f);
     501           0 : }
     502             : 
     503             : static void
     504           0 : printBATproperties(stream *f, BAT *b)
     505             : {
     506           0 :         mnstr_printf(f, " count=" BUNFMT " lrefs=%d ",
     507           0 :                                  BATcount(b), BBP_lrefs(b->batCacheid));
     508           0 :         if (BBP_refs(b->batCacheid) - 1)
     509           0 :                 mnstr_printf(f, " refs=%d ", BBP_refs(b->batCacheid));
     510           0 :         if (b->theap->refs)
     511           0 :                 mnstr_printf(f, " views=%llu",
     512           0 :                                          (unsigned long long) ATOMIC_GET(&b->theap->refs));
     513           0 :         if (b->tvheap->refs)
     514           0 :                 mnstr_printf(f, " shared vheaps=%llu",
     515           0 :                                          (unsigned long long) ATOMIC_GET(&b->tvheap->refs));
     516           0 :         if (b->theap->parentid != b->batCacheid)
     517           0 :                 mnstr_printf(f, "view on %s ", BBP_logical(b->theap->parentid));
     518           0 : }
     519             : 
     520             : static void
     521           0 : printBATelm(stream *f, bat i, BUN cnt, BUN first)
     522             : {
     523           0 :         BAT *b, *bs = NULL;
     524           0 :         str tpe;
     525             : 
     526           0 :         b = BATdescriptor(i);
     527           0 :         if (b) {
     528           0 :                 tpe = getTypeName(newBatType(b->ttype));
     529           0 :                 mnstr_printf(f, ":%s ", tpe);
     530           0 :                 GDKfree(tpe);
     531           0 :                 printBATproperties(f, b);
     532             :                 /* perform property checking */
     533           0 :                 BATassertProps(b);
     534           0 :                 mnstr_printf(f, "\n");
     535           0 :                 if (cnt && BATcount(b) > 0) {
     536           0 :                         if (cnt < BATcount(b)) {
     537           0 :                                 mnstr_printf(f, "Sample " BUNFMT " out of " BUNFMT "\n", cnt,
     538             :                                                          BATcount(b));
     539             :                         }
     540             :                         /* cut out a portion of the BAT for display */
     541           0 :                         bs = BATslice(b, first, first + cnt);
     542             :                         /* get the void values */
     543           0 :                         if (bs == NULL)
     544           0 :                                 mnstr_printf(f, "Failed to take chunk\n");
     545             :                         else {
     546           0 :                                 if (BATprint(f, bs) != GDK_SUCCEED)
     547           0 :                                          mnstr_printf(f, "Failed to print chunk\n");
     548           0 :                                 BBPunfix(bs->batCacheid);
     549             :                         }
     550             :                 }
     551             : 
     552           0 :                 BBPunfix(b->batCacheid);
     553             :         } else
     554           0 :                 mnstr_printf(f, "\n");
     555           0 : }
     556             : 
     557             : static void
     558           0 : printStackElm(stream *f, MalBlkPtr mb, const ValRecord *v, int index, BUN cnt, BUN first)
     559             : {
     560           0 :         str nme, nmeOnStk;
     561           0 :         VarPtr n = getVar(mb, index);
     562             : 
     563           0 :         printStackHdr(f, mb, v, index);
     564             : 
     565           0 :         if (v && v->bat) {
     566           0 :                 bat i = v->val.bval;
     567           0 :                 BAT *b = BBPquickdesc(i);
     568             : 
     569           0 :                 if (b) {
     570           0 :                         nme = getTypeName(newBatType(b->ttype));
     571           0 :                         mnstr_printf(f, " :%s rows=" BUNFMT, nme, BATcount(b));
     572             :                 } else {
     573           0 :                         nme = getTypeName(n->type);
     574           0 :                         mnstr_printf(f, " :%s", nme);
     575             :                 }
     576             :         } else {
     577           0 :                 nme = getTypeName(n->type);
     578           0 :                 mnstr_printf(f, " :%s", nme);
     579             :         }
     580           0 :         nmeOnStk = v ? getTypeName(v->vtype) : GDKstrdup(nme);
     581             :         /* check for type errors */
     582           0 :         if (nmeOnStk && strcmp(nmeOnStk, nme) && strncmp(nmeOnStk, "BAT", 3))
     583           0 :                 mnstr_printf(f, "!%s ", nmeOnStk);
     584           0 :         mnstr_printf(f, " %s", (isVarConstant(mb, index) ? " constant" : ""));
     585           0 :         mnstr_printf(f, " %s", (isVarTypedef(mb, index) ? " type variable" : ""));
     586           0 :         GDKfree(nme);
     587           0 :         mnstr_printf(f, "\n");
     588           0 :         GDKfree(nmeOnStk);
     589             : 
     590           0 :         if (cnt && v && (isaBatType(n->type) || v->bat) && !is_bat_nil(v->val.bval)) {
     591           0 :                 printBATelm(f, v->val.bval, cnt, first);
     592             :         }
     593           0 : }
     594             : 
     595             : static void
     596           0 : printStack(stream *f, MalBlkPtr mb, MalStkPtr s)
     597             : {
     598           0 :         int i = 0;
     599             : 
     600           0 :         setVariableScope(mb);
     601           0 :         if (s) {
     602           0 :                 mnstr_printf(f, "#Stack '%s' size=%d top=%d\n",
     603           0 :                                          getInstrPtr(mb, 0)->fcnname, s->stksize, s->stktop);
     604           0 :                 for (; i < mb->vtop; i++)
     605           0 :                         printStackElm(f, mb, s->stk + i, i, 0, 0);
     606             :         } else
     607           0 :                 for (; i < mb->vtop; i++)
     608           0 :                         printStackElm(f, mb, 0, i, 0, 0);
     609           0 : }
     610             : 
     611             : static str
     612           0 : MDBvar(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     613             : {
     614           0 :         (void) p;
     615           0 :         (void) stk;
     616           0 :         (void) cntxt;
     617           0 :         (void) mb;
     618           0 :         printStack(cntxt->fdout, mb, stk);
     619           0 :         return MAL_SUCCEED;
     620             : }
     621             : 
     622             : static str
     623           0 : MDBvar3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     624             : {
     625           0 :         str modnme = *getArgReference_str(stk, p, 1);
     626           0 :         str fcnnme = *getArgReference_str(stk, p, 2);
     627           0 :         Symbol s = NULL;
     628             : 
     629           0 :         s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
     630           0 :         if (s == NULL)
     631           0 :                 throw(MAL, "mdb.var", "Could not find %s.%s", modnme, fcnnme);
     632           0 :         (void) cntxt;
     633           0 :         (void) mb;
     634           0 :         printStack(cntxt->fdout, s->def, (s->def == mb ? stk : 0));
     635           0 :         (void) mb;
     636           0 :         return NULL;
     637             : }
     638             : 
     639             : /*
     640             :  * It is illustrative to dump the code when you
     641             :  * have encountered an error.
     642             :  */
     643             : static str
     644           1 : MDBgetDefinition(Client cntxt, MalBlkPtr m, MalStkPtr stk, InstrPtr p)
     645             : {
     646           1 :         int i;
     647           1 :         bat *ret = getArgReference_bat(stk, p, 0);
     648           1 :         str ps;
     649           1 :         BAT *b = COLnew(0, TYPE_str, 256, TRANSIENT);
     650             : 
     651           1 :         (void) cntxt;
     652           1 :         if (b == 0)
     653           0 :                 throw(MAL, "mdb.getDefinition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     654             : 
     655           7 :         for (i = 0; i < m->stop; i++) {
     656           6 :                 if ((ps = instruction2str(m, 0, getInstrPtr(m, i), 1)) == NULL) {
     657           0 :                         BBPreclaim(b);
     658           0 :                         throw(MAL, "mdb.getDefinition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     659             :                 }
     660           6 :                 if (BUNappend(b, ps, false) != GDK_SUCCEED) {
     661           0 :                         GDKfree(ps);
     662           0 :                         BBPreclaim(b);
     663           0 :                         throw(MAL, "mdb.getDefinition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     664             :                 }
     665           6 :                 GDKfree(ps);
     666             :         }
     667           1 :         *ret = b->batCacheid;
     668           1 :         BBPkeepref(b);
     669             : 
     670           1 :         return MAL_SUCCEED;
     671             : }
     672             : 
     673             : static str
     674           0 : MDBgetExceptionVariable(str *ret, str *msg)
     675             : {
     676           0 :         str tail;
     677             : 
     678           0 :         tail = strchr(*msg, ':');
     679           0 :         if (tail == 0)
     680           0 :                 throw(MAL, "mdb.getExceptionVariable",
     681             :                           OPERATION_FAILED " ':'<name> missing");
     682             : 
     683           0 :         *tail = 0;
     684           0 :         *ret = GDKstrdup(*msg);
     685           0 :         if (*ret == NULL)
     686           0 :                 throw(MAL, "mdb.getExceptionVariable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     687           0 :         *tail = ':';
     688           0 :         return MAL_SUCCEED;
     689             : }
     690             : 
     691             : static str
     692           0 : MDBgetExceptionContext(str *ret, str *msg)
     693             : {
     694           0 :         str tail, tail2;
     695             : 
     696           0 :         tail = strchr(*msg, ':');
     697           0 :         if (tail == 0)
     698           0 :                 throw(MAL, "mdb.getExceptionContext",
     699             :                           OPERATION_FAILED " ':'<name> missing");
     700           0 :         tail2 = strchr(tail + 1, ':');
     701           0 :         if (tail2 == 0)
     702           0 :                 throw(MAL, "mdb.getExceptionContext",
     703             :                           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           0 :         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             : static str
     732           6 : MDBdummy(void *ret)
     733             : {
     734           6 :         (void) ret;
     735           6 :         throw(MAL, "mdb.dummy", OPERATION_FAILED);
     736             : }
     737             : 
     738             : 
     739             : static str
     740           0 : CMDmodules(bat *bid)
     741             : {
     742           0 :         BAT *b = getModules();
     743             : 
     744           0 :         if (b == NULL)
     745           0 :                 throw(MAL, "mdb.modules", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     746           0 :         *bid = b->batCacheid;
     747           0 :         BBPkeepref(b);
     748           0 :         return MAL_SUCCEED;
     749             : }
     750             : 
     751             : #include "mel.h"
     752             : mel_func mdb_init_funcs[] = {
     753             :  command("mdb", "modules", CMDmodules, false, "List available modules", args(1,1, batarg("",str))),
     754             :  pattern("mdb", "getVMsize", MDBgetVMsize, false, "Retrieve the max VM size", args(1,1, arg("",lng))),
     755             :  pattern("mdb", "setVMsize", MDBsetVMsize, false, "Manipulate the VM max size in MBs", args(1,2, arg("",lng),arg("l",lng))),
     756             :  pattern("mdb", "getDebugFlags", MDBgetDebugFlags, false, "Get the kernel debugging flags bit-set", args(2,2, batarg("flg",str),batarg("val",bit))),
     757             :  pattern("mdb", "getDebug", MDBgetDebug, false, "Get the kernel debugging bit-set.\nSee the MonetDB configuration file for details", args(1,1, arg("",int))),
     758             :  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))),
     759             :  pattern("mdb", "setDebug", MDBsetDebug, false, "Set the kernel debugging bit-set and return its previous value.", args(1,2, arg("",int),arg("flg",int))),
     760             :  command("mdb", "getException", MDBgetExceptionVariable, false, "Extract the variable name from the exception message", args(1,2, arg("",str),arg("s",str))),
     761             :  command("mdb", "getReason", MDBgetExceptionReason, false, "Extract the reason from the exception message", args(1,2, arg("",str),arg("s",str))),
     762             :  command("mdb", "getContext", MDBgetExceptionContext, false, "Extract the context string from the exception message", args(1,2, arg("",str),arg("s",str))),
     763             :  pattern("mdb", "list", MDBlist, false, "Dump the current routine on standard out.", args(1,1, arg("",void))),
     764             :  pattern("mdb", "listMapi", MDBlistMapi, false, "Dump the current routine on standard out with Mapi prefix.", args(1,1, arg("",void))),
     765             :  pattern("mdb", "list", MDBlist3, false, "Dump the routine M.F on standard out.", args(1,3, arg("",void),arg("M",str),arg("F",str))),
     766             :  pattern("mdb", "List", MDBlistDetail, false, "Dump the current routine on standard out.", args(1,1, arg("",void))),
     767             :  pattern("mdb", "List", MDBlist3Detail, false, "Dump the routine M.F on standard out.", args(1,3, arg("",void),arg("M",str),arg("F",str))),
     768             :  pattern("mdb", "var", MDBvar, false, "Dump the symboltable of current routine on standard out.", args(1,1, arg("",void))),
     769             :  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))),
     770             :  pattern("mdb", "getStackDepth", MDBStkDepth, false, "Return the depth of the calling stack.", args(1,1, arg("",int))),
     771             :  pattern("mdb", "getStackFrame", MDBgetStackFrameN, false, "", args(2,3, batarg("",str),batarg("",str),arg("i",int))),
     772             :  pattern("mdb", "getStackFrame", MDBgetStackFrame, false, "Collect variable binding of current (n-th) stack frame.", args(2,2, batarg("",str),batarg("",str))),
     773             :  pattern("mdb", "getStackTrace", MDBStkTrace, false, "", args(2,2, batarg("",int),batarg("",str))),
     774             :  pattern("mdb", "getDefinition", MDBgetDefinition, false, "Returns a string representation of the current function \nwith typing information attached", args(1,1, batarg("",str))),
     775             :  command("mdb", "#dummy", MDBdummy, false, "Dummy function for testing", args(1,1, arg("",void))),
     776             :  { .imp=NULL }
     777             : };
     778             : #include "mal_import.h"
     779             : #ifdef _MSC_VER
     780             : #undef read
     781             : #pragma section(".CRT$XCU",read)
     782             : #endif
     783         334 : LIB_STARTUP_FUNC(init_mdb_mal)
     784         334 : { mal_module("mdb", NULL, mdb_init_funcs); }

Generated by: LCOV version 1.14