Add source sending feature to the debugger. (#1932)

With this feature the debugger webIDE and the python client can able to send a source code to the debugger while that is running in wait mode.
This feature can be activated with the --debugger-wait-source switch and the debugger will wait for the source messages.
If every message part are received the debugger will continue the exectuion with the initalized options.

JerryScript-DCO-1.0-Signed-off-by: Imre Kiss kissi.szeged@partner.samsung.com
This commit is contained in:
Imre Kiss
2017-08-03 14:29:47 +02:00
committed by Zoltan Herczeg
parent a3885be6ce
commit 3e3d6373b8
16 changed files with 423 additions and 86 deletions
+12 -3
View File
@@ -44,6 +44,13 @@
*/
#define JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE 4
/**
*
*/
#define JERRY_DEBUGGER_RECEIVE_DATA_MODE \
(JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
/**
* Header for incoming packets.
*/
@@ -433,16 +440,18 @@ JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MAX_RECEIVE_SIZE < 126,
* false - otherwise
*/
bool
jerry_debugger_receive (void)
jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */
{
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
JERRY_ASSERT (message_data_p != NULL ? (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE)
: !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE));
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
uint8_t *recv_buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
bool resume_exec = false;
uint8_t expected_message_type = 0;
void *message_data = NULL;
while (true)
{
@@ -532,7 +541,7 @@ jerry_debugger_receive (void)
message_size,
&resume_exec,
&expected_message_type,
&message_data))
message_data_p))
{
return true;
}
+18 -1
View File
@@ -63,6 +63,23 @@ typedef struct
uint8_t size; /**< size of the message */
} jerry_debugger_send_header_t;
/**
* Incoming message: next message of string data.
*/
typedef struct
{
uint8_t type; /**< type of the message */
} jerry_debugger_receive_uint8_data_part_t;
/**
* Byte data for evaluating expressions and receiving client source.
*/
typedef struct
{
uint32_t uint8_size; /**< total size of the client source */
uint32_t uint8_offset; /**< current offset in the client source */
} jerry_debugger_uint8_data_t;
/**
* Initialize the header of an outgoing message.
*/
@@ -85,7 +102,7 @@ bool jerry_debugger_accept_connection (void);
void jerry_debugger_close_connection (void);
bool jerry_debugger_send (size_t data_size);
bool jerry_debugger_receive (void);
bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p);
void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len,
const uint8_t *input2, size_t input2_len,
+109 -38
View File
@@ -45,11 +45,6 @@
#define JERRY_DEBUGGER_RECEIVE_BUFFER_AS(type, name_p) \
type *name_p = ((type *) recv_buffer_p)
/**
* Sleep time in milliseconds between each jerry_debugger_receive call
*/
#define JERRY_DEBUGGER_TIMEOUT 100
/**
* Free all unreferenced byte code structures which
* were not acknowledged by the debugger client.
@@ -218,19 +213,17 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
* Suspend execution for a given time.
* Note: If the platform does not have nanosleep or usleep, this function does not sleep at all.
*/
static void
jerry_debugger_sleep (unsigned milliseconds) /**< suspending time */
void
jerry_debugger_sleep (void)
{
#ifdef HAVE_TIME_H
nanosleep (&(const struct timespec)
{
milliseconds / 1000, (milliseconds % 1000) * 1000000L /* Seconds, nanoseconds */
JERRY_DEBUGGER_TIMEOUT / 1000, (JERRY_DEBUGGER_TIMEOUT % 1000) * 1000000L /* Seconds, nanoseconds */
}
, NULL);
#elif defined (HAVE_UNISTD_H)
usleep ((useconds_t) milliseconds * 1000);
#else /* If neither of the libs found */
JERRY_UNUSED (milliseconds);
usleep ((useconds_t) JERRY_DEBUGGER_TIMEOUT * 1000);
#endif /* HAVE_TIME_H */
} /* jerry_debugger_sleep */
@@ -255,8 +248,8 @@ inline bool __attr_always_inline___
jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the received data */
uint32_t message_size, /**< message size */
bool *resume_exec_p, /**< pointer to the resume exec flag */
uint8_t *expected_message_type_p, /**< expected message type */
void **message_data_p) /**< custom message data */
uint8_t *expected_message_type_p, /**< message type */
jerry_debugger_uint8_data_t **message_data_p) /**< custom message data */
{
/* Process the received message. */
@@ -270,53 +263,65 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec
if (*expected_message_type_p != 0)
{
JERRY_ASSERT (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART);
JERRY_ASSERT (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART
|| *expected_message_type_p == JERRY_DEBUGGER_CLIENT_SOURCE_PART);
jerry_debugger_eval_data_t *eval_data_p = (jerry_debugger_eval_data_t *) *message_data_p;
jerry_debugger_uint8_data_t *uint8_data_p = (jerry_debugger_uint8_data_t *) *message_data_p;
if (recv_buffer_p[0] != JERRY_DEBUGGER_EVAL_PART)
if (recv_buffer_p[0] != *expected_message_type_p)
{
jmem_heap_free_block (eval_data_p, eval_data_p->eval_size + sizeof (jerry_debugger_eval_data_t));
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message\n");
jerry_debugger_close_connection ();
return false;
}
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_eval_part_t, eval_part_p);
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_uint8_data_part_t, uint8_data_part_p);
if (message_size < sizeof (jerry_debugger_receive_eval_part_t) + 1)
if (message_size < sizeof (jerry_debugger_receive_uint8_data_part_t) + 1)
{
jmem_heap_free_block (eval_data_p, eval_data_p->eval_size + sizeof (jerry_debugger_eval_data_t));
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
jerry_debugger_close_connection ();
return false;
}
uint32_t expected_data = eval_data_p->eval_size - eval_data_p->eval_offset;
uint32_t expected_data = uint8_data_p->uint8_size - uint8_data_p->uint8_offset;
message_size -= (uint32_t) sizeof (jerry_debugger_receive_eval_part_t);
message_size -= (uint32_t) sizeof (jerry_debugger_receive_uint8_data_part_t);
if (message_size > expected_data)
{
jmem_heap_free_block (eval_data_p, eval_data_p->eval_size + sizeof (jerry_debugger_eval_data_t));
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
jerry_debugger_close_connection ();
return false;
}
lit_utf8_byte_t *eval_string_p = (lit_utf8_byte_t *) (eval_data_p + 1);
memcpy (eval_string_p + eval_data_p->eval_offset,
(lit_utf8_byte_t *) (eval_part_p + 1),
lit_utf8_byte_t *string_p = (lit_utf8_byte_t *) (uint8_data_p + 1);
memcpy (string_p + uint8_data_p->uint8_offset,
(lit_utf8_byte_t *) (uint8_data_part_p + 1),
message_size);
if (message_size < expected_data)
{
eval_data_p->eval_offset += message_size;
uint8_data_p->uint8_offset += message_size;
return true;
}
bool result = jerry_debugger_send_eval (eval_string_p, eval_data_p->eval_size);
jmem_heap_free_block (eval_data_p, eval_data_p->eval_size + sizeof (jerry_debugger_eval_data_t));
bool result = false;
if (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART)
{
result = jerry_debugger_send_eval (string_p, uint8_data_p->uint8_size);
}
else
{
result = true;
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags)
& ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE);
*resume_exec_p = true;
}
*expected_message_type_p = 0;
return result;
}
@@ -486,24 +491,82 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec
return jerry_debugger_send_eval ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size);
}
jerry_debugger_eval_data_t *eval_data_p;
size_t eval_data_size = sizeof (jerry_debugger_eval_data_t) + eval_size;
jerry_debugger_uint8_data_t *eval_uint8_data_p;
size_t eval_data_size = sizeof (jerry_debugger_uint8_data_t) + eval_size;
eval_data_p = (jerry_debugger_eval_data_t *) jmem_heap_alloc_block (eval_data_size);
eval_uint8_data_p = (jerry_debugger_uint8_data_t *) jmem_heap_alloc_block (eval_data_size);
eval_data_p->eval_size = eval_size;
eval_data_p->eval_offset = (uint32_t) (message_size - sizeof (jerry_debugger_receive_eval_first_t));
eval_uint8_data_p->uint8_size = eval_size;
eval_uint8_data_p->uint8_offset = (uint32_t) (message_size - sizeof (jerry_debugger_receive_eval_first_t));
lit_utf8_byte_t *eval_string_p = (lit_utf8_byte_t *) (eval_data_p + 1);
lit_utf8_byte_t *eval_string_p = (lit_utf8_byte_t *) (eval_uint8_data_p + 1);
memcpy (eval_string_p,
(lit_utf8_byte_t *) (eval_first_p + 1),
message_size - sizeof (jerry_debugger_receive_eval_first_t));
*message_data_p = eval_data_p;
*message_data_p = eval_uint8_data_p;
*expected_message_type_p = JERRY_DEBUGGER_EVAL_PART;
return true;
}
case JERRY_DEBUGGER_CLIENT_SOURCE:
{
if (message_size <= sizeof (jerry_debugger_receive_client_source_first_t))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
jerry_debugger_close_connection ();
return false;
}
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in client source mode\n");
jerry_debugger_close_connection ();
return false;
}
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_client_source_first_t, client_source_first_p);
uint32_t client_source_size;
memcpy (&client_source_size, client_source_first_p->code_size, sizeof (uint32_t));
if (client_source_size <= JERRY_DEBUGGER_MAX_RECEIVE_SIZE - sizeof (jerry_debugger_receive_client_source_first_t)
&& client_source_size != message_size - sizeof (jerry_debugger_receive_client_source_first_t))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
jerry_debugger_close_connection ();
return false;
}
jerry_debugger_uint8_data_t *client_source_data_p;
size_t client_source_data_size = sizeof (jerry_debugger_uint8_data_t) + client_source_size;
client_source_data_p = (jerry_debugger_uint8_data_t *) jmem_heap_alloc_block (client_source_data_size);
client_source_data_p->uint8_size = client_source_size;
client_source_data_p->uint8_offset = (uint32_t) (message_size
- sizeof (jerry_debugger_receive_client_source_first_t));
lit_utf8_byte_t *client_source_string_p = (lit_utf8_byte_t *) (client_source_data_p + 1);
memcpy (client_source_string_p,
(lit_utf8_byte_t *) (client_source_first_p + 1),
message_size - sizeof (jerry_debugger_receive_client_source_first_t));
*message_data_p = client_source_data_p;
if (client_source_data_p->uint8_size != client_source_data_p->uint8_offset)
{
*expected_message_type_p = JERRY_DEBUGGER_CLIENT_SOURCE_PART;
}
else
{
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags)
& ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE);
*resume_exec_p = true;
}
return true;
}
default:
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message.");
@@ -545,9 +608,17 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_BREAKPOINT_MODE);
while (!jerry_debugger_receive ())
jerry_debugger_uint8_data_t *uint8_data = NULL;
while (!jerry_debugger_receive (&uint8_data))
{
jerry_debugger_sleep (JERRY_DEBUGGER_TIMEOUT);
jerry_debugger_sleep ();
}
if (uint8_data != NULL)
{
jmem_heap_free_block (uint8_data,
uint8_data->uint8_size + sizeof (jerry_debugger_uint8_data_t));
}
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_BREAKPOINT_MODE);
+22 -18
View File
@@ -28,6 +28,11 @@
*/
#define JERRY_DEBUGGER_MESSAGE_FREQUENCY 5
/**
* Sleep time in milliseconds between each jerry_debugger_receive call
*/
#define JERRY_DEBUGGER_TIMEOUT 100
/**
* Limited resources available for the engine, so it is important to
* check the maximum buffer size. It needs to be between 64 and 256 bytes.
@@ -78,6 +83,7 @@ typedef enum
JERRY_DEBUGGER_VM_STOP = 1u << 2, /**< stop at the next breakpoint regardless it is enabled */
JERRY_DEBUGGER_VM_IGNORE = 1u << 3, /**< ignore all breakpoints */
JERRY_DEBUGGER_VM_IGNORE_EXCEPTION = 1u << 4, /**< debugger stop at an exception */
JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 5, /**< debugger waiting for client code */
} jerry_debugger_flags_t;
/**
@@ -119,16 +125,18 @@ typedef enum
JERRY_DEBUGGER_EXCEPTION_CONFIG = 3, /**< exception handler config */
JERRY_DEBUGGER_MEMSTATS = 4, /**< list memory statistics */
JERRY_DEBUGGER_STOP = 5, /**< stop execution */
JERRY_DEBUGGER_CLIENT_SOURCE = 6, /**< first message of client source */
JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7, /**< next message of client source */
/* The following messages are only available in breakpoint
* mode and they switch the engine to run mode. */
JERRY_DEBUGGER_CONTINUE = 6, /**< continue execution */
JERRY_DEBUGGER_STEP = 7, /**< next breakpoint, step into functions */
JERRY_DEBUGGER_NEXT = 8, /**< next breakpoint in the same context */
JERRY_DEBUGGER_CONTINUE = 8, /**< continue execution */
JERRY_DEBUGGER_STEP = 9, /**< next breakpoint, step into functions */
JERRY_DEBUGGER_NEXT = 10, /**< next breakpoint in the same context */
/* The following messages are only available in breakpoint
* mode and this mode is kept after the message is processed. */
JERRY_DEBUGGER_GET_BACKTRACE = 9, /**< get backtrace */
JERRY_DEBUGGER_EVAL = 10, /**< first message of evaluating a string */
JERRY_DEBUGGER_EVAL_PART = 11, /**< next message of evaluating a string */
JERRY_DEBUGGER_GET_BACKTRACE = 11, /**< get backtrace */
JERRY_DEBUGGER_EVAL = 12, /**< first message of evaluating a string */
JERRY_DEBUGGER_EVAL_PART = 13, /**< next message of evaluating a string */
} jerry_debugger_header_type_t;
/**
@@ -288,27 +296,23 @@ typedef struct
uint8_t eval_size[sizeof (uint32_t)]; /**< total size of the message */
} jerry_debugger_receive_eval_first_t;
/**
* Incoming message: next message of evaluating expression.
* Incoming message: first message of client source.
*/
typedef struct
{
uint8_t type; /**< type of the message */
} jerry_debugger_receive_eval_part_t;
/**
* Data for evaluating expressions
*/
typedef struct
{
uint32_t eval_size; /**< total size of the eval string */
uint32_t eval_offset; /**< current offset in the eval string */
} jerry_debugger_eval_data_t;
uint8_t code_size[sizeof (uint32_t)]; /**< total size of the message */
} jerry_debugger_receive_client_source_first_t;
void jerry_debugger_free_unreferenced_byte_code (void);
void jerry_debugger_sleep (void);
bool jerry_debugger_process_message (uint8_t *recv_buffer_p, uint32_t message_size,
bool *resume_exec_p, uint8_t *expected_message_p, void **message_data_p);
bool *resume_exec_p, uint8_t *expected_message_p,
jerry_debugger_uint8_data_t **message_data_p);
void jerry_debugger_breakpoint_hit (uint8_t message_type);
void jerry_debugger_send_type (jerry_debugger_header_type_t type);