1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "debugger.h"
17#include "jcontext.h"
18#include "jerryscript.h"
19
20/**
21 * Checks whether the debugger is connected.
22 *
23 * @return true - if the debugger is connected
24 * false - otherwise
25 */
26bool
27jerry_debugger_is_connected (void)
28{
29#if ENABLED (JERRY_DEBUGGER)
30 return JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED;
31#else /* !ENABLED (JERRY_DEBUGGER) */
32 return false;
33#endif /* ENABLED (JERRY_DEBUGGER) */
34} /* jerry_debugger_is_connected */
35
36/**
37 * Stop execution at the next available breakpoint.
38 */
39void
40jerry_debugger_stop (void)
41{
42#if ENABLED (JERRY_DEBUGGER)
43 if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
44 && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
45 {
46 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
47 JERRY_CONTEXT (debugger_stop_context) = NULL;
48 }
49#endif /* ENABLED (JERRY_DEBUGGER) */
50} /* jerry_debugger_stop */
51
52/**
53 * Continue execution.
54 */
55void
56jerry_debugger_continue (void)
57{
58#if ENABLED (JERRY_DEBUGGER)
59 if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
60 && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
61 {
62 JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP);
63 JERRY_CONTEXT (debugger_stop_context) = NULL;
64 }
65#endif /* ENABLED (JERRY_DEBUGGER) */
66} /* jerry_debugger_continue */
67
68/**
69 * Sets whether the engine should stop at breakpoints.
70 */
71void
72jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint) /**< enable/disable stop at breakpoint */
73{
74#if ENABLED (JERRY_DEBUGGER)
75 if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED
76 && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
77 {
78 if (enable_stop_at_breakpoint)
79 {
80 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE);
81 }
82 else
83 {
84 JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE);
85 }
86 }
87#else /* !ENABLED (JERRY_DEBUGGER) */
88 JERRY_UNUSED (enable_stop_at_breakpoint);
89#endif /* ENABLED (JERRY_DEBUGGER) */
90} /* jerry_debugger_stop_at_breakpoint */
91
92/**
93 * Sets whether the engine should wait and run a source.
94 *
95 * @return enum JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED - if the source is not received
96 * JERRY_DEBUGGER_SOURCE_RECEIVED - if a source code received
97 * JERRY_DEBUGGER_SOURCE_END - the end of the source codes
98 * JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED - the end of the context
99 */
100jerry_debugger_wait_for_source_status_t
101jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t callback_p, /**< callback function */
102 void *user_p, /**< user pointer passed to the callback */
103 jerry_value_t *return_value) /**< [out] parse and run return value */
104{
105 *return_value = jerry_create_undefined ();
106
107#if ENABLED (JERRY_DEBUGGER)
108 if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
109 && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
110 {
111 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE);
112 jerry_debugger_uint8_data_t *client_source_data_p = NULL;
113 jerry_debugger_wait_for_source_status_t ret_type = JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
114
115 /* Notify the client about that the engine is waiting for a source. */
116 jerry_debugger_send_type (JERRY_DEBUGGER_WAIT_FOR_SOURCE);
117
118 while (true)
119 {
120 if (jerry_debugger_receive (&client_source_data_p))
121 {
122 if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED))
123 {
124 break;
125 }
126
127 /* Stop executing the current context. */
128 if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONTEXT_RESET_MODE))
129 {
130 ret_type = JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED;
131 JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE);
132 break;
133 }
134
135 /* Stop waiting for a new source file. */
136 if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_NO_SOURCE))
137 {
138 ret_type = JERRY_DEBUGGER_SOURCE_END;
139 JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE);
140 break;
141 }
142
143 /* The source arrived. */
144 if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
145 {
146 JERRY_ASSERT (client_source_data_p != NULL);
147
148 jerry_char_t *resource_name_p = (jerry_char_t *) (client_source_data_p + 1);
149 size_t resource_name_size = strlen ((const char *) resource_name_p);
150
151 *return_value = callback_p (resource_name_p,
152 resource_name_size,
153 resource_name_p + resource_name_size + 1,
154 client_source_data_p->uint8_size - resource_name_size - 1,
155 user_p);
156
157 ret_type = JERRY_DEBUGGER_SOURCE_RECEIVED;
158 break;
159 }
160 }
161
162 jerry_debugger_transport_sleep ();
163 }
164
165 JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
166 || !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED));
167
168 if (client_source_data_p != NULL)
169 {
170 /* The data may partly arrived. */
171 jmem_heap_free_block (client_source_data_p,
172 client_source_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
173 }
174
175 return ret_type;
176 }
177
178 return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
179#else /* !ENABLED (JERRY_DEBUGGER) */
180 JERRY_UNUSED (callback_p);
181 JERRY_UNUSED (user_p);
182
183 return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
184#endif /* ENABLED (JERRY_DEBUGGER) */
185} /* jerry_debugger_wait_for_client_source */
186
187/**
188 * Send the output of the program to the debugger client.
189 * Currently only sends print output.
190 */
191void
192jerry_debugger_send_output (const jerry_char_t *buffer, /**< buffer */
193 jerry_size_t str_size) /**< string size */
194{
195#if ENABLED (JERRY_DEBUGGER)
196 if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
197 {
198 jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT,
199 JERRY_DEBUGGER_OUTPUT_OK,
200 (const uint8_t *) buffer,
201 sizeof (uint8_t) * str_size);
202 }
203#else /* !ENABLED (JERRY_DEBUGGER) */
204 JERRY_UNUSED (buffer);
205 JERRY_UNUSED (str_size);
206#endif /* ENABLED (JERRY_DEBUGGER) */
207} /* jerry_debugger_send_output */
208
209/**
210 * Send the log of the program to the debugger client.
211 */
212void
213jerry_debugger_send_log (jerry_log_level_t level, /**< level of the diagnostics message */
214 const jerry_char_t *buffer, /**< buffer */
215 jerry_size_t str_size) /**< string size */
216{
217#if ENABLED (JERRY_DEBUGGER)
218 if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
219 {
220 jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT,
221 (uint8_t) (level + 2),
222 (const uint8_t *) buffer,
223 sizeof (uint8_t) * str_size);
224 }
225#else /* !ENABLED (JERRY_DEBUGGER) */
226 JERRY_UNUSED (level);
227 JERRY_UNUSED (buffer);
228 JERRY_UNUSED (str_size);
229#endif /* ENABLED (JERRY_DEBUGGER) */
230} /* jerry_debugger_send_log */
231