2 * Debugging related API calls
5 #include "duk_internal.h"
7 DUK_EXTERNAL
void duk_push_context_dump(duk_context
*ctx
) {
11 DUK_ASSERT_CTX_VALID(ctx
);
13 /* We don't duk_require_stack() here now, but rely on the caller having
17 top
= duk_get_top(ctx
);
19 for (idx
= 0; idx
< top
; idx
++) {
21 duk_put_prop_index(ctx
, -2, idx
);
24 /* XXX: conversion errors should not propagate outwards.
25 * Perhaps values need to be coerced individually?
27 duk_bi_json_stringify_helper(ctx
,
28 duk_get_top_index(ctx
), /*idx_value*/
29 DUK_INVALID_INDEX
, /*idx_replacer*/
30 DUK_INVALID_INDEX
, /*idx_space*/
31 DUK_JSON_FLAG_EXT_CUSTOM
|
32 DUK_JSON_FLAG_ASCII_ONLY
|
33 DUK_JSON_FLAG_AVOID_KEY_QUOTES
/*flags*/);
35 duk_push_sprintf(ctx
, "ctx: top=%ld, stack=%s", (long) top
, (const char *) duk_safe_to_string(ctx
, -1));
36 duk_replace(ctx
, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
38 DUK_ASSERT(duk_is_string(ctx
, -1));
41 #if defined(DUK_USE_DEBUGGER_SUPPORT)
43 DUK_EXTERNAL
void duk_debugger_attach_custom(duk_context
*ctx
,
44 duk_debug_read_function read_cb
,
45 duk_debug_write_function write_cb
,
46 duk_debug_peek_function peek_cb
,
47 duk_debug_read_flush_function read_flush_cb
,
48 duk_debug_write_flush_function write_flush_cb
,
49 duk_debug_request_function request_cb
,
50 duk_debug_detached_function detached_cb
,
52 duk_hthread
*thr
= (duk_hthread
*) ctx
;
57 /* XXX: should there be an error or an automatic detach if
61 DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
63 DUK_ASSERT_CTX_VALID(ctx
);
64 DUK_ASSERT(read_cb
!= NULL
);
65 DUK_ASSERT(write_cb
!= NULL
);
66 /* Other callbacks are optional. */
69 heap
->dbg_read_cb
= read_cb
;
70 heap
->dbg_write_cb
= write_cb
;
71 heap
->dbg_peek_cb
= peek_cb
;
72 heap
->dbg_read_flush_cb
= read_flush_cb
;
73 heap
->dbg_write_flush_cb
= write_flush_cb
;
74 heap
->dbg_request_cb
= request_cb
;
75 heap
->dbg_detached_cb
= detached_cb
;
76 heap
->dbg_udata
= udata
;
77 heap
->dbg_have_next_byte
= 0;
79 /* Start in paused state. */
80 heap
->dbg_processing
= 0;
82 heap
->dbg_state_dirty
= 1;
83 heap
->dbg_force_restart
= 0;
84 heap
->dbg_step_type
= 0;
85 heap
->dbg_step_thread
= NULL
;
86 heap
->dbg_step_csindex
= 0;
87 heap
->dbg_step_startline
= 0;
88 heap
->dbg_exec_counter
= 0;
89 heap
->dbg_last_counter
= 0;
90 heap
->dbg_last_time
= 0.0;
92 /* Send version identification and flush right afterwards. Note that
93 * we must write raw, unframed bytes here.
95 duk_push_sprintf(ctx
, "%ld %ld %s %s\n",
96 (long) DUK_DEBUG_PROTOCOL_VERSION
,
98 (const char *) DUK_GIT_DESCRIBE
,
99 (const char *) DUK_USE_TARGET_INFO
);
100 str
= duk_get_lstring(ctx
, -1, &len
);
101 DUK_ASSERT(str
!= NULL
);
102 duk_debug_write_bytes(thr
, (const duk_uint8_t
*) str
, len
);
103 duk_debug_write_flush(thr
);
107 DUK_EXTERNAL
void duk_debugger_detach(duk_context
*ctx
) {
110 DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
112 DUK_ASSERT_CTX_VALID(ctx
);
113 thr
= (duk_hthread
*) ctx
;
114 DUK_ASSERT(thr
!= NULL
);
115 DUK_ASSERT(thr
->heap
!= NULL
);
117 /* Can be called multiple times with no harm. */
118 duk_debug_do_detach(thr
->heap
);
121 DUK_EXTERNAL
void duk_debugger_cooperate(duk_context
*ctx
) {
123 duk_bool_t processed_messages
;
125 DUK_ASSERT_CTX_VALID(ctx
);
126 thr
= (duk_hthread
*) ctx
;
127 DUK_ASSERT(thr
!= NULL
);
128 DUK_ASSERT(thr
->heap
!= NULL
);
130 if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr
->heap
)) {
133 if (thr
->callstack_top
> 0 || thr
->heap
->dbg_processing
) {
134 /* Calling duk_debugger_cooperate() while Duktape is being
135 * called into is not supported. This is not a 100% check
136 * but prevents any damage in most cases.
141 processed_messages
= duk_debug_process_messages(thr
, 1 /*no_block*/);
142 DUK_UNREF(processed_messages
);
145 DUK_EXTERNAL duk_bool_t
duk_debugger_notify(duk_context
*ctx
, duk_idx_t nvalues
) {
151 DUK_ASSERT_CTX_VALID(ctx
);
152 thr
= (duk_hthread
*) ctx
;
153 DUK_ASSERT(thr
!= NULL
);
154 DUK_ASSERT(thr
->heap
!= NULL
);
156 DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues
));
158 top
= duk_get_top(ctx
);
160 DUK_ERROR_API(thr
, "not enough stack values for notify");
161 return ret
; /* unreachable */
163 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr
->heap
)) {
164 duk_debug_write_notify(thr
, DUK_DBG_CMD_APPNOTIFY
);
165 for (idx
= top
- nvalues
; idx
< top
; idx
++) {
166 duk_tval
*tv
= DUK_GET_TVAL_POSIDX(ctx
, idx
);
167 duk_debug_write_tval(thr
, tv
);
169 duk_debug_write_eom(thr
);
171 /* Return non-zero (true) if we have a good reason to believe
172 * the notify was delivered; if we're still attached at least
173 * a transport error was not indicated by the transport write
174 * callback. This is not a 100% guarantee of course.
176 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr
->heap
)) {
180 duk_pop_n(ctx
, nvalues
);
184 DUK_EXTERNAL
void duk_debugger_pause(duk_context
*ctx
) {
187 DUK_ASSERT_CTX_VALID(ctx
);
188 thr
= (duk_hthread
*) ctx
;
189 DUK_ASSERT(thr
!= NULL
);
190 DUK_ASSERT(thr
->heap
!= NULL
);
192 DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
194 /* Treat like a debugger statement: ignore when not attached. */
195 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr
->heap
)) {
196 DUK_HEAP_SET_PAUSED(thr
->heap
);
198 /* Pause on the next opcode executed. This is always safe to do even
199 * inside the debugger message loop: the interrupt counter will be reset
200 * to its proper value when the message loop exits.
202 thr
->interrupt_init
= 1;
203 thr
->interrupt_counter
= 0;
207 #else /* DUK_USE_DEBUGGER_SUPPORT */
209 DUK_EXTERNAL
void duk_debugger_attach_custom(duk_context
*ctx
,
210 duk_debug_read_function read_cb
,
211 duk_debug_write_function write_cb
,
212 duk_debug_peek_function peek_cb
,
213 duk_debug_read_flush_function read_flush_cb
,
214 duk_debug_write_flush_function write_flush_cb
,
215 duk_debug_request_function request_cb
,
216 duk_debug_detached_function detached_cb
,
218 DUK_ASSERT_CTX_VALID(ctx
);
222 DUK_UNREF(read_flush_cb
);
223 DUK_UNREF(write_flush_cb
);
224 DUK_UNREF(request_cb
);
225 DUK_UNREF(detached_cb
);
227 DUK_ERROR_API((duk_hthread
*) ctx
, "no debugger support");
230 DUK_EXTERNAL
void duk_debugger_detach(duk_context
*ctx
) {
231 DUK_ASSERT_CTX_VALID(ctx
);
232 DUK_ERROR_API((duk_hthread
*) ctx
, "no debugger support");
235 DUK_EXTERNAL
void duk_debugger_cooperate(duk_context
*ctx
) {
237 DUK_ASSERT_CTX_VALID(ctx
);
241 DUK_EXTERNAL duk_bool_t
duk_debugger_notify(duk_context
*ctx
, duk_idx_t nvalues
) {
244 DUK_ASSERT_CTX_VALID(ctx
);
246 top
= duk_get_top(ctx
);
248 DUK_ERROR_API((duk_hthread
*) ctx
, "not enough stack values for notify");
249 return 0; /* unreachable */
252 /* No debugger support, just pop values. */
253 duk_pop_n(ctx
, nvalues
);
257 DUK_EXTERNAL
void duk_debugger_pause(duk_context
*ctx
) {
258 /* Treat like debugger statement: nop */
259 DUK_ASSERT_CTX_VALID(ctx
);
263 #endif /* DUK_USE_DEBUGGER_SUPPORT */