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 */ 35void 36jerry_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 */ 92void 93jerry_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 */ 113bool 114jerry_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 */ 122void 123jerry_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 */ 157bool 158jerry_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 */ 197bool 198jerry_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 */ 217void 218jerry_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 */ 247void 248jerry_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