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