]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_debugger.c
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.3.0 / src-separate / duk_debugger.c
CommitLineData
7c673cae
FG
1/*
2 * Duktape debugger
3 */
4
5#include "duk_internal.h"
6
7#if defined(DUK_USE_DEBUGGER_SUPPORT)
8
9/*
10 * Helper structs
11 */
12
13typedef union {
14 void *p;
15 duk_uint_t b[1];
16 /* Use b[] to access the size of the union, which is strictly not
17 * correct. Can't use fixed size unless there's feature detection
18 * for pointer byte size.
19 */
20} duk__ptr_union;
21
22/*
23 * Detach handling
24 */
25
26#define DUK__SET_CONN_BROKEN(thr) do { \
27 /* For now shared handler is fine. */ \
28 duk_debug_do_detach((thr)->heap); \
29 } while (0)
30
31DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
32 /* Can be called muliple times with no harm. */
33
34 heap->dbg_read_cb = NULL;
35 heap->dbg_write_cb = NULL;
36 heap->dbg_peek_cb = NULL;
37 heap->dbg_read_flush_cb = NULL;
38 heap->dbg_write_flush_cb = NULL;
39 if (heap->dbg_detached_cb) {
40 heap->dbg_detached_cb(heap->dbg_udata);
41 }
42 heap->dbg_detached_cb = NULL;
43 heap->dbg_udata = NULL;
44 heap->dbg_processing = 0;
45 heap->dbg_paused = 0;
46 heap->dbg_state_dirty = 0;
47 heap->dbg_force_restart = 0;
48 heap->dbg_step_type = 0;
49 heap->dbg_step_thread = NULL;
50 heap->dbg_step_csindex = 0;
51 heap->dbg_step_startline = 0;
52
53 /* Ensure there are no stale active breakpoint pointers.
54 * Breakpoint list is currently kept - we could empty it
55 * here but we'd need to handle refcounts correctly, and
56 * we'd need a 'thr' reference for that.
57 *
58 * XXX: clear breakpoint on either attach or detach?
59 */
60 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
61}
62
63/*
64 * Debug connection peek and flush primitives
65 */
66
67DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
68 duk_heap *heap;
69
70 DUK_ASSERT(thr != NULL);
71 heap = thr->heap;
72 DUK_ASSERT(heap != NULL);
73
74 if (heap->dbg_read_cb == NULL) {
75 DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
76 return 0;
77 }
78 if (heap->dbg_peek_cb == NULL) {
79 DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
80 return 0;
81 }
82
83 return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
84}
85
86DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
87 duk_heap *heap;
88
89 DUK_ASSERT(thr != NULL);
90 heap = thr->heap;
91 DUK_ASSERT(heap != NULL);
92
93 if (heap->dbg_read_cb == NULL) {
94 DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
95 return;
96 }
97 if (heap->dbg_read_flush_cb == NULL) {
98 DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
99 return;
100 }
101
102 heap->dbg_read_flush_cb(heap->dbg_udata);
103}
104
105DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
106 duk_heap *heap;
107
108 DUK_ASSERT(thr != NULL);
109 heap = thr->heap;
110 DUK_ASSERT(heap != NULL);
111
112 if (heap->dbg_read_cb == NULL) {
113 DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
114 return;
115 }
116 if (heap->dbg_write_flush_cb == NULL) {
117 DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
118 return;
119 }
120
121 heap->dbg_write_flush_cb(heap->dbg_udata);
122}
123
124/*
125 * Debug connection skip primitives
126 */
127
128/* Skip fully. */
129DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
130 duk_uint8_t dummy[64];
131 duk_size_t now;
132
133 DUK_ASSERT(thr != NULL);
134
135 while (length > 0) {
136 now = (length > sizeof(dummy) ? sizeof(dummy) : length);
137 duk_debug_read_bytes(thr, dummy, now);
138 length -= now;
139 }
140}
141
142DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
143 DUK_ASSERT(thr != NULL);
144
145 (void) duk_debug_read_byte(thr);
146}
147
148/*
149 * Debug connection read primitives
150 */
151
152/* Read fully. */
153DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
154 duk_heap *heap;
155 duk_uint8_t *p;
156 duk_size_t left;
157 duk_size_t got;
158
159 DUK_ASSERT(thr != NULL);
160 heap = thr->heap;
161 DUK_ASSERT(heap != NULL);
162
163 if (heap->dbg_read_cb == NULL) {
164 DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
165 goto fail;
166 }
167
168 p = data;
169 for (;;) {
170 left = (duk_size_t) ((data + length) - p);
171 if (left == 0) {
172 break;
173 }
174 DUK_ASSERT(heap->dbg_read_cb != NULL);
175 DUK_ASSERT(left >= 1);
176#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
177 left = 1;
178#endif
179 got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
180 if (got == 0 || got > left) {
181 DUK_D(DUK_DPRINT("connection error during read, return zero data"));
182 DUK__SET_CONN_BROKEN(thr);
183 goto fail;
184 }
185 p += got;
186 }
187 return;
188
189 fail:
190 DUK_MEMZERO((void *) data, (size_t) length);
191}
192
193DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
194 duk_heap *heap;
195 duk_size_t got;
196 duk_uint8_t x;
197
198 DUK_ASSERT(thr != NULL);
199 heap = thr->heap;
200 DUK_ASSERT(heap != NULL);
201
202 if (heap->dbg_read_cb == NULL) {
203 DUK_D(DUK_DPRINT("attempt to read 1 bytes in detached state, return zero data"));
204 return 0;
205 }
206
207 x = 0; /* just in case callback is broken and won't write 'x' */
208 DUK_ASSERT(heap->dbg_read_cb != NULL);
209 got = heap->dbg_read_cb(heap->dbg_udata, (char *) (&x), 1);
210 if (got != 1) {
211 DUK_D(DUK_DPRINT("connection error during read, return zero data"));
212 DUK__SET_CONN_BROKEN(thr);
213 return 0;
214 }
215
216 return x;
217}
218
219DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
220 duk_uint8_t buf[4];
221
222 DUK_ASSERT(thr != NULL);
223
224 duk_debug_read_bytes(thr, buf, 4);
225 return ((duk_uint32_t) buf[0] << 24) |
226 ((duk_uint32_t) buf[1] << 16) |
227 ((duk_uint32_t) buf[2] << 8) |
228 (duk_uint32_t) buf[3];
229}
230
231DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
232 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
233}
234
235DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
236 duk_uint8_t buf[2];
237
238 DUK_ASSERT(thr != NULL);
239
240 duk_debug_read_bytes(thr, buf, 2);
241 return ((duk_uint16_t) buf[0] << 8) |
242 (duk_uint16_t) buf[1];
243}
244
245DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
246 duk_small_uint_t x;
247 duk_small_uint_t t;
248
249 DUK_ASSERT(thr != NULL);
250
251 x = duk_debug_read_byte(thr);
252 if (x >= 0xc0) {
253 t = duk_debug_read_byte(thr);
254 return (duk_int32_t) (((x - 0xc0) << 8) + t);
255 } else if (x >= 0x80) {
256 return (duk_int32_t) (x - 0x80);
257 } else if (x == 0x10) {
258 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
259 }
260
261 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
262 DUK__SET_CONN_BROKEN(thr);
263 return 0;
264}
265
266DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
267 duk_context *ctx = (duk_context *) thr;
268 duk_uint8_t buf[31];
269 duk_uint8_t *p;
270
271 if (len <= sizeof(buf)) {
272 duk_debug_read_bytes(thr, buf, (duk_size_t) len);
273 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
274 } else {
275 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
276 DUK_ASSERT(p != NULL);
277 duk_debug_read_bytes(thr, p, (duk_size_t) len);
278 duk_to_string(ctx, -1);
279 }
280
281 return duk_require_hstring(ctx, -1);
282}
283
284DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
285 duk_context *ctx = (duk_context *) thr;
286 duk_small_uint_t x;
287 duk_uint32_t len;
288
289 DUK_ASSERT(thr != NULL);
290
291 x = duk_debug_read_byte(thr);
292 if (x >= 0x60 && x <= 0x7f) {
293 /* For short strings, use a fixed temp buffer. */
294 len = (duk_uint32_t) (x - 0x60);
295 } else if (x == 0x12) {
296 len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
297 } else if (x == 0x11) {
298 len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
299 } else {
300 goto fail;
301 }
302
303 return duk__debug_read_hstring_raw(thr, len);
304
305 fail:
306 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
307 DUK__SET_CONN_BROKEN(thr);
308 duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */
309 return duk_require_hstring(ctx, -1);
310}
311
312DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
313 duk_context *ctx = (duk_context *) thr;
314 duk_uint8_t *p;
315
316 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
317 DUK_ASSERT(p != NULL);
318 duk_debug_read_bytes(thr, p, (duk_size_t) len);
319
320 return duk_require_hbuffer(ctx, -1);
321}
322
323DUK_LOCAL const void *duk__debug_read_pointer_raw(duk_hthread *thr) {
324 duk_small_uint_t x;
325 volatile duk__ptr_union pu;
326
327 DUK_ASSERT(thr != NULL);
328
329 x = duk_debug_read_byte(thr);
330 if (x != sizeof(pu)) {
331 goto fail;
332 }
333 duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
334#if defined(DUK_USE_INTEGER_LE)
335 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
336#endif
337 return (const void *) pu.p;
338
339 fail:
340 DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
341 DUK__SET_CONN_BROKEN(thr);
342 return (const void *) NULL;
343}
344
345DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
346 duk_double_union du;
347
348 DUK_ASSERT(sizeof(du.uc) == 8);
349 duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
350 DUK_DBLUNION_DOUBLE_NTOH(&du);
351 return du.d;
352}
353
354DUK_INTERNAL void duk_debug_read_tval(duk_hthread *thr) {
355 duk_context *ctx = (duk_context *) thr;
356 duk_uint8_t x;
357 duk_uint_t t;
358 duk_uint32_t len;
359
360 DUK_ASSERT(thr != NULL);
361
362 x = duk_debug_read_byte(thr);
363
364 if (x >= 0xc0) {
365 t = (duk_uint_t) (x - 0xc0);
366 t = (t << 8) + duk_debug_read_byte(thr);
367 duk_push_uint(ctx, (duk_uint_t) t);
368 return;
369 }
370 if (x >= 0x80) {
371 duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
372 return;
373 }
374 if (x >= 0x60) {
375 len = (duk_uint32_t) (x - 0x60);
376 duk__debug_read_hstring_raw(thr, len);
377 return;
378 }
379
380 switch (x) {
381 case 0x10: {
382 duk_int32_t i = duk__debug_read_int32_raw(thr);
383 duk_push_i32(ctx, i);
384 break;
385 }
386 case 0x11:
387 len = duk__debug_read_uint32_raw(thr);
388 duk__debug_read_hstring_raw(thr, len);
389 break;
390 case 0x12:
391 len = duk__debug_read_uint16_raw(thr);
392 duk__debug_read_hstring_raw(thr, len);
393 break;
394 case 0x13:
395 len = duk__debug_read_uint32_raw(thr);
396 duk__debug_read_hbuffer_raw(thr, len);
397 break;
398 case 0x14:
399 len = duk__debug_read_uint16_raw(thr);
400 duk__debug_read_hbuffer_raw(thr, len);
401 break;
402 case 0x15:
403 duk_push_unused(ctx);
404 break;
405 case 0x16:
406 duk_push_undefined(ctx);
407 break;
408 case 0x17:
409 duk_push_null(ctx);
410 break;
411 case 0x18:
412 duk_push_true(ctx);
413 break;
414 case 0x19:
415 duk_push_false(ctx);
416 break;
417 case 0x1a: {
418 duk_double_t d;
419 d = duk__debug_read_double_raw(thr);
420 duk_push_number(ctx, d);
421 break;
422 }
423 case 0x1b:
424 /* XXX: not needed for now, so not implemented */
425 DUK_D(DUK_DPRINT("reading object values unimplemented"));
426 goto fail;
427 case 0x1c: {
428 const void *ptr;
429 ptr = duk__debug_read_pointer_raw(thr);
430 duk_push_pointer(thr, (void *) ptr);
431 break;
432 }
433 case 0x1d:
434 /* XXX: not needed for now, so not implemented */
435 DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
436 goto fail;
437 case 0x1e: {
438 duk_heaphdr *h;
439 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
440 duk_push_heapptr(thr, (void *) h);
441 break;
442 }
443 default:
444 goto fail;
445 }
446
447 return;
448
449 fail:
450 DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
451 DUK__SET_CONN_BROKEN(thr);
452}
453
454/*
455 * Debug connection write primitives
456 */
457
458/* Write fully. */
459DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
460 duk_heap *heap;
461 const duk_uint8_t *p;
462 duk_size_t left;
463 duk_size_t got;
464
465 DUK_ASSERT(thr != NULL);
466 DUK_ASSERT(length == 0 || data != NULL);
467 heap = thr->heap;
468 DUK_ASSERT(heap != NULL);
469
470 if (heap->dbg_write_cb == NULL) {
471 DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
472 return;
473 }
474 if (length == 0) {
475 /* Avoid doing an actual write callback with length == 0,
476 * because that's reserved for a write flush.
477 */
478 return;
479 }
480 DUK_ASSERT(data != NULL);
481
482 p = data;
483 for (;;) {
484 left = (duk_size_t) ((data + length) - p);
485 if (left == 0) {
486 break;
487 }
488 DUK_ASSERT(heap->dbg_write_cb != NULL);
489 DUK_ASSERT(left >= 1);
490#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
491 left = 1;
492#endif
493 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
494 if (got == 0 || got > left) {
495 DUK_D(DUK_DPRINT("connection error during write"));
496 DUK__SET_CONN_BROKEN(thr);
497 return;
498 }
499 p += got;
500 }
501}
502
503DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
504 duk_heap *heap;
505 duk_size_t got;
506
507 DUK_ASSERT(thr != NULL);
508 heap = thr->heap;
509 DUK_ASSERT(heap != NULL);
510
511 if (heap->dbg_write_cb == NULL) {
512 DUK_D(DUK_DPRINT("attempt to write 1 bytes in detached state, ignore"));
513 return;
514 }
515
516 DUK_ASSERT(heap->dbg_write_cb != NULL);
517 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) (&x), 1);
518 if (got != 1) {
519 DUK_D(DUK_DPRINT("connection error during write"));
520 DUK__SET_CONN_BROKEN(thr);
521 }
522}
523
524DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
525 duk_debug_write_byte(thr, 0x15);
526}
527
528DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
529 duk_debug_write_byte(thr, 0x16);
530}
531
532/* Write signed 32-bit integer. */
533DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
534 duk_uint8_t buf[5];
535 duk_size_t len;
536
537 DUK_ASSERT(thr != NULL);
538
539 if (x >= 0 && x <= 0x3fL) {
540 buf[0] = (duk_uint8_t) (0x80 + x);
541 len = 1;
542 } else if (x >= 0 && x <= 0x3fffL) {
543 buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
544 buf[1] = (duk_uint8_t) (x & 0xff);
545 len = 2;
546 } else {
547 /* Signed integers always map to 4 bytes now. */
548 buf[0] = (duk_uint8_t) 0x10;
549 buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
550 buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
551 buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
552 buf[4] = (duk_uint8_t) (x & 0xff);
553 len = 5;
554 }
555 duk_debug_write_bytes(thr, buf, len);
556}
557
558/* Write unsigned 32-bit integer. */
559DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
560 /* XXX: there's currently no need to support full 32-bit unsigned
561 * integer range in practice. If that becomes necessary, add a new
562 * dvalue type or encode as an IEEE double.
563 */
564 duk_debug_write_int(thr, (duk_int32_t) x);
565}
566
567DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
568 duk_uint8_t buf[5];
569 duk_size_t buflen;
570
571 DUK_ASSERT(thr != NULL);
572 DUK_ASSERT(length == 0 || data != NULL);
573
574 if (length <= 0x1fUL && marker_base == 0x11) {
575 /* For strings, special form for short lengths. */
576 buf[0] = (duk_uint8_t) (0x60 + length);
577 buflen = 1;
578 } else if (length <= 0xffffUL) {
579 buf[0] = (duk_uint8_t) (marker_base + 1);
580 buf[1] = (duk_uint8_t) (length >> 8);
581 buf[2] = (duk_uint8_t) (length & 0xff);
582 buflen = 3;
583 } else {
584 buf[0] = (duk_uint8_t) marker_base;
585 buf[1] = (duk_uint8_t) (length >> 24);
586 buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
587 buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
588 buf[4] = (duk_uint8_t) (length & 0xff);
589 buflen = 5;
590 }
591
592 duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
593 duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
594}
595
596DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
597 duk_debug_write_strbuf(thr, data, length, 0x11);
598}
599
600DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
601 DUK_ASSERT(thr != NULL);
602
603 duk_debug_write_string(thr,
604 data,
605 data ? DUK_STRLEN(data) : 0);
606}
607
608DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
609 DUK_ASSERT(thr != NULL);
610
611 /* XXX: differentiate null pointer from empty string? */
612 duk_debug_write_string(thr,
613 (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
614 (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
615}
616
617DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
618 duk_debug_write_strbuf(thr, data, length, 0x13);
619}
620
621DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
622 DUK_ASSERT(thr != NULL);
623
624 duk_debug_write_buffer(thr,
625 (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
626 (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
627}
628
629DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, const void *ptr, duk_uint8_t ibyte) {
630 duk_uint8_t buf[2];
631 volatile duk__ptr_union pu;
632
633 DUK_ASSERT(thr != NULL);
634 DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
635 /* ptr may be NULL */
636
637 buf[0] = ibyte;
638 buf[1] = sizeof(pu);
639 duk_debug_write_bytes(thr, buf, 2);
640 pu.p = (void *) ptr;
641#if defined(DUK_USE_INTEGER_LE)
642 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
643#endif
644 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
645}
646
647DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, const void *ptr) {
648 duk__debug_write_pointer_raw(thr, ptr, 0x1c);
649}
650
651#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
652DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
653 duk__debug_write_pointer_raw(thr, (const void *) h, 0x1e);
654}
655#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
656
657DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
658 duk_uint8_t buf[3];
659 volatile duk__ptr_union pu;
660
661 DUK_ASSERT(thr != NULL);
662 DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
663 DUK_ASSERT(obj != NULL);
664
665 buf[0] = 0x1b;
666 buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
667 buf[2] = sizeof(pu);
668 duk_debug_write_bytes(thr, buf, 3);
669 pu.p = (void *) obj;
670#if defined(DUK_USE_INTEGER_LE)
671 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
672#endif
673 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
674}
675
676DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
677 duk_c_function lf_func;
678 duk_small_uint_t lf_flags;
679 duk_uint8_t buf[4];
680 duk_double_union du;
681
682 DUK_ASSERT(thr != NULL);
683 DUK_ASSERT(tv != NULL);
684
685 switch (DUK_TVAL_GET_TAG(tv)) {
686 case DUK_TAG_UNDEFINED:
687 duk_debug_write_byte(thr,
688 DUK_TVAL_IS_UNDEFINED_UNUSED(tv) ? 0x15 : 0x16);
689 break;
690 case DUK_TAG_NULL:
691 duk_debug_write_byte(thr, 0x17);
692 break;
693 case DUK_TAG_BOOLEAN:
694 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
695 DUK_TVAL_GET_BOOLEAN(tv) == 1);
696 duk_debug_write_byte(thr, DUK_TVAL_GET_BOOLEAN(tv) ? 0x18 : 0x19);
697 break;
698 case DUK_TAG_POINTER:
699 duk_debug_write_pointer(thr, (const void *) DUK_TVAL_GET_POINTER(tv));
700 break;
701 case DUK_TAG_LIGHTFUNC:
702 DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
703 buf[0] = 0x1d;
704 buf[1] = (duk_uint8_t) (lf_flags >> 8);
705 buf[2] = (duk_uint8_t) (lf_flags & 0xff);
706 buf[3] = sizeof(lf_func);
707 duk_debug_write_bytes(thr, buf, 4);
708 duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
709 break;
710 case DUK_TAG_STRING:
711 duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
712 break;
713 case DUK_TAG_OBJECT:
714 duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
715 break;
716 case DUK_TAG_BUFFER:
717 duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
718 break;
719#if defined(DUK_USE_FASTINT)
720 case DUK_TAG_FASTINT:
721#endif
722 default:
723 /* Numbers are normalized to big (network) endian. */
724 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
725 du.d = DUK_TVAL_GET_NUMBER(tv);
726 DUK_DBLUNION_DOUBLE_HTON(&du);
727
728 duk_debug_write_byte(thr, 0x1a);
729 duk_debug_write_bytes(thr, (const duk_uint8_t *) du.uc, sizeof(du.uc));
730 }
731}
732
733#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
734/* Variant for writing duk_tvals so that any heap allocated values are
735 * written out as tagged heap pointers.
736 */
737DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
738 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
739 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
740 duk_debug_write_heapptr(thr, h);
741 } else {
742 duk_debug_write_tval(thr, tv);
743 }
744}
745#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
746
747/*
748 * Debug connection message write helpers
749 */
750
751#if 0 /* unused */
752DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
753 duk_debug_write_byte(thr, DUK_DBG_MARKER_REQUEST);
754 duk_debug_write_int(thr, command);
755}
756#endif
757
758DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
759 duk_debug_write_byte(thr, DUK_DBG_MARKER_REPLY);
760}
761
762DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
763 /* Allow NULL 'msg' */
764 duk_debug_write_byte(thr, DUK_DBG_MARKER_ERROR);
765 duk_debug_write_int(thr, (duk_int32_t) err_code);
766 duk_debug_write_cstring(thr, msg);
767 duk_debug_write_eom(thr);
768}
769
770DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
771 duk_debug_write_byte(thr, DUK_DBG_MARKER_NOTIFY);
772 duk_debug_write_int(thr, command);
773}
774
775DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
776 duk_debug_write_byte(thr, DUK_DBG_MARKER_EOM);
777
778 /* As an initial implementation, write flush after every EOM (and the
779 * version identifier). A better implementation would flush only when
780 * Duktape is finished processing messages so that a flush only happens
781 * after all outbound messages are finished on that occasion.
782 */
783 duk_debug_write_flush(thr);
784}
785
786/*
787 * Status message and helpers
788 */
789
790DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
791 duk_context *ctx = (duk_context *) thr;
792 duk_activation *act;
793 duk_uint_fast32_t line;
794 duk_uint_fast32_t pc;
795
796 if (thr->callstack_top == 0) {
797 return 0;
798 }
799 act = thr->callstack + thr->callstack_top - 1;
800
801 /* We're conceptually between two opcodes; act->pc indicates the next
802 * instruction to be executed. This is usually the correct pc/line to
803 * indicate in Status. (For the 'debugger' statement this now reports
804 * the pc/line after the debugger statement because the debugger opcode
805 * has already been executed.)
806 */
807
808 pc = duk_hthread_get_act_curr_pc(thr, act);
809
810 /* XXX: this should be optimized to be a raw query and avoid valstack
811 * operations if possible.
812 */
813 duk_push_hobject(ctx, act->func);
814 line = duk_hobject_pc2line_query(ctx, -1, pc);
815 duk_pop(ctx);
816 return line;
817}
818
819DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
820 duk_context *ctx = (duk_context *) thr;
821 duk_activation *act;
822
823 duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
824 duk_debug_write_int(thr, thr->heap->dbg_paused);
825
826 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
827 if (thr->callstack_top == 0) {
828 duk_debug_write_undefined(thr);
829 duk_debug_write_undefined(thr);
830 duk_debug_write_int(thr, 0);
831 duk_debug_write_int(thr, 0);
832 } else {
833 act = thr->callstack + thr->callstack_top - 1;
834 duk_push_hobject(ctx, act->func);
835 duk_get_prop_string(ctx, -1, "fileName");
836 duk_safe_to_string(ctx, -1);
837 duk_debug_write_hstring(thr, duk_require_hstring(ctx, -1));
838 duk_get_prop_string(ctx, -2, "name");
839 duk_safe_to_string(ctx, -1);
840 duk_debug_write_hstring(thr, duk_require_hstring(ctx, -1));
841 duk_pop_3(ctx);
842 /* Report next pc/line to be executed. */
843 duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
844 duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
845 }
846
847 duk_debug_write_eom(thr);
848}
849
850/*
851 * Debug message processing
852 */
853
854/* Skip dvalue. */
855DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
856 duk_uint8_t x;
857 duk_uint32_t len;
858
859 x = duk_debug_read_byte(thr);
860
861 if (x >= 0xc0) {
862 duk_debug_skip_byte(thr);
863 return 0;
864 }
865 if (x >= 0x80) {
866 return 0;
867 }
868 if (x >= 0x60) {
869 duk_debug_skip_bytes(thr, x - 0x60);
870 return 0;
871 }
872 switch(x) {
873 case 0x00:
874 return 1; /* Return 1: got EOM */
875 case 0x01:
876 case 0x02:
877 case 0x03:
878 case 0x04:
879 break;
880 case 0x10:
881 (void) duk__debug_read_uint32_raw(thr);
882 break;
883 case 0x11:
884 case 0x13:
885 len = duk__debug_read_uint32_raw(thr);
886 duk_debug_skip_bytes(thr, len);
887 break;
888 case 0x12:
889 case 0x14:
890 len = duk__debug_read_uint16_raw(thr);
891 duk_debug_skip_bytes(thr, len);
892 break;
893 case 0x15:
894 case 0x16:
895 case 0x17:
896 case 0x18:
897 case 0x19:
898 break;
899 case 0x1a:
900 duk_debug_skip_bytes(thr, 8);
901 break;
902 case 0x1b:
903 duk_debug_skip_byte(thr);
904 len = duk_debug_read_byte(thr);
905 duk_debug_skip_bytes(thr, len);
906 break;
907 case 0x1c:
908 len = duk_debug_read_byte(thr);
909 duk_debug_skip_bytes(thr, len);
910 break;
911 case 0x1d:
912 duk_debug_skip_bytes(thr, 2);
913 len = duk_debug_read_byte(thr);
914 duk_debug_skip_bytes(thr, len);
915 break;
916 default:
917 goto fail;
918 }
919
920 return 0;
921
922 fail:
923 DUK__SET_CONN_BROKEN(thr);
924 return 1; /* Pretend like we got EOM */
925}
926
927/* Skip dvalues to EOM. */
928DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
929 for (;;) {
930 if (duk__debug_skip_dvalue(thr)) {
931 break;
932 }
933 }
934}
935
936/*
937 * Process incoming debug requests
938 */
939
940DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
941 DUK_UNREF(heap);
942 DUK_D(DUK_DPRINT("debug command version"));
943
944 duk_debug_write_reply(thr);
945 duk_debug_write_int(thr, DUK_VERSION);
946 duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
947 duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
948#if defined(DUK_USE_DOUBLE_LE)
949 duk_debug_write_int(thr, 1);
950#elif defined(DUK_USE_DOUBLE_ME)
951 duk_debug_write_int(thr, 2);
952#elif defined(DUK_USE_DOUBLE_BE)
953 duk_debug_write_int(thr, 3);
954#else
955 duk_debug_write_int(thr, 0);
956#endif
957 duk_debug_write_eom(thr);
958}
959
960DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
961 DUK_UNREF(heap);
962 DUK_D(DUK_DPRINT("debug command triggerstatus"));
963
964 duk_debug_write_reply(thr);
965 duk_debug_write_eom(thr);
966 heap->dbg_state_dirty = 1;
967}
968
969DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
970 DUK_D(DUK_DPRINT("debug command pause"));
971
972 DUK_HEAP_SET_PAUSED(heap);
973 duk_debug_write_reply(thr);
974 duk_debug_write_eom(thr);
975}
976
977DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
978 DUK_D(DUK_DPRINT("debug command resume"));
979
980 DUK_HEAP_CLEAR_PAUSED(heap);
981 duk_debug_write_reply(thr);
982 duk_debug_write_eom(thr);
983}
984
985DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
986 duk_small_uint_t step_type;
987 duk_uint_fast32_t line;
988
989 if (cmd == DUK_DBG_CMD_STEPINTO) {
990 step_type = DUK_STEP_TYPE_INTO;
991 } else if (cmd == DUK_DBG_CMD_STEPOVER) {
992 step_type = DUK_STEP_TYPE_OVER;
993 } else {
994 DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
995 step_type = DUK_STEP_TYPE_OUT;
996 }
997
998 DUK_D(DUK_DPRINT("debug command stepinto/stepover/stepout: %d", (int) cmd));
999 line = duk_debug_curr_line(thr);
1000 if (line > 0) {
1001 heap->dbg_paused = 0;
1002 heap->dbg_step_type = step_type;
1003 heap->dbg_step_thread = thr;
1004 heap->dbg_step_csindex = thr->callstack_top - 1;
1005 heap->dbg_step_startline = line;
1006 heap->dbg_state_dirty = 1;
1007 } else {
1008 DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
1009 }
1010 duk_debug_write_reply(thr);
1011 duk_debug_write_eom(thr);
1012}
1013
1014DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
1015 duk_small_int_t i;
1016
1017 DUK_D(DUK_DPRINT("debug command listbreak"));
1018 duk_debug_write_reply(thr);
1019 for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
1020 duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
1021 duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
1022 }
1023 duk_debug_write_eom(thr);
1024}
1025
1026DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
1027 duk_context *ctx = (duk_context *) thr;
1028 duk_hstring *filename;
1029 duk_uint32_t linenumber;
1030 duk_small_int_t idx;
1031
1032 DUK_UNREF(heap);
1033
1034 filename = duk_debug_read_hstring(thr);
1035 linenumber = (duk_uint32_t) duk_debug_read_int(thr);
1036 DUK_D(DUK_DPRINT("debug command addbreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
1037 idx = duk_debug_add_breakpoint(thr, filename, linenumber);
1038 if (idx >= 0) {
1039 duk_debug_write_reply(thr);
1040 duk_debug_write_int(thr, (duk_int32_t) idx);
1041 duk_debug_write_eom(thr);
1042 } else {
1043 duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
1044 }
1045 duk_pop(ctx);
1046}
1047
1048DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
1049 duk_small_uint_t idx;
1050
1051 DUK_UNREF(heap);
1052
1053 DUK_D(DUK_DPRINT("debug command delbreak"));
1054 idx = (duk_small_uint_t) duk_debug_read_int(thr);
1055 if (duk_debug_remove_breakpoint(thr, idx)) {
1056 duk_debug_write_reply(thr);
1057 duk_debug_write_eom(thr);
1058 } else {
1059 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
1060 }
1061}
1062
1063DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
1064 duk_context *ctx = (duk_context *) thr;
1065 duk_hstring *str;
1066 duk_bool_t rc;
1067
1068 DUK_UNREF(heap);
1069 DUK_D(DUK_DPRINT("debug command getvar"));
1070
1071 str = duk_debug_read_hstring(thr); /* push to stack */
1072 DUK_ASSERT(str != NULL);
1073
1074 if (thr->callstack_top > 0) {
1075 rc = duk_js_getvar_activation(thr,
1076 thr->callstack + thr->callstack_top - 1,
1077 str,
1078 0);
1079 } else {
1080 /* No activation, no variable access. Could also pretend
1081 * we're in the global program context and read stuff off
1082 * the global object.
1083 */
1084 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
1085 rc = 0;
1086 }
1087
1088 duk_debug_write_reply(thr);
1089 if (rc) {
1090 duk_debug_write_int(thr, 1);
1091 duk_debug_write_tval(thr, duk_require_tval(ctx, -2));
1092 duk_pop_2(ctx);
1093 } else {
1094 duk_debug_write_int(thr, 0);
1095 duk_debug_write_unused(thr);
1096 }
1097 duk_pop(ctx);
1098 duk_debug_write_eom(thr);
1099}
1100
1101DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
1102 duk_context *ctx = (duk_context *) thr;
1103 duk_hstring *str;
1104 duk_tval *tv;
1105
1106 DUK_UNREF(heap);
1107 DUK_D(DUK_DPRINT("debug command putvar"));
1108
1109 str = duk_debug_read_hstring(thr); /* push to stack */
1110 DUK_ASSERT(str != NULL);
1111 duk_debug_read_tval(thr); /* push to stack */
1112 tv = duk_require_tval(ctx, -1);
1113
1114 if (thr->callstack_top > 0) {
1115 duk_js_putvar_activation(thr,
1116 thr->callstack + thr->callstack_top - 1,
1117 str,
1118 tv,
1119 0);
1120 } else {
1121 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
1122 }
1123 duk_pop_2(ctx);
1124
1125 /* XXX: Current putvar implementation doesn't have a success flag,
1126 * add one and send to debug client?
1127 */
1128 duk_debug_write_reply(thr);
1129 duk_debug_write_eom(thr);
1130}
1131
1132DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
1133 duk_context *ctx = (duk_context *) thr;
1134 duk_hthread *curr_thr = thr;
1135 duk_activation *curr_act;
1136 duk_uint_fast32_t pc;
1137 duk_uint_fast32_t line;
1138 duk_size_t i;
1139
1140 DUK_UNREF(heap);
1141
1142 duk_debug_write_reply(thr);
1143 while (curr_thr != NULL) {
1144 i = curr_thr->callstack_top;
1145 while (i > 0) {
1146 i--;
1147 curr_act = curr_thr->callstack + i;
1148
1149 /* PC/line semantics here are:
1150 * - For callstack top we're conceptually between two
1151 * opcodes and current PC indicates next line to
1152 * execute, so report that (matches Status).
1153 * - For other activations we're conceptually still
1154 * executing the instruction at PC-1, so report that
1155 * (matches error stacktrace behavior).
1156 * - See: https://github.com/svaarala/duktape/issues/281
1157 */
1158
1159 /* XXX: optimize to use direct reads, i.e. avoid
1160 * value stack operations.
1161 */
1162 duk_push_tval(ctx, &curr_act->tv_func);
1163 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
1164 duk_safe_to_string(ctx, -1);
1165 duk_debug_write_hstring(thr, duk_get_hstring(ctx, -1));
1166 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
1167 duk_safe_to_string(ctx, -1);
1168 duk_debug_write_hstring(thr, duk_get_hstring(ctx, -1));
1169 pc = duk_hthread_get_act_curr_pc(thr, curr_act);
1170 if (i != curr_thr->callstack_top - 1 && pc > 0) {
1171 pc--;
1172 }
1173 line = duk_hobject_pc2line_query(ctx, -3, pc);
1174 duk_debug_write_uint(thr, (duk_uint32_t) line);
1175 duk_debug_write_uint(thr, (duk_uint32_t) pc);
1176 duk_pop_3(ctx);
1177 }
1178 curr_thr = curr_thr->resumer;
1179 }
1180 duk_debug_write_eom(thr);
1181}
1182
1183DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
1184 duk_context *ctx = (duk_context *) thr;
1185 duk_activation *curr_act;
1186 duk_hstring *varname;
1187
1188 DUK_UNREF(heap);
1189
1190 duk_debug_write_reply(thr);
1191 if (thr->callstack_top == 0) {
1192 goto callstack_empty;
1193 }
1194 curr_act = thr->callstack + thr->callstack_top - 1;
1195
1196 /* XXX: several nice-to-have improvements here:
1197 * - Use direct reads avoiding value stack operations
1198 * - Avoid triggering getters, indicate getter values to debug client
1199 * - If side effects are possible, add error catching
1200 */
1201
1202 duk_push_tval(ctx, &curr_act->tv_func);
1203 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP);
1204 if (duk_is_object(ctx, -1)) {
1205 duk_enum(ctx, -1, 0 /*enum_flags*/);
1206 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
1207 varname = duk_get_hstring(ctx, -1);
1208 DUK_ASSERT(varname != NULL);
1209
1210 duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
1211 /* [ ... func varmap enum key value this ] */
1212 duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
1213 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
1214 duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
1215 }
1216 duk_pop(ctx);
1217 } else {
1218 DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
1219 }
1220 duk_pop_2(ctx);
1221
1222 callstack_empty:
1223 duk_debug_write_eom(thr);
1224}
1225
1226DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
1227 duk_context *ctx = (duk_context *) thr;
1228
1229 duk_small_uint_t call_flags;
1230 duk_int_t call_ret;
1231 duk_small_int_t eval_err;
1232#if defined(DUK_USE_ASSERTIONS)
1233 duk_idx_t entry_top;
1234#endif
1235
1236 DUK_UNREF(heap);
1237
1238 DUK_D(DUK_DPRINT("debug command eval"));
1239
1240 /* The eval code must be executed within the current (topmost)
1241 * activation. For now, use global object eval() function, with
1242 * the eval considered a 'direct call to eval'.
1243 */
1244
1245#if defined(DUK_USE_ASSERTIONS)
1246 entry_top = duk_get_top(ctx);
1247#endif
1248
1249 duk_push_c_function(ctx, duk_bi_global_object_eval, 1 /*nargs*/);
1250 duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
1251 (void) duk_debug_read_hstring(thr);
1252
1253 /* [ ... eval "eval" eval_input ] */
1254
1255 call_flags = DUK_CALL_FLAG_PROTECTED;
1256 if (thr->callstack_top >= 1) {
1257 duk_activation *act;
1258 duk_hobject *fun;
1259
1260 act = thr->callstack + thr->callstack_top - 1;
1261 fun = DUK_ACT_GET_FUNC(act);
1262 if (fun && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
1263 /* Direct eval requires that there's a current
1264 * activation and it is an Ecmascript function.
1265 * When Eval is executed from e.g. cooperate API
1266 * call we'll need to an indirect eval instead.
1267 */
1268 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
1269 }
1270 }
1271
1272 call_ret = duk_handle_call(thr, 1 /*num_stack_args*/, call_flags);
1273
1274 if (call_ret == DUK_EXEC_SUCCESS) {
1275 eval_err = 0;
1276 /* Use result value as is. */
1277 } else {
1278 /* For errors a string coerced result is most informative
1279 * right now, as the debug client doesn't have the capability
1280 * to traverse the error object.
1281 */
1282 eval_err = 1;
1283 duk_safe_to_string(ctx, -1);
1284 }
1285
1286 /* [ ... result ] */
1287
1288 duk_debug_write_reply(thr);
1289 duk_debug_write_int(thr, (duk_int32_t) eval_err);
1290 duk_debug_write_tval(thr, duk_require_tval(ctx, -1));
1291 duk_debug_write_eom(thr);
1292 duk_pop(ctx);
1293
1294 DUK_ASSERT(duk_get_top(ctx) == entry_top);
1295}
1296
1297DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
1298 DUK_UNREF(heap);
1299 DUK_D(DUK_DPRINT("debug command detach"));
1300
1301 duk_debug_write_reply(thr);
1302 duk_debug_write_eom(thr);
1303
1304 DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
1305 DUK__SET_CONN_BROKEN(thr);
1306}
1307
1308#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
1309DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
1310 DUK_UNREF(heap);
1311
1312 duk_debug_write_heapptr(thr, hdr);
1313 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
1314 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
1315#if defined(DUK_USE_REFERENCE_COUNTING)
1316 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
1317#else
1318 duk_debug_write_int(thr, (duk_int32_t) -1);
1319#endif
1320
1321 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
1322 case DUK_HTYPE_STRING: {
1323 duk_hstring *h = (duk_hstring *) hdr;
1324
1325 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
1326 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
1327 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
1328 duk_debug_write_hstring(thr, h);
1329 break;
1330 }
1331 case DUK_HTYPE_OBJECT: {
1332 duk_hobject *h = (duk_hobject *) hdr;
1333 duk_hstring *k;
1334 duk_uint_fast32_t i;
1335
1336 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
1337 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
1338 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
1339 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
1340 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
1341 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
1342
1343 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
1344 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
1345 k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
1346 duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
1347 if (k == NULL) {
1348 duk_debug_write_int(thr, 0); /* isAccessor */
1349 duk_debug_write_unused(thr);
1350 continue;
1351 }
1352 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
1353 duk_debug_write_int(thr, 1); /* isAccessor */
1354 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
1355 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
1356 } else {
1357 duk_debug_write_int(thr, 0); /* isAccessor */
1358
1359 duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
1360 }
1361 }
1362
1363 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
1364 /* Note: array dump will include elements beyond
1365 * 'length'.
1366 */
1367 duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
1368 }
1369 break;
1370 }
1371 case DUK_HTYPE_BUFFER: {
1372 duk_hbuffer *h = (duk_hbuffer *) hdr;
1373
1374 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
1375 duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
1376 break;
1377 }
1378 default: {
1379 DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
1380 }
1381 }
1382}
1383
1384DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
1385 duk_heaphdr *hdr;
1386
1387 hdr = heap->heap_allocated;
1388 while (hdr != NULL) {
1389 duk__debug_dump_heaphdr(thr, heap, hdr);
1390 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
1391 }
1392}
1393
1394#if defined(DUK_USE_STRTAB_CHAIN)
1395DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) {
1396 duk_uint_fast32_t i, j;
1397 duk_strtab_entry *e;
1398#if defined(DUK_USE_HEAPPTR16)
1399 duk_uint16_t *lst;
1400#else
1401 duk_hstring **lst;
1402#endif
1403 duk_hstring *h;
1404
1405 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
1406 e = heap->strtable + i;
1407 if (e->listlen > 0) {
1408#if defined(DUK_USE_HEAPPTR16)
1409 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
1410#else
1411 lst = e->u.strlist;
1412#endif
1413 DUK_ASSERT(lst != NULL);
1414
1415 for (j = 0; j < e->listlen; j++) {
1416#if defined(DUK_USE_HEAPPTR16)
1417 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
1418#else
1419 h = lst[j];
1420#endif
1421 if (h != NULL) {
1422 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
1423 }
1424 }
1425 } else {
1426#if defined(DUK_USE_HEAPPTR16)
1427 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
1428#else
1429 h = e->u.str;
1430#endif
1431 if (h != NULL) {
1432 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
1433 }
1434 }
1435 }
1436}
1437#endif /* DUK_USE_STRTAB_CHAIN */
1438
1439#if defined(DUK_USE_STRTAB_PROBE)
1440DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) {
1441 duk_uint32_t i;
1442 duk_hstring *h;
1443
1444 for (i = 0; i < heap->st_size; i++) {
1445#if defined(DUK_USE_HEAPPTR16)
1446 h = DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
1447#else
1448 h = heap->strtable[i];
1449#endif
1450 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
1451 continue;
1452 }
1453
1454 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
1455 }
1456}
1457#endif /* DUK_USE_STRTAB_PROBE */
1458
1459DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
1460 DUK_D(DUK_DPRINT("debug command dumpheap"));
1461
1462 duk_debug_write_reply(thr);
1463 duk__debug_dump_heap_allocated(thr, heap);
1464#if defined(DUK_USE_STRTAB_CHAIN)
1465 duk__debug_dump_strtab_chain(thr, heap);
1466#endif
1467#if defined(DUK_USE_STRTAB_PROBE)
1468 duk__debug_dump_strtab_probe(thr, heap);
1469#endif
1470 duk_debug_write_eom(thr);
1471}
1472#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
1473
1474DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
1475 duk_activation *act;
1476 duk_hcompiledfunction *fun;
1477 duk_size_t i, n;
1478 duk_tval *tv;
1479 duk_hobject **fn;
1480
1481 DUK_UNREF(heap);
1482
1483 DUK_D(DUK_DPRINT("debug command getbytecode"));
1484
1485 duk_debug_write_reply(thr);
1486 if (thr->callstack_top == 0) {
1487 fun = NULL;
1488 } else {
1489 act = thr->callstack + thr->callstack_top - 1;
1490 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
1491 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)) {
1492 fun = NULL;
1493 }
1494 }
1495 DUK_ASSERT(fun == NULL || DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun));
1496
1497 if (fun) {
1498 n = DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap, fun);
1499 duk_debug_write_int(thr, (int) n);
1500 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, fun);
1501 for (i = 0; i < n; i++) {
1502 duk_debug_write_tval(thr, tv);
1503 tv++;
1504 }
1505
1506 n = DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap, fun);
1507 duk_debug_write_int(thr, (int) n);
1508 fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, fun);
1509 for (i = 0; i < n; i++) {
1510 duk_debug_write_hobject(thr, *fn);
1511 fn++;
1512 }
1513
1514 duk_debug_write_string(thr,
1515 (const char *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap, fun),
1516 (duk_size_t) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap, fun));
1517 } else {
1518 duk_debug_write_int(thr, 0);
1519 duk_debug_write_int(thr, 0);
1520 duk_debug_write_cstring(thr, "");
1521 }
1522 duk_debug_write_eom(thr);
1523}
1524
1525DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
1526 duk_context *ctx = (duk_context *) thr;
1527 duk_heap *heap;
1528 duk_uint8_t x;
1529 duk_int32_t cmd;
1530
1531 DUK_ASSERT(thr != NULL);
1532 heap = thr->heap;
1533 DUK_ASSERT(heap != NULL);
1534 DUK_UNREF(ctx);
1535
1536 x = duk_debug_read_byte(thr);
1537 switch (x) {
1538 case DUK_DBG_MARKER_REQUEST: {
1539 cmd = duk_debug_read_int(thr);
1540 switch (cmd) {
1541 case DUK_DBG_CMD_BASICINFO: {
1542 duk__debug_handle_basic_info(thr, heap);
1543 break;
1544 }
1545 case DUK_DBG_CMD_TRIGGERSTATUS: {
1546 duk__debug_handle_trigger_status(thr, heap);
1547 break;
1548 }
1549 case DUK_DBG_CMD_PAUSE: {
1550 duk__debug_handle_pause(thr, heap);
1551 break;
1552 }
1553 case DUK_DBG_CMD_RESUME: {
1554 duk__debug_handle_resume(thr, heap);
1555 break;
1556 }
1557 case DUK_DBG_CMD_STEPINTO:
1558 case DUK_DBG_CMD_STEPOVER:
1559 case DUK_DBG_CMD_STEPOUT: {
1560 duk__debug_handle_step(thr, heap, cmd);
1561 break;
1562 }
1563 case DUK_DBG_CMD_LISTBREAK: {
1564 duk__debug_handle_list_break(thr, heap);
1565 break;
1566 }
1567 case DUK_DBG_CMD_ADDBREAK: {
1568 duk__debug_handle_add_break(thr, heap);
1569 break;
1570 }
1571 case DUK_DBG_CMD_DELBREAK: {
1572 duk__debug_handle_del_break(thr, heap);
1573 break;
1574 }
1575 case DUK_DBG_CMD_GETVAR: {
1576 duk__debug_handle_get_var(thr, heap);
1577 break;
1578 }
1579 case DUK_DBG_CMD_PUTVAR: {
1580 duk__debug_handle_put_var(thr, heap);
1581 break;
1582 }
1583 case DUK_DBG_CMD_GETCALLSTACK: {
1584 duk__debug_handle_get_call_stack(thr, heap);
1585 break;
1586 }
1587 case DUK_DBG_CMD_GETLOCALS: {
1588 duk__debug_handle_get_locals(thr, heap);
1589 break;
1590 }
1591 case DUK_DBG_CMD_EVAL: {
1592 duk__debug_handle_eval(thr, heap);
1593 break;
1594 }
1595 case DUK_DBG_CMD_DETACH: {
1596 duk__debug_handle_detach(thr, heap);
1597 break;
1598 }
1599#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
1600 case DUK_DBG_CMD_DUMPHEAP: {
1601 duk__debug_handle_dump_heap(thr, heap);
1602 break;
1603 }
1604#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
1605 case DUK_DBG_CMD_GETBYTECODE: {
1606 duk__debug_handle_get_bytecode(thr, heap);
1607 break;
1608 }
1609 default: {
1610 DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
1611 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
1612 }
1613 } /* switch cmd */
1614 break;
1615 }
1616 case DUK_DBG_MARKER_REPLY: {
1617 DUK_D(DUK_DPRINT("debug reply, skipping"));
1618 break;
1619 }
1620 case DUK_DBG_MARKER_ERROR: {
1621 DUK_D(DUK_DPRINT("debug error, skipping"));
1622 break;
1623 }
1624 case DUK_DBG_MARKER_NOTIFY: {
1625 DUK_D(DUK_DPRINT("debug notify, skipping"));
1626 break;
1627 }
1628 default: {
1629 DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
1630 goto fail;
1631 }
1632 } /* switch initial byte */
1633
1634 duk__debug_skip_to_eom(thr);
1635 return;
1636
1637 fail:
1638 DUK__SET_CONN_BROKEN(thr);
1639 return;
1640}
1641
1642DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
1643 duk_context *ctx = (duk_context *) thr;
1644#if defined(DUK_USE_ASSERTIONS)
1645 duk_idx_t entry_top;
1646#endif
1647 duk_bool_t retval = 0;
1648
1649 DUK_ASSERT(thr != NULL);
1650 DUK_UNREF(ctx);
1651#if defined(DUK_USE_ASSERTIONS)
1652 entry_top = duk_get_top(ctx);
1653#endif
1654
1655 DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
1656
1657 for (;;) {
1658 /* Process messages until we're no longer paused or we peek
1659 * and see there's nothing to read right now.
1660 */
1661 DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
1662
1663 if (thr->heap->dbg_read_cb == NULL) {
1664 DUK_D(DUK_DPRINT("debug connection broken, stop processing messages"));
1665 break;
1666 } else if (!thr->heap->dbg_paused || no_block) {
1667 if (!duk_debug_read_peek(thr)) {
1668 DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing"));
1669 break;
1670 }
1671 DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
1672 } else {
1673 DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
1674 }
1675
1676 duk__debug_process_message(thr);
1677 if (thr->heap->dbg_state_dirty) {
1678 /* Executed something that may have affected status,
1679 * resend.
1680 */
1681 duk_debug_send_status(thr);
1682 thr->heap->dbg_state_dirty = 0;
1683 }
1684 retval = 1; /* processed one or more messages */
1685 }
1686
1687 /* As an initial implementation, read flush after exiting the message
1688 * loop.
1689 */
1690 duk_debug_read_flush(thr);
1691
1692 DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
1693
1694#if defined(DUK_USE_ASSERTIONS)
1695 /* Easy to get wrong, so assert for it. */
1696 DUK_ASSERT(entry_top == duk_get_top(ctx));
1697#endif
1698
1699 return retval;
1700}
1701
1702/*
1703 * Breakpoint management
1704 */
1705
1706DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
1707 duk_heap *heap;
1708 duk_breakpoint *b;
1709
1710 /* Caller must trigger recomputation of active breakpoint list. To
1711 * ensure stale values are not used if that doesn't happen, clear the
1712 * active breakpoint list here.
1713 */
1714
1715 DUK_ASSERT(thr != NULL);
1716 DUK_ASSERT(filename != NULL);
1717 heap = thr->heap;
1718 DUK_ASSERT(heap != NULL);
1719
1720 if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
1721 DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
1722 (duk_heaphdr *) filename, (long) line));
1723 return -1;
1724 }
1725 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
1726 b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
1727 b->filename = filename;
1728 b->line = line;
1729 DUK_HSTRING_INCREF(thr, filename);
1730
1731 return heap->dbg_breakpoint_count - 1; /* index */
1732}
1733
1734DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
1735 duk_heap *heap;
1736 duk_hstring *h;
1737 duk_breakpoint *b;
1738 duk_size_t move_size;
1739
1740 /* Caller must trigger recomputation of active breakpoint list. To
1741 * ensure stale values are not used if that doesn't happen, clear the
1742 * active breakpoint list here.
1743 */
1744
1745 DUK_ASSERT(thr != NULL);
1746 heap = thr->heap;
1747 DUK_ASSERT(heap != NULL);
1748 DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
1749
1750 if (breakpoint_index >= heap->dbg_breakpoint_count) {
1751 DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
1752 return 0;
1753 }
1754 b = heap->dbg_breakpoints + breakpoint_index;
1755
1756 h = b->filename;
1757 DUK_ASSERT(h != NULL);
1758
1759 move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
1760 if (move_size > 0) {
1761 DUK_MEMMOVE((void *) b,
1762 (void *) (b + 1),
1763 move_size);
1764 }
1765 heap->dbg_breakpoint_count--;
1766 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
1767
1768 DUK_HSTRING_DECREF(thr, h); /* side effects */
1769
1770 /* Breakpoint entries above the used area are left as garbage. */
1771
1772 return 1;
1773}
1774
1775#undef DUK__SET_CONN_BROKEN
1776
1777#else /* DUK_USE_DEBUGGER_SUPPORT */
1778
1779/* No debugger support. */
1780
1781#endif /* DUK_USE_DEBUGGER_SUPPORT */