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 | |
50 | static int |
51 | pseudo(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 | |
63 | str |
64 | MDBstart(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 | |
88 | str |
89 | MDBstartFactory(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 | |
98 | str |
99 | MDBstop(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 | |
109 | static void |
110 | MDBtraceFlag(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 | |
121 | str |
122 | MDBsetTrace(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 | |
133 | str |
134 | MDBgetVMsize(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 */ |
145 | str |
146 | MDBsetVMsize(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 | |
158 | str |
159 | MDBsetVarTrace(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 | |
171 | str |
172 | MDBgetDebug(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 | |
184 | str |
185 | MDBsetDebug(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 | |
204 | str |
205 | MDBgetDebugFlags(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 | |
274 | bailout: |
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 */ |
281 | static str |
282 | MDBsetDebugStr_(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 | |
334 | str |
335 | MDBsetDebugStr(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 | |
345 | str |
346 | MDBsetCatch(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 | |
356 | str |
357 | MDBinspect(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 | |
384 | static int |
385 | getStkDepth(MalStkPtr s) |
386 | { |
387 | int i = 0; |
388 | |
389 | while (s != 0) { |
390 | i++; |
391 | s = s->up; |
392 | } |
393 | return i; |
394 | } |
395 | |
396 | str |
397 | MDBStkDepth(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 | |
407 | static str |
408 | MDBgetFrame(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 | |
435 | str |
436 | MDBgetStackFrame(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 | |
468 | str |
469 | MDBgetStackFrameN(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 | |
509 | str |
510 | MDBStkTrace(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 | */ |
603 | str |
604 | MDBlist(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 | |
612 | str |
613 | MDBlistMapi(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 | |
621 | str |
622 | MDBlist3(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 | |
636 | str |
637 | MDBlistDetail(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 | |
645 | str |
646 | MDBlist3Detail(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 | |
660 | str |
661 | MDBvar(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 | |
669 | str |
670 | MDBvar3(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 | */ |
688 | str |
689 | MDBgetDefinition(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 | |
720 | str |
721 | MDBgetExceptionVariable(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 | |
737 | str |
738 | MDBgetExceptionContext(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 | |
757 | str |
758 | MDBgetExceptionReason(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 | |
775 | str MDBdump(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){ |
776 | (void) cntxt; |
777 | mdbDump(cntxt,mb,stk,pci); |
778 | return MAL_SUCCEED; |
779 | } |
780 | |
781 | str |
782 | MDBdummy(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 | */ |
793 | static BAT * |
794 | TBL_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 | |
861 | str |
862 | CMDmodules(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 | |