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