1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * author Martin Kersten
11 * MAL debugger interface
12 * This module provides access to the functionality offered
13 * by the MonetDB debugger and interpreter status.
14 * It is primarilly used in interactive sessions to activate
15 * the debugger at a given point. Furthermore, the instructions
16 * provide the necessary handle to generate information
17 * for post-mortum analysis.
18 *
19 * To enable ease of debugging and performance monitoring, the MAL interpreter
20 * comes with a hardwired gdb-like text-based debugger.
21 * A limited set of instructions can be included in the programs themselves,
22 * but beware that debugging has a global effect. Any concurrent user
23 * will be affected by breakpoints being set.
24 *
25 * The prime scheme to inspect the MAL interpreter status is to use
26 * the MAL debugger directly. However, in case of automatic exception handling
27 * it helps to be able to obtain BAT versions of the critical information,
28 * such as stack frame table, stack trace,
29 * and the instruction(s) where an exception occurred.
30 * The inspection typically occurs in the exception handling part of the
31 * MAL block.
32 *
33 * Beware, a large class of internal errors can not easily captured this way.
34 * For example, bus-errors and segmentation faults lead to premature
35 * termination of the process. Similar, creation of the post-mortum
36 * information may fail due to an inconsistent state or insufficient resources.
37 */
38
39#include "monetdb_config.h"
40#include "mdb.h"
41#include "mal_authorize.h"
42#include "mal_function.h"
43
44#define MDBstatus(X) \
45 if( stk->cmd && X==0 ) \
46 mnstr_printf(cntxt->fdout,"#Monet Debugger off\n"); \
47 else if(stk->cmd==0 && X) \
48 mnstr_printf(cntxt->fdout,"#Monet Debugger on\n");
49
50static int
51pseudo(bat *ret, BAT *b, const char *X1, const char *X2, const char *X3) {
52 char buf[BUFSIZ];
53 snprintf(buf,BUFSIZ,"%s_%s_%s", X1,X2,X3);
54 if (BBPindex(buf) <= 0 && BBPrename(b->batCacheid, buf) != 0)
55 return -1;
56 if (BATroles(b,X2) != GDK_SUCCEED)
57 return -1;
58 *ret = b->batCacheid;
59 BBPkeepref(*ret);
60 return 0;
61}
62
63str
64MDBstart(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
65{
66 Client c;
67 int pid;
68
69 if( p->argc == 2){
70 /* debug running process */
71 pid = *getArgReference_int(stk, p, 1);
72 if( pid< 0 || pid >= MAL_MAXCLIENTS || mal_clients[pid].mode <= FINISHCLIENT)
73 throw(MAL, "mdb.start", ILLEGAL_ARGUMENT " Illegal process id");
74 if( cntxt->user != MAL_ADMIN && mal_clients[pid].user != cntxt->user)
75 throw(MAL, "mdb.start", "Access violation");
76 c= mal_clients+pid;
77 /* make client aware of being debugged */
78 cntxt= c;
79 } else
80 if ( stk->cmd == 0)
81 stk->cmd = 'n';
82 cntxt->itrace = stk->cmd;
83 (void) mb;
84 (void) p;
85 return MAL_SUCCEED;
86}
87
88str
89MDBstartFactory(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
90{
91 (void) cntxt;
92 (void) mb;
93 (void) stk;
94 (void) p;
95 throw(MAL, "mdb.start", SQLSTATE(0A000) PROGRAM_NYI);
96}
97
98str
99MDBstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
100{
101 stk->cmd = 0;
102 cntxt->itrace = 0;
103 mnstr_printf(cntxt->fdout,"mdb>#EOD\n");
104 (void) mb;
105 (void) p;
106 return MAL_SUCCEED;
107}
108
109static void
110MDBtraceFlag(Client cntxt, MalStkPtr stk, int b)
111{
112 if (b) {
113 stk->cmd = b;
114 cntxt->itrace = b;
115 } else {
116 stk->cmd = 0;
117 cntxt->itrace = 0;
118 }
119}
120
121str
122MDBsetTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
123{
124 int b;
125
126 (void) cntxt;
127 (void) mb; /* still unused */
128 b = *getArgReference_bit(stk, p, 1);
129 MDBtraceFlag(cntxt, stk, (b? (int) 't':0));
130 return MAL_SUCCEED;
131}
132
133str
134MDBgetVMsize(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
135{
136 lng *ret = getArgReference_lng(stk, p, 0);
137
138 (void) cntxt;
139 (void) mb; /* still unused */
140 *ret = (lng) GDK_vm_maxsize / 1024/1024;
141 return MAL_SUCCEED;
142}
143
144/* Set the max VM in MBs */
145str
146MDBsetVMsize(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
147{
148 lng *ret = getArgReference_lng(stk, p, 0);
149
150 (void) cntxt;
151 (void) mb; /* still unused */
152 *ret = (lng) GDK_vm_maxsize;
153 if( *getArgReference_lng(stk, p, 1) > 1024 )
154 GDK_vm_maxsize = (size_t) (*getArgReference_lng(stk, p, 1) * 1024 * 1024);
155 return MAL_SUCCEED;
156}
157
158str
159MDBsetVarTrace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
160{
161 str v;
162
163 (void) cntxt;
164 v = *getArgReference_str(stk, p, 1);
165 mdbSetBreakRequest(cntxt, mb, v, 't');
166 stk->cmd = 'c';
167 cntxt->itrace = 'c';
168 return MAL_SUCCEED;
169}
170
171str
172MDBgetDebug(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
173{
174 int *ret = getArgReference_int(stk,p,0);
175
176 (void) cntxt;
177 (void) mb;
178 (void) stk;
179 (void) p;
180 *ret = GDKdebug;
181 return MAL_SUCCEED;
182}
183
184str
185MDBsetDebug(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
186{
187 int *ret = getArgReference_int(stk,p,0);
188 int *flg = getArgReference_int(stk,p,1);
189
190 (void) cntxt;
191 (void) mb;
192 (void) stk;
193 (void) p;
194 GDKdebug = *flg;
195 *ret = GDKdebug;
196 return MAL_SUCCEED;
197}
198
199#define addFlag(NME, FLG, DSET) \
200 state = (DSET & FLG) > 0;\
201 if (BUNappend(flg, (void*) NME, false) != GDK_SUCCEED) goto bailout;\
202 if (BUNappend(val, &state, false) != GDK_SUCCEED) goto bailout;
203
204str
205MDBgetDebugFlags(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
206{
207 bat *f = getArgReference_bat(stk,p,0);
208 bat *v = getArgReference_bat(stk,p,1);
209 BAT *flg, *val;
210 bit state = 0;
211
212 (void) cntxt;
213 (void) mb;
214
215 flg = COLnew(0, TYPE_str, 256, TRANSIENT);
216 val = COLnew(0, TYPE_bit, 256, TRANSIENT);
217
218 if( flg == NULL || val == NULL){
219 BBPreclaim(flg);
220 BBPreclaim(val);
221 throw(MAL, "mdb.getDebugFlags",SQLSTATE(HY001) MAL_MALLOC_FAIL);
222 }
223 addFlag("threads", GRPthreads, GDKdebug);
224 addFlag("memory", GRPmemory, GDKdebug);
225 addFlag("properties", GRPproperties, GDKdebug);
226 addFlag("io", GRPio, GDKdebug);
227 addFlag("heaps", GRPheaps, GDKdebug);
228 addFlag("transactions", GRPtransactions, GDKdebug);
229 addFlag("modules", GRPmodules, GDKdebug);
230 addFlag("algorithms", GRPalgorithms, GDKdebug);
231 addFlag("performance", GRPperformance, GDKdebug);
232 addFlag("forcemito", GRPforcemito, GDKdebug);
233
234 addFlag("aliases", OPTaliases, OPTdebug);
235 addFlag("candidates", OPTcandidates, OPTdebug);
236 addFlag("coercion", OPTcoercion, OPTdebug);
237 addFlag("commonterms", OPTcommonterms, OPTdebug);
238 addFlag("constants", OPTconstants, OPTdebug);
239 addFlag("costmodel", OPTcostmodel, OPTdebug);
240 addFlag("dataflow", OPTdataflow, OPTdebug);
241 addFlag("deadcode", OPTdeadcode, OPTdebug);
242 addFlag("emptybind", OPTemptybind, OPTdebug);
243 addFlag("evaluate", OPTevaluate, OPTdebug);
244 addFlag("garbagecollector", OPTgarbagecollector, OPTdebug);
245 addFlag("generator", OPTgenerator, OPTdebug);
246 addFlag("inline", OPTinline, OPTdebug);
247 addFlag("jit", OPTjit, OPTdebug);
248 addFlag("json", OPTjson, OPTdebug);
249 addFlag("macros", OPTmacros, OPTdebug);
250 addFlag("matpack", OPTmatpack, OPTdebug);
251 addFlag("mergetable", OPTmergetable, OPTdebug);
252 addFlag("mitosis", OPTmitosis, OPTdebug);
253 addFlag("multiplex", OPTmultiplex, OPTdebug);
254 addFlag("oltp", OPToltp, OPTdebug);
255 addFlag("pipes", OPTpipes, OPTdebug);
256 addFlag("postfix", OPTpostfix, OPTdebug);
257 addFlag("prelude", OPTprelude, OPTdebug);
258 addFlag("profiler", OPTprofiler, OPTdebug);
259 addFlag("projectionpath", OPTprojectionpath, OPTdebug);
260 addFlag("pushselect", OPTpushselect, OPTdebug);
261 addFlag("querylog", OPTquerylog, OPTdebug);
262 addFlag("reduce", OPTreduce, OPTdebug);
263 addFlag("remap", OPTremap, OPTdebug);
264 addFlag("remotequeries", OPTremotequeries, OPTdebug);
265 addFlag("reorder", OPTreorder, OPTdebug);
266 addFlag("support", OPTsupport, OPTdebug);
267 addFlag("volcano", OPTvolcano, OPTdebug);
268 addFlag("wlc", OPTwlc, OPTdebug);
269
270 BBPkeepref( *f = flg->batCacheid);
271 BBPkeepref( *v = val->batCacheid);
272 return MAL_SUCCEED;
273
274bailout:
275 BBPunfix(flg->batCacheid);
276 BBPunfix(val->batCacheid);
277 throw(MAL, "mdb.getDebugFlags",SQLSTATE(HY001) "Failed to append");
278}
279
280/* Toggle the debug flags on/off */
281static str
282MDBsetDebugStr_(int *ret, str *flg)
283{
284 if( strcmp("threads",*flg)==0) GDKdebug ^= GRPthreads;
285 if( strcmp("memory",*flg)==0) GDKdebug ^= GRPmemory;
286 if( strcmp("properties",*flg)==0) GDKdebug ^= GRPproperties;
287 if( strcmp("io",*flg)==0) GDKdebug ^= GRPio;
288 if( strcmp("heaps",*flg)==0) GDKdebug ^= GRPheaps;
289 if( strcmp("transactions",*flg)==0) GDKdebug ^= GRPtransactions;
290 if( strcmp("modules",*flg)==0) GDKdebug ^= GRPmodules;
291 if( strcmp("algorithms",*flg)==0) GDKdebug ^= GRPalgorithms;
292 if( strcmp("performance",*flg)==0) GDKdebug ^= GRPperformance;
293 if( strcmp("forcemito",*flg)==0) GDKdebug ^= GRPforcemito;
294 *ret = GDKdebug;
295
296 if( strcmp("aliases",*flg)==0) OPTdebug ^= OPTaliases;
297 if( strcmp("candidates", *flg) == 0) OPTdebug ^= OPTcandidates;
298 if( strcmp("coercion", *flg) == 0) OPTdebug ^= OPTcoercion;
299 if( strcmp("commonterms", *flg) == 0) OPTdebug ^= OPTcommonterms;
300 if( strcmp("constants", *flg) == 0) OPTdebug ^= OPTconstants;
301 if( strcmp("costmodel", *flg) == 0) OPTdebug ^= OPTcostmodel;
302 if( strcmp("dataflow", *flg) == 0) OPTdebug ^= OPTdataflow;
303 if( strcmp("deadcode", *flg) == 0) OPTdebug ^= OPTdeadcode;
304 if( strcmp("emptybind", *flg) == 0) OPTdebug ^= OPTemptybind;
305 if( strcmp("evaluate", *flg) == 0) OPTdebug ^= OPTevaluate;
306 if( strcmp("garbagecollector", *flg) == 0) OPTdebug ^= OPTgarbagecollector;
307 if( strcmp("generator", *flg) == 0) OPTdebug ^= OPTgenerator;
308 if( strcmp("inline", *flg) == 0) OPTdebug ^= OPTinline;
309 if( strcmp("jit", *flg) == 0) OPTdebug ^= OPTjit;
310 if( strcmp("json", *flg) == 0) OPTdebug ^= OPTjson;
311 if( strcmp("macros", *flg) == 0) OPTdebug ^= OPTmacros;
312 if( strcmp("matpack", *flg) == 0) OPTdebug ^= OPTmatpack;
313 if( strcmp("mergetable", *flg) == 0) OPTdebug ^= OPTmergetable;
314 if( strcmp("mitosis", *flg) == 0) OPTdebug ^= OPTmitosis;
315 if( strcmp("multiplex", *flg) == 0) OPTdebug ^= OPTmultiplex;
316 if( strcmp("oltp", *flg) == 0) OPTdebug ^= OPToltp;
317 if( strcmp("pipes", *flg) == 0) OPTdebug ^= OPTpipes;
318 if( strcmp("postfix", *flg) == 0) OPTdebug ^= OPTpostfix;
319 if( strcmp("prelude", *flg) == 0) OPTdebug ^= OPTprelude;
320 if( strcmp("profiler", *flg) == 0) OPTdebug ^= OPTprofiler;
321 if( strcmp("projectionpath", *flg) == 0) OPTdebug ^= OPTprojectionpath;
322 if( strcmp("pushselect", *flg) == 0) OPTdebug ^= OPTpushselect;
323 if( strcmp("querylog", *flg) == 0) OPTdebug ^= OPTquerylog;
324 if( strcmp("reduce", *flg) == 0) OPTdebug ^= OPTreduce;
325 if( strcmp("remap", *flg) == 0) OPTdebug ^= OPTremap;
326 if( strcmp("remotequeries", *flg) == 0) OPTdebug ^= OPTremotequeries;
327 if( strcmp("reorder", *flg) == 0) OPTdebug ^= OPTreorder;
328 if( strcmp("support", *flg) == 0) OPTdebug ^= OPTsupport;
329 if( strcmp("volcano", *flg) == 0) OPTdebug ^= OPTvolcano;
330 if( strcmp("wlc", *flg) == 0) OPTdebug ^= OPTwlc;
331 return MAL_SUCCEED;
332}
333
334str
335MDBsetDebugStr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
336{
337 str *flg = (str*) getArgReference(stk, p, 1);
338 int *ret = (int*) getArgReference(stk, p, 0);
339
340 (void) cntxt;
341 (void) mb;
342 return MDBsetDebugStr_(ret, flg);
343}
344
345str
346MDBsetCatch(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
347{
348 int b;
349
350 (void) mb; /* still unused */
351 b = *getArgReference_bit(stk, p, 1);
352 stk->cmd = cntxt->itrace = (b? (int) 'C':0);
353 return MAL_SUCCEED;
354}
355
356str
357MDBinspect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
358{
359 str modnme;
360 str fcnnme;
361 Symbol s = NULL;
362
363 (void) cntxt;
364 if (stk != 0) {
365 modnme = *getArgReference_str(stk, p, 1);
366 fcnnme = *getArgReference_str(stk, p, 2);
367 } else {
368 modnme = getArgDefault(mb, p, 1);
369 fcnnme = getArgDefault(mb, p, 2);
370 }
371
372 s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
373
374 if (s == NULL)
375 throw(MAL, "mdb.inspect", RUNTIME_SIGNATURE_MISSING);
376 return runMALDebugger(cntxt, s->def);
377}
378
379/*
380 * Variables and stack information
381 * The variable information can be turned into a BAT for inspection as well.
382 */
383
384static int
385getStkDepth(MalStkPtr s)
386{
387 int i = 0;
388
389 while (s != 0) {
390 i++;
391 s = s->up;
392 }
393 return i;
394}
395
396str
397MDBStkDepth(Client cntxt, MalBlkPtr mb, MalStkPtr s, InstrPtr p)
398{
399 int *ret = getArgReference_int(s, p, 0);
400
401 (void) cntxt;
402 (void) mb; /* fool compiler */
403 *ret = getStkDepth(s);
404 return MAL_SUCCEED;
405}
406
407static str
408MDBgetFrame(BAT *b, BAT *bn, MalBlkPtr mb, MalStkPtr s, int depth, const char *name)
409{
410 ValPtr v;
411 int i;
412 char *buf = 0;
413
414 while (depth > 0 && s) {
415 depth--;
416 s = s->up;
417 }
418 if (s != 0)
419 for (i = 0; i < s->stktop; i++, v++) {
420 v = &s->stk[i];
421 if ((buf = ATOMformat(v->vtype, VALptr(v))) == NULL ||
422 BUNappend(b, getVarName(mb, i), false) != GDK_SUCCEED ||
423 BUNappend(bn, buf, false) != GDK_SUCCEED) {
424 BBPunfix(b->batCacheid);
425 BBPunfix(bn->batCacheid);
426 GDKfree(buf);
427 throw(MAL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL);
428 }
429 GDKfree(buf);
430 buf = NULL;
431 }
432 return MAL_SUCCEED;
433}
434
435str
436MDBgetStackFrame(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
437{
438 bat *ret = getArgReference_bat(s, p, 0);
439 bat *ret2 = getArgReference_bat(s, p, 1);
440 BAT *b = COLnew(0, TYPE_str, 256, TRANSIENT);
441 BAT *bn = COLnew(0, TYPE_str, 256, TRANSIENT);
442 str err;
443
444 (void) cntxt;
445 if (b == 0 || bn == 0) {
446 BBPreclaim(b);
447 BBPreclaim(bn);
448 throw(MAL, "mdb.getStackFrame", SQLSTATE(HY001) MAL_MALLOC_FAIL);
449 }
450 if ((err = MDBgetFrame(b, bn, m, s, 0, "mdb.getStackFrame")) != MAL_SUCCEED) {
451 BBPreclaim(b);
452 BBPreclaim(bn);
453 return err;
454 }
455 if (pseudo(ret,b,"view","stk","frame")) {
456 BBPunfix(b->batCacheid);
457 BBPunfix(bn->batCacheid);
458 throw(MAL, "mdb.getStackFrame", GDK_EXCEPTION);
459 }
460 if (pseudo(ret2,bn,"view","stk","frame")) {
461 BBPrelease(*ret);
462 BBPunfix(bn->batCacheid);
463 throw(MAL, "mdb.getStackFrame", GDK_EXCEPTION);
464 }
465 return MAL_SUCCEED;
466}
467
468str
469MDBgetStackFrameN(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
470{
471 int n;
472 bat *ret = getArgReference_bat(s, p, 0);
473 bat *ret2 = getArgReference_bat(s, p, 1);
474 BAT *b;
475 BAT *bn;
476 str err;
477
478 (void) cntxt;
479 n = *getArgReference_int(s, p, 2);
480 if (n < 0 || n >= getStkDepth(s))
481 throw(MAL, "mdb.getStackFrame", ILLEGAL_ARGUMENT " Illegal depth.");
482
483 b = COLnew(0, TYPE_str, 256, TRANSIENT);
484 bn = COLnew(0, TYPE_str, 256, TRANSIENT);
485 if (b == 0 || bn == 0) {
486 BBPreclaim(b);
487 BBPreclaim(bn);
488 throw(MAL, "mdb.getStackFrame", SQLSTATE(HY001) MAL_MALLOC_FAIL);
489 }
490
491 if ((err = MDBgetFrame(b, bn, m, s, n, "mdb.getStackFrameN")) != MAL_SUCCEED) {
492 BBPreclaim(b);
493 BBPreclaim(bn);
494 return err;
495 }
496 if (pseudo(ret,b,"view","stk","frame")) {
497 BBPunfix(b->batCacheid);
498 BBPunfix(bn->batCacheid);
499 throw(MAL, "mdb.getStackFrameN", GDK_EXCEPTION);
500 }
501 if (pseudo(ret2,bn,"view","stk","frameB")) {
502 BBPrelease(*ret);
503 BBPunfix(bn->batCacheid);
504 throw(MAL, "mdb.getStackFrameN", GDK_EXCEPTION);
505 }
506 return MAL_SUCCEED;
507}
508
509str
510MDBStkTrace(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
511{
512 BAT *b, *bn;
513 str msg;
514 char *buf;
515 bat *ret = getArgReference_bat(s, p, 0);
516 bat *ret2 = getArgReference_bat(s, p, 1);
517 int k = 0;
518 size_t len,l;
519
520 b = COLnew(0, TYPE_int, 256, TRANSIENT);
521 if ( b== NULL)
522 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
523 bn = COLnew(0, TYPE_str, 256, TRANSIENT);
524 if ( bn== NULL) {
525 BBPreclaim(b);
526 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
527 }
528 (void) cntxt;
529 if ((msg = instruction2str(s->blk, s, p, LIST_MAL_DEBUG)) == NULL) {
530 BBPreclaim(b);
531 BBPreclaim(bn);
532 throw(MAL, "mdb.getStackTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
533 }
534 len = strlen(msg);
535 buf = (char*) GDKmalloc(len +1024);
536 if ( buf == NULL){
537 GDKfree(msg);
538 BBPreclaim(b);
539 BBPreclaim(bn);
540 throw(MAL,"mdb.setTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
541 }
542 snprintf(buf,len+1024,"%s at %s.%s[%d]", msg,
543 getModuleId(getInstrPtr(m,0)),
544 getFunctionId(getInstrPtr(m,0)), getPC(m, p));
545 if (BUNappend(b, &k, false) != GDK_SUCCEED ||
546 BUNappend(bn, buf, false) != GDK_SUCCEED) {
547 GDKfree(msg);
548 GDKfree(buf);
549 BBPreclaim(b);
550 BBPreclaim(bn);
551 throw(MAL,"mdb.setTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
552 }
553 GDKfree(msg);
554
555 for (s = s->up, k++; s != NULL; s = s->up, k++) {
556 if ((msg = instruction2str(s->blk, s, getInstrPtr(s->blk,s->pcup),LIST_MAL_DEBUG)) == NULL){
557 BBPunfix(b->batCacheid);
558 BBPunfix(bn->batCacheid);
559 throw(MAL,"mdb.setTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
560 }
561 l = strlen(msg);
562 if (l>len){
563 GDKfree(buf);
564 len=l;
565 buf = (char*) GDKmalloc(len +1024);
566 if ( buf == NULL){
567 GDKfree(msg);
568 BBPunfix(b->batCacheid);
569 BBPunfix(bn->batCacheid);
570 throw(MAL,"mdb.setTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
571 }
572 }
573 snprintf(buf,len+1024,"%s at %s.%s[%d]", msg,
574 getModuleId(getInstrPtr(s->blk,0)),
575 getFunctionId(getInstrPtr(s->blk,0)), s->pcup);
576 if (BUNappend(b, &k, false) != GDK_SUCCEED ||
577 BUNappend(bn, buf, false) != GDK_SUCCEED) {
578 GDKfree(buf);
579 GDKfree(msg);
580 BBPunfix(b->batCacheid);
581 BBPunfix(bn->batCacheid);
582 throw(MAL, "mdb.setTrace", SQLSTATE(HY001) MAL_MALLOC_FAIL);
583 }
584 GDKfree(msg);
585 }
586 GDKfree(buf);
587 if (pseudo(ret,b,"view","stk","trace")) {
588 BBPunfix(b->batCacheid);
589 BBPunfix(bn->batCacheid);
590 throw(MAL, "mdb.setTrace", GDK_EXCEPTION);
591 }
592 if (pseudo(ret2,bn,"view","stk","traceB")) {
593 BBPrelease(*ret);
594 BBPunfix(bn->batCacheid);
595 throw(MAL, "mdb.setTrace", GDK_EXCEPTION);
596 }
597 return MAL_SUCCEED;
598}
599
600/*
601 * Display routines
602 */
603str
604MDBlist(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
605{
606 (void) p;
607 (void) stk;
608 printFunction(cntxt->fdout, mb, 0, LIST_MAL_NAME);
609 return MAL_SUCCEED;
610}
611
612str
613MDBlistMapi(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
614{
615 (void) p;
616 (void) stk;
617 printFunction(cntxt->fdout, mb, 0, LIST_MAL_ALL);
618 return MAL_SUCCEED;
619}
620
621str
622MDBlist3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
623{
624 str modnme = *getArgReference_str(stk, p, 1);
625 str fcnnme = *getArgReference_str(stk, p, 2);
626 Symbol s = NULL;
627
628 s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
629 if (s == NULL)
630 throw(MAL,"mdb.list","Could not find %s.%s", modnme, fcnnme);
631 printFunction(cntxt->fdout, s->def, 0, LIST_MAL_NAME );
632 (void) mb; /* fool compiler */
633 return MAL_SUCCEED;
634}
635
636str
637MDBlistDetail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
638{
639 (void) p;
640 (void) stk;
641 debugFunction(cntxt->fdout, mb, 0, LIST_MAL_NAME | LIST_MAL_VALUE | LIST_MAL_TYPE | LIST_MAL_PROPS, 0, mb->stop );
642 return MAL_SUCCEED;
643}
644
645str
646MDBlist3Detail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
647{
648 str modnme = *getArgReference_str(stk, p, 1);
649 str fcnnme = *getArgReference_str(stk, p, 2);
650 Symbol s = NULL;
651
652 s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
653 if (s == NULL)
654 throw(MAL,"mdb.list","Could not find %s.%s", modnme, fcnnme);
655 debugFunction(cntxt->fdout, s->def, 0, LIST_MAL_NAME | LIST_MAL_VALUE | LIST_MAL_TYPE | LIST_MAL_PROPS , 0, s->def->stop);
656 (void) mb; /* fool compiler */
657 return NULL;
658}
659
660str
661MDBvar(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
662{
663 (void) p;
664 (void) stk;
665 printStack(cntxt->fdout, mb, stk);
666 return MAL_SUCCEED;
667}
668
669str
670MDBvar3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
671{
672 str modnme = *getArgReference_str(stk, p, 1);
673 str fcnnme = *getArgReference_str(stk, p, 2);
674 Symbol s = NULL;
675
676 s = findSymbol(cntxt->usermodule, putName(modnme), putName(fcnnme));
677 if (s == NULL)
678 throw(MAL,"mdb.var","Could not find %s.%s", modnme, fcnnme);
679 printStack(cntxt->fdout, s->def, (s->def == mb ? stk : 0));
680 (void) mb;
681 return NULL;
682}
683
684/*
685 * It is illustrative to dump the code when you
686 * have encountered an error.
687 */
688str
689MDBgetDefinition(Client cntxt, MalBlkPtr m, MalStkPtr stk, InstrPtr p)
690{
691 int i;
692 bat *ret = getArgReference_bat(stk, p, 0);
693 str ps;
694 BAT *b = COLnew(0, TYPE_str, 256, TRANSIENT);
695
696 (void) cntxt;
697 if (b == 0)
698 throw(MAL, "mdb.getDefinition", SQLSTATE(HY001) MAL_MALLOC_FAIL);
699
700 for (i = 0; i < m->stop; i++) {
701 if((ps = instruction2str(m,0, getInstrPtr(m, i), 1)) == NULL) {
702 BBPreclaim(b);
703 throw(MAL, "mdb.getDefinition", SQLSTATE(HY001) MAL_MALLOC_FAIL);
704 }
705 if (BUNappend(b, ps, false) != GDK_SUCCEED) {
706 GDKfree(ps);
707 BBPreclaim(b);
708 throw(MAL, "mdb.getDefinition", SQLSTATE(HY001) MAL_MALLOC_FAIL);
709 }
710 GDKfree(ps);
711 }
712 if (pseudo(ret,b,"view","fcn","stmt")) {
713 BBPreclaim(b);
714 throw(MAL, "mdb.getDefinition", GDK_EXCEPTION);
715 }
716
717 return MAL_SUCCEED;
718}
719
720str
721MDBgetExceptionVariable(str *ret, str *msg)
722{
723 str tail;
724
725 tail = strchr(*msg, ':');
726 if (tail == 0)
727 throw(MAL, "mdb.getExceptionVariable", OPERATION_FAILED " ':'<name> missing");
728
729 *tail = 0;
730 *ret = GDKstrdup(*msg);
731 if (*ret == NULL)
732 throw(MAL, "mdb.getExceptionVariable", SQLSTATE(HY001) MAL_MALLOC_FAIL);
733 *tail = ':';
734 return MAL_SUCCEED;
735}
736
737str
738MDBgetExceptionContext(str *ret, str *msg)
739{
740 str tail, tail2;
741
742 tail = strchr(*msg, ':');
743 if (tail == 0)
744 throw(MAL, "mdb.getExceptionContext", OPERATION_FAILED " ':'<name> missing");
745 tail2 = strchr(tail + 1, ':');
746 if (tail2 == 0)
747 throw(MAL, "mdb.getExceptionContext", OPERATION_FAILED " <name> missing");
748
749 *tail2 = 0;
750 *ret = GDKstrdup(tail + 1);
751 if (*ret == NULL)
752 throw(MAL, "mdb.getExceptionContext", SQLSTATE(HY001) MAL_MALLOC_FAIL);
753 *tail2 = ':';
754 return MAL_SUCCEED;
755}
756
757str
758MDBgetExceptionReason(str *ret, str *msg)
759{
760 str tail;
761
762 tail = strchr(*msg, ':');
763 if (tail == 0)
764 throw(MAL, "mdb.getExceptionReason", OPERATION_FAILED " '::' missing");
765 tail = strchr(tail + 1, ':');
766 if (tail == 0)
767 throw(MAL, "mdb.getExceptionReason", OPERATION_FAILED " ':' missing");
768
769 *ret = GDKstrdup(tail + 1);
770 if( *ret == NULL)
771 throw(MAL, "mdb.getExceptionReason", SQLSTATE(HY001) MAL_MALLOC_FAIL);
772 return MAL_SUCCEED;
773}
774
775str MDBdump(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){
776 (void) cntxt;
777 mdbDump(cntxt,mb,stk,pci);
778 return MAL_SUCCEED;
779}
780
781str
782MDBdummy(int *ret)
783{
784 (void) ret;
785 throw(MAL, "mdb.dummy", OPERATION_FAILED);
786}
787
788/*
789 * CMDmodules
790 * Obtains a list of modules by looking at what files are present in the
791 * module directory.
792 */
793static BAT *
794TBL_getdir(void)
795{
796 BAT *b = COLnew(0, TYPE_str, 100, TRANSIENT);
797 int i = 0;
798
799 const char *mod_path;
800 size_t extlen = strlen(MAL_EXT);
801 size_t len;
802 struct dirent *dent;
803 DIR *dirp = NULL;
804
805 if ( b == 0)
806 return NULL;
807 mod_path = GDKgetenv("monet_mod_path");
808 if (mod_path == NULL)
809 return b;
810 while (*mod_path == PATH_SEP)
811 mod_path++;
812 if (*mod_path == 0)
813 return b;
814
815 while (mod_path || dirp) {
816 if (dirp == NULL) {
817 char *cur_dir;
818 const char *p;
819 size_t l;
820
821 if ((p = strchr(mod_path, PATH_SEP)) != NULL) {
822 l = p - mod_path;
823 } else {
824 l = strlen(mod_path);
825 }
826 cur_dir = GDKmalloc(l + 1);
827 if ( cur_dir == NULL){
828 BBPreclaim(b);
829 return NULL;
830 }
831 strncpy(cur_dir, mod_path, l + 1); /* including NULL byte */
832 if ((mod_path = p) != NULL) {
833 while (*mod_path == PATH_SEP)
834 mod_path++;
835 }
836 dirp = opendir(cur_dir);
837 GDKfree(cur_dir);
838 if (dirp == NULL)
839 continue;
840 }
841 if ((dent = readdir(dirp)) == NULL) {
842 closedir(dirp);
843 dirp = NULL;
844 continue;
845 }
846 len = strlen(dent->d_name);
847 if (len < extlen || strcmp(dent->d_name + len - extlen, MAL_EXT) != 0)
848 continue;
849 dent->d_name[len - extlen] = 0;
850 if (BUNappend(b, dent->d_name, false) != GDK_SUCCEED) {
851 BBPreclaim(b);
852 if (dirp)
853 closedir(dirp);
854 return NULL;
855 }
856 i++;
857 }
858 return b;
859}
860
861str
862CMDmodules(bat *bid)
863{
864 BAT *b = TBL_getdir();
865
866 if (b == NULL)
867 throw(MAL, "mdb.modules", SQLSTATE(HY001) MAL_MALLOC_FAIL);
868 *bid = b->batCacheid;
869 BBPkeepref(*bid);
870 return MAL_SUCCEED;
871}
872