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 #if ENABLED (JERRY_DEBUGGER)
21
22 /**
23 * Minimum number of bytes transmitted or received.
24 */
25 #define JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE 64
26
27 /**
28 * Sleep time in milliseconds between each jerry_debugger_receive call
29 */
30 #define JERRY_DEBUGGER_TRANSPORT_TIMEOUT 10
31
32 /**
33 * Add a new transport layer.
34 */
35 void
jerry_debugger_transport_add(jerry_debugger_transport_header_t * header_p,size_t send_message_header_size,size_t max_send_message_size,size_t receive_message_header_size,size_t max_receive_message_size)36 jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p, /**< transport implementation */
37 size_t send_message_header_size, /**< header bytes reserved for outgoing messages */
38 size_t max_send_message_size, /**< maximum number of bytes transmitted in a message */
39 size_t receive_message_header_size, /**< header bytes reserved for incoming messages */
40 size_t max_receive_message_size) /**< maximum number of bytes received in a message */
41 {
42 JERRY_ASSERT (max_send_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE
43 && max_receive_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE);
44
45 header_p->next_p = JERRY_CONTEXT (debugger_transport_header_p);
46 JERRY_CONTEXT (debugger_transport_header_p) = header_p;
47
48 uint8_t *payload_p;
49 size_t max_send_size;
50 size_t max_receive_size;
51
52 if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
53 {
54 payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
55 max_send_size = JERRY_CONTEXT (debugger_max_send_size);
56 max_receive_size = JERRY_CONTEXT (debugger_max_receive_size);
57 }
58 else
59 {
60 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED);
61 payload_p = JERRY_CONTEXT (debugger_send_buffer);
62 max_send_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
63 max_receive_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
64 }
65
66 JERRY_ASSERT (max_send_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + send_message_header_size);
67 JERRY_ASSERT (max_receive_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + receive_message_header_size);
68
69 JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p + send_message_header_size;
70
71 max_send_size = max_send_size - send_message_header_size;
72 max_receive_size = max_receive_size - receive_message_header_size;
73
74 if (max_send_size > max_send_message_size)
75 {
76 max_send_size = max_send_message_size;
77 }
78
79 if (max_receive_size > max_receive_message_size)
80 {
81 max_receive_size = max_receive_message_size;
82 }
83
84 JERRY_CONTEXT (debugger_max_send_size) = (uint8_t) max_send_size;
85 JERRY_CONTEXT (debugger_max_receive_size) = (uint8_t) max_receive_size;
86 } /* jerry_debugger_transport_add */
87
88 /**
89 * Starts the communication to the debugger client.
90 * Must be called after the connection is successfully established.
91 */
92 void
jerry_debugger_transport_start(void)93 jerry_debugger_transport_start (void)
94 {
95 #ifdef ACE_DEBUGGER_CUSTOM
96 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_TRANSPORT_STARTED);
97 #endif
98 JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
99
100 if (jerry_debugger_send_configuration (JERRY_CONTEXT (debugger_max_receive_size)))
101 {
102 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
103 JERRY_CONTEXT (debugger_stop_context) = NULL;
104 }
105 } /* jerry_debugger_transport_start */
106
107 /**
108 * Returns true if a debugger client is connected.
109 *
110 * @return true - a debugger client is connected,
111 * false - otherwise
112 */
113 bool
jerry_debugger_transport_is_connected(void)114 jerry_debugger_transport_is_connected (void)
115 {
116 return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0;
117 } /* jerry_debugger_transport_is_connected */
118
119 /**
120 * Notifies the debugger server that the connection is closed.
121 */
122 void
jerry_debugger_transport_close(void)123 jerry_debugger_transport_close (void)
124 {
125 if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED))
126 {
127 return;
128 }
129
130 JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE;
131
132 jerry_debugger_transport_header_t *current_p = JERRY_CONTEXT (debugger_transport_header_p);
133
134 JERRY_ASSERT (current_p != NULL);
135
136 do
137 {
138 jerry_debugger_transport_header_t *next_p = current_p->next_p;
139
140 current_p->close (current_p);
141
142 current_p = next_p;
143 }
144 while (current_p != NULL);
145
146 jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n");
147
148 jerry_debugger_free_unreferenced_byte_code ();
149 } /* jerry_debugger_transport_close */
150
151 /**
152 * Send data over the current connection
153 *
154 * @return true - data sent successfully,
155 * false - connection closed
156 */
157 bool
jerry_debugger_transport_send(const uint8_t * message_p,size_t message_length)158 jerry_debugger_transport_send (const uint8_t *message_p, /**< message to be sent */
159 size_t message_length) /**< message length in bytes */
160 {
161 JERRY_ASSERT (jerry_debugger_transport_is_connected ());
162 JERRY_ASSERT (message_length > 0);
163
164 jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
165 uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
166 size_t max_send_size = JERRY_CONTEXT (debugger_max_send_size);
167
168 do
169 {
170 size_t fragment_length = (message_length <= max_send_size ? message_length
171 : max_send_size);
172
173 memcpy (payload_p, message_p, fragment_length);
174
175 if (!header_p->send (header_p, payload_p, fragment_length))
176 {
177 return false;
178 }
179
180 message_p += fragment_length;
181 message_length -= fragment_length;
182 }
183 while (message_length > 0);
184
185 return true;
186 } /* jerry_debugger_transport_send */
187
188 /**
189 * Receive data from the current connection
190 *
191 * Note:
192 * A message is received if message_start_p is not NULL
193 *
194 * @return true - function successfully completed,
195 * false - connection closed
196 */
197 bool
jerry_debugger_transport_receive(jerry_debugger_transport_receive_context_t * context_p)198 jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p) /**< [out] receive
199 * context */
200 {
201 JERRY_ASSERT (jerry_debugger_transport_is_connected ());
202
203 context_p->buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
204 context_p->received_length = JERRY_CONTEXT (debugger_received_length);
205 context_p->message_p = NULL;
206 context_p->message_length = 0;
207 context_p->message_total_length = 0;
208
209 jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
210
211 return header_p->receive (header_p, context_p);
212 } /* jerry_debugger_transport_receive */
213
214 /**
215 * Clear the message buffer after the message is processed
216 */
217 void
jerry_debugger_transport_receive_completed(jerry_debugger_transport_receive_context_t * context_p)218 jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p) /**< receive
219 * context */
220 {
221 JERRY_ASSERT (context_p->message_p != NULL);
222 JERRY_ASSERT (context_p->buffer_p == JERRY_CONTEXT (debugger_receive_buffer));
223
224 size_t message_total_length = context_p->message_total_length;
225 size_t received_length = context_p->received_length;
226
227 JERRY_ASSERT (message_total_length <= received_length);
228
229 if (message_total_length == 0 || message_total_length == received_length)
230 {
231 /* All received data is processed. */
232 JERRY_CONTEXT (debugger_received_length) = 0;
233 return;
234 }
235
236 uint8_t *buffer_p = context_p->buffer_p;
237 received_length -= message_total_length;
238
239 memmove (buffer_p, buffer_p + message_total_length, received_length);
240
241 JERRY_CONTEXT (debugger_received_length) = (uint16_t) received_length;
242 } /* jerry_debugger_transport_receive_completed */
243
244 /**
245 * Suspend execution for a predefined time (JERRY_DEBUGGER_TRANSPORT_TIMEOUT ms).
246 */
247 void
jerry_debugger_transport_sleep(void)248 jerry_debugger_transport_sleep (void)
249 {
250 jerry_port_sleep (JERRY_DEBUGGER_TRANSPORT_TIMEOUT);
251 } /* jerry_debugger_transport_sleep */
252
253 #endif /* ENABLED (JERRY_DEBUGGER) */
254