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:
committed by
Zoltan Herczeg
parent
a3885be6ce
commit
3e3d6373b8
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user