/* Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "debugger.h" #include "jcontext.h" #include "jerryscript.h" #if ENABLED (JERRY_DEBUGGER) /** * Minimum number of bytes transmitted or received. */ #define JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE 64 /** * Sleep time in milliseconds between each jerry_debugger_receive call */ #define JERRY_DEBUGGER_TRANSPORT_TIMEOUT 10 /** * Add a new transport layer. */ void jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p, /**< transport implementation */ size_t send_message_header_size, /**< header bytes reserved for outgoing messages */ size_t max_send_message_size, /**< maximum number of bytes transmitted in a message */ size_t receive_message_header_size, /**< header bytes reserved for incoming messages */ size_t max_receive_message_size) /**< maximum number of bytes received in a message */ { JERRY_ASSERT (max_send_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE && max_receive_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE); header_p->next_p = JERRY_CONTEXT (debugger_transport_header_p); JERRY_CONTEXT (debugger_transport_header_p) = header_p; uint8_t *payload_p; size_t max_send_size; size_t max_receive_size; if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p); max_send_size = JERRY_CONTEXT (debugger_max_send_size); max_receive_size = JERRY_CONTEXT (debugger_max_receive_size); } else { JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED); payload_p = JERRY_CONTEXT (debugger_send_buffer); max_send_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE; max_receive_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE; } JERRY_ASSERT (max_send_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + send_message_header_size); JERRY_ASSERT (max_receive_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + receive_message_header_size); JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p + send_message_header_size; max_send_size = max_send_size - send_message_header_size; max_receive_size = max_receive_size - receive_message_header_size; if (max_send_size > max_send_message_size) { max_send_size = max_send_message_size; } if (max_receive_size > max_receive_message_size) { max_receive_size = max_receive_message_size; } JERRY_CONTEXT (debugger_max_send_size) = (uint8_t) max_send_size; JERRY_CONTEXT (debugger_max_receive_size) = (uint8_t) max_receive_size; } /* jerry_debugger_transport_add */ /** * Starts the communication to the debugger client. * Must be called after the connection is successfully established. */ void jerry_debugger_transport_start (void) { #ifdef ACE_DEBUGGER_CUSTOM JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_TRANSPORT_STARTED); #endif JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); if (jerry_debugger_send_configuration (JERRY_CONTEXT (debugger_max_receive_size))) { JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; } } /* jerry_debugger_transport_start */ /** * Returns true if a debugger client is connected. * * @return true - a debugger client is connected, * false - otherwise */ bool jerry_debugger_transport_is_connected (void) { return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0; } /* jerry_debugger_transport_is_connected */ /** * Notifies the debugger server that the connection is closed. */ void jerry_debugger_transport_close (void) { if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)) { return; } JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE; jerry_debugger_transport_header_t *current_p = JERRY_CONTEXT (debugger_transport_header_p); JERRY_ASSERT (current_p != NULL); do { jerry_debugger_transport_header_t *next_p = current_p->next_p; current_p->close (current_p); current_p = next_p; } while (current_p != NULL); jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n"); jerry_debugger_free_unreferenced_byte_code (); } /* jerry_debugger_transport_close */ /** * Send data over the current connection * * @return true - data sent successfully, * false - connection closed */ bool jerry_debugger_transport_send (const uint8_t *message_p, /**< message to be sent */ size_t message_length) /**< message length in bytes */ { JERRY_ASSERT (jerry_debugger_transport_is_connected ()); JERRY_ASSERT (message_length > 0); jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p); uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p); size_t max_send_size = JERRY_CONTEXT (debugger_max_send_size); do { size_t fragment_length = (message_length <= max_send_size ? message_length : max_send_size); memcpy (payload_p, message_p, fragment_length); if (!header_p->send (header_p, payload_p, fragment_length)) { return false; } message_p += fragment_length; message_length -= fragment_length; } while (message_length > 0); return true; } /* jerry_debugger_transport_send */ /** * Receive data from the current connection * * Note: * A message is received if message_start_p is not NULL * * @return true - function successfully completed, * false - connection closed */ bool jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p) /**< [out] receive * context */ { JERRY_ASSERT (jerry_debugger_transport_is_connected ()); context_p->buffer_p = JERRY_CONTEXT (debugger_receive_buffer); context_p->received_length = JERRY_CONTEXT (debugger_received_length); context_p->message_p = NULL; context_p->message_length = 0; context_p->message_total_length = 0; jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p); return header_p->receive (header_p, context_p); } /* jerry_debugger_transport_receive */ /** * Clear the message buffer after the message is processed */ void jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p) /**< receive * context */ { JERRY_ASSERT (context_p->message_p != NULL); JERRY_ASSERT (context_p->buffer_p == JERRY_CONTEXT (debugger_receive_buffer)); size_t message_total_length = context_p->message_total_length; size_t received_length = context_p->received_length; JERRY_ASSERT (message_total_length <= received_length); if (message_total_length == 0 || message_total_length == received_length) { /* All received data is processed. */ JERRY_CONTEXT (debugger_received_length) = 0; return; } uint8_t *buffer_p = context_p->buffer_p; received_length -= message_total_length; memmove (buffer_p, buffer_p + message_total_length, received_length); JERRY_CONTEXT (debugger_received_length) = (uint16_t) received_length; } /* jerry_debugger_transport_receive_completed */ /** * Suspend execution for a predefined time (JERRY_DEBUGGER_TRANSPORT_TIMEOUT ms). */ void jerry_debugger_transport_sleep (void) { jerry_port_sleep (JERRY_DEBUGGER_TRANSPORT_TIMEOUT); } /* jerry_debugger_transport_sleep */ #endif /* ENABLED (JERRY_DEBUGGER) */