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
+43 -6
View File
@@ -25,18 +25,25 @@ can be used for transmitting debugger messages.
## Debugging JavaScript applications
The debugger client must be connected to the server before the
JavaScript application runs. On-the-fly attachment is not supported
because the debugging information (e.g. line index of each possible
breakpoint location) is not preserved by JerryScript. The client is
expected to be run on a system with much more resources and it should
be capable of storing this information. JerryScript frees all debug
information after it is transmitted to the client to save memory.
JavaScript application runs. On-the-fly attachment is supported
for one file, right after of engine initialization
(this feature available with the python client). The debugging
information (e.g. line index of each possible -breakpoint location)
is not preserved by JerryScript. The client is expected to be run
on a system with much more resources and it should be capable of
storing this information. JerryScript frees all debug information
after it is transmitted to the client to save memory.
The following argument makes JerryScript wait for a client
connection:
`--start-debug-server`
The following argument makes JerryScript wait for a client
source code:
`--debugger-wait-source`
It is also recommended to increase the log level to see
the *Waiting for client connection* message:
@@ -194,3 +201,33 @@ jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint)
jerry_debugger_stop_at_breakpoint (false);
}
```
### jerry_debugger_wait_and_run_client_source
**Summary**
Stops the engine and puts that into a waiting loop. If the client send
a source code and the JerryScript receive that, then the function will
run the source with the initialized options.
**Prototype**
```c
jerry_debugger_wait_and_run_type_t
jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value)
```
**Example**
```c
jerry_init (JERRY_INIT_DEBUGGER);
jerry_value_t wait_and_run_value;
if (jerry_debugger_wait_and_run_client_source (&wait_and_run_value) == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
{
// Handle the fail (e.g. create an error).
}
jerry_release_value (wait_and_run_value);
```
+79
View File
@@ -116,3 +116,82 @@ jerry_debugger_cleanup (void)
}
#endif /* JERRY_DEBUGGER */
} /* jerry_debugger_cleanup */
/**
* Sets whether the engine should wait and run a source.
*
* @return enum JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED - if the source is not received
* JERRY_DEBUGGER_SOURCE_RECEIVED - if the source received
*/
jerry_debugger_wait_and_run_type_t
jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value) /**< [out] parse and run return value */
{
*return_value = jerry_create_undefined ();
#ifdef JERRY_DEBUGGER
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
{
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CLIENT_SOURCE_MODE);
jerry_debugger_uint8_data_t *client_source_data_p = NULL;
while (true)
{
if (jerry_debugger_receive (&client_source_data_p))
{
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED))
{
break;
}
/* The source arrived. */
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
JERRY_ASSERT (client_source_data_p != NULL);
jerry_char_t *string_p = (jerry_char_t *) (client_source_data_p + 1);
size_t name_size = strlen ((const char *) string_p);
*return_value = jerry_parse_named_resource (string_p,
name_size,
(string_p + name_size + 1),
(client_source_data_p->uint8_size - name_size - 1),
false);
if (!jerry_value_has_error_flag (*return_value))
{
jerry_value_t func_val = *return_value;
*return_value = jerry_run (func_val);
jerry_release_value (func_val);
return JERRY_DEBUGGER_SOURCE_RECEIVED;
}
else
{
jmem_heap_free_block (client_source_data_p,
client_source_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
}
}
}
jerry_debugger_sleep ();
}
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
|| !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED));
if (client_source_data_p != NULL)
{
/* The data may partly arrived. */
jmem_heap_free_block (client_source_data_p,
client_source_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
}
}
return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
#else
return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
#endif /* JERRY_DEBUGGER */
} /* jerry_debugger_wait_and_run_client_source */
+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);
+1 -1
View File
@@ -803,7 +803,7 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever
&& JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER)
{
/* Wait until all byte code is freed or the connection is aborted. */
jerry_debugger_receive ();
jerry_debugger_receive (NULL);
}
#endif /* JERRY_DEBUGGER */
+10
View File
@@ -27,6 +27,15 @@ extern "C"
* @{
*/
/**
* Types for the client source wait and run method.
*/
typedef enum
{
JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED = 0, /**< source is not received */
JERRY_DEBUGGER_SOURCE_RECEIVED = 1, /**< the source has been received */
} jerry_debugger_wait_and_run_type_t;
/**
* Engine debugger functions.
*/
@@ -34,6 +43,7 @@ bool jerry_debugger_is_connected (void);
void jerry_debugger_stop (void);
void jerry_debugger_continue (void);
void jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint);
jerry_debugger_wait_and_run_type_t jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value);
void jerry_debugger_init (uint16_t port);
void jerry_debugger_cleanup (void);
+1 -1
View File
@@ -2405,7 +2405,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
if (jerry_debugger_receive ())
if (jerry_debugger_receive (NULL))
{
continue;
}
+8 -6
View File
@@ -65,12 +65,14 @@ var JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2;
var JERRY_DEBUGGER_EXCEPTION_CONFIG = 3;
var JERRY_DEBUGGER_MEMSTATS = 4;
var JERRY_DEBUGGER_STOP = 5;
var JERRY_DEBUGGER_CONTINUE = 6;
var JERRY_DEBUGGER_STEP = 7;
var JERRY_DEBUGGER_NEXT = 8;
var JERRY_DEBUGGER_GET_BACKTRACE = 9;
var JERRY_DEBUGGER_EVAL = 10;
var JERRY_DEBUGGER_EVAL_PART = 11;
var JERRY_DEBUGGER_CLIENT_SOURCE = 6;
var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7;
var JERRY_DEBUGGER_CONTINUE = 8;
var JERRY_DEBUGGER_STEP = 9;
var JERRY_DEBUGGER_NEXT = 10;
var JERRY_DEBUGGER_GET_BACKTRACE = 11;
var JERRY_DEBUGGER_EVAL = 12;
var JERRY_DEBUGGER_EVAL_PART = 13;
var textBox = document.getElementById("log");
var commandBox = document.getElementById("command");
+32 -10
View File
@@ -58,12 +58,14 @@ JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2
JERRY_DEBUGGER_EXCEPTION_CONFIG = 3
JERRY_DEBUGGER_MEMSTATS = 4
JERRY_DEBUGGER_STOP = 5
JERRY_DEBUGGER_CONTINUE = 6
JERRY_DEBUGGER_STEP = 7
JERRY_DEBUGGER_NEXT = 8
JERRY_DEBUGGER_GET_BACKTRACE = 9
JERRY_DEBUGGER_EVAL = 10
JERRY_DEBUGGER_EVAL_PART = 11
JERRY_DEBUGGER_CLIENT_SOURCE = 6
JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7
JERRY_DEBUGGER_CONTINUE = 8
JERRY_DEBUGGER_STEP = 9
JERRY_DEBUGGER_NEXT = 10
JERRY_DEBUGGER_GET_BACKTRACE = 11
JERRY_DEBUGGER_EVAL = 12
JERRY_DEBUGGER_EVAL_PART = 13
MAX_BUFFER_SIZE = 128
WEBSOCKET_BINARY_FRAME = 2
@@ -85,6 +87,8 @@ def arguments_parse():
help="set display range")
parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1],
help="set exception config, usage 1: [Enable] or 0: [Disable]")
parser.add_argument("--client-source", action="store", default=None, type=str,
help="specify a javascript source file to execute")
args = parser.parse_args()
@@ -345,7 +349,7 @@ class DebuggerPrompt(Cmd):
pprint(self.debugger.function_list)
def eval_string(self, args):
def send_string(self, args, message_type):
size = len(args)
if size == 0:
return
@@ -359,7 +363,7 @@ class DebuggerPrompt(Cmd):
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
WEBSOCKET_FIN_BIT + max_fragment + message_header,
0,
JERRY_DEBUGGER_EVAL,
message_type,
size)
if size == max_fragment:
@@ -370,6 +374,11 @@ class DebuggerPrompt(Cmd):
self.debugger.send_message(message + args[0:max_fragment])
offset = max_fragment
if message_type == JERRY_DEBUGGER_EVAL:
message_type = JERRY_DEBUGGER_EVAL_PART
else:
message_type = JERRY_DEBUGGER_CLIENT_SOURCE_PART
# 1: length of type byte
message_header = 1
@@ -381,7 +390,7 @@ class DebuggerPrompt(Cmd):
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
WEBSOCKET_FIN_BIT + next_fragment + message_header,
0,
JERRY_DEBUGGER_EVAL_PART)
message_type)
prev_offset = offset
offset += next_fragment
@@ -391,7 +400,7 @@ class DebuggerPrompt(Cmd):
def do_eval(self, args):
""" Evaluate JavaScript source code """
self.eval_string(args)
self.send_string(args, JERRY_DEBUGGER_EVAL)
do_e = do_eval
@@ -420,6 +429,16 @@ class DebuggerPrompt(Cmd):
do_ms = do_memstats
def send_client_source(self, args):
""" Send and execute the specified Javascript source file to the debugger """
if not args.lower().endswith('.js'):
sys.exit("Error: Javascript file expected!")
return
with open(args, 'r') as f:
content = args + "\0" + f.read()
self.send_string(content, JERRY_DEBUGGER_CLIENT_SOURCE)
class Multimap(object):
def __init__(self):
@@ -941,6 +960,9 @@ def main():
if args.exception is not None:
prompt.do_exception(str(args.exception))
if args.client_source is not None:
prompt.send_client_source(str(args.client_source))
while True:
if not non_interactive and prompt.cont:
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
+27
View File
@@ -281,6 +281,7 @@ typedef enum
OPT_SHOW_RE_OP,
OPT_DEBUG_SERVER,
OPT_DEBUG_PORT,
OPT_DEBUGGER_WAIT_SOURCE,
OPT_SAVE_SNAP_GLOBAL,
OPT_SAVE_SNAP_EVAL,
OPT_SAVE_LIT_LIST,
@@ -312,6 +313,8 @@ static const cli_opt_t main_opts[] =
.help = "start debug server and wait for a connecting client"),
CLI_OPT_DEF (.id = OPT_DEBUG_PORT, .longopt = "debug-port", .meta = "NUM",
.help = "debug server port (default: 5001)"),
CLI_OPT_DEF (.id = OPT_DEBUGGER_WAIT_SOURCE, .longopt = "debugger-wait-source",
.help = "wait for an executable source from the client"),
CLI_OPT_DEF (.id = OPT_SAVE_SNAP_GLOBAL, .longopt = "save-snapshot-for-global", .meta = "FILE",
.help = "save binary snapshot of parsed JS input (for execution in global context)"),
CLI_OPT_DEF (.id = OPT_SAVE_SNAP_EVAL, .longopt = "save-snapshot-for-eval", .meta = "FILE",
@@ -407,6 +410,7 @@ main (int argc,
uint16_t debug_port = 5001;
bool is_repl_mode = false;
bool is_wait_mode = false;
bool no_prompt = false;
cli_state_t cli_state = cli_init (main_opts, argc - 1, argv + 1);
@@ -472,6 +476,14 @@ main (int argc,
}
break;
}
case OPT_DEBUGGER_WAIT_SOURCE:
{
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
{
is_wait_mode = true;
}
break;
}
case OPT_SAVE_SNAP_GLOBAL:
case OPT_SAVE_SNAP_EVAL:
{
@@ -707,6 +719,21 @@ main (int argc,
}
}
if (is_wait_mode)
{
is_repl_mode = false;
#ifdef JERRY_DEBUGGER
jerry_value_t wait_and_run_value;
if (jerry_debugger_wait_and_run_client_source (&wait_and_run_value) == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
{
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Connection aborted before source arrived.");
}
jerry_release_value (wait_and_run_value);
#endif /* JERRY_DEBUGGER */
}
if (is_repl_mode)
{
const char *prompt = !no_prompt ? "jerry> " : "";
+4
View File
@@ -0,0 +1,4 @@
s
s
s
continue
+9
View File
@@ -0,0 +1,9 @@
Connecting to: localhost:5001
Stopped at tests/debugger/client_source.js:15
(jerry-debugger) s
Stopped at tests/debugger/client_source.js:40
(jerry-debugger) s
Stopped at tests/debugger/client_source.js:35 (in test() at line:33, col:1)
(jerry-debugger) s
Stopped at tests/debugger/client_source.js:36 (in test() at line:33, col:1)
(jerry-debugger) continue
+40
View File
@@ -0,0 +1,40 @@
// 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.
print("client-source-test");
function finish(z) {
print("function finish");
print("finish: " + z);
}
function bar(y) {
print("function bar");
finish(y + "-bar");
}
function foo(x)
{
print("function foo");
bar(x + "-foo");
}
function test()
{
print("function test");
var x = "test";
foo(x);
}
test();
+8 -2
View File
@@ -17,8 +17,14 @@
JERRY=$1
DEBUGGER_CLIENT=$2
TEST_CASE=$3
CLIENT_ARGS=""
START_DEBUG_SERVER="${JERRY} ${TEST_CASE}.js --start-debug-server &"
if [[ $TEST_CASE == *"client_source"* ]]; then
START_DEBUG_SERVER="${JERRY} --start-debug-server --debugger-wait-source &"
CLIENT_ARGS="--client-source ${TEST_CASE}.js"
else
START_DEBUG_SERVER="${JERRY} ${TEST_CASE}.js --start-debug-server &"
fi
echo "$START_DEBUG_SERVER"
eval "$START_DEBUG_SERVER"
@@ -26,7 +32,7 @@ sleep 1s
RESULT_TEMP=`mktemp ${TEST_CASE}.out.XXXXXXXXXX`
(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive) &> ${RESULT_TEMP}
(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) &> ${RESULT_TEMP}
diff -U0 ${TEST_CASE}.expected ${RESULT_TEMP}
STATUS_CODE=$?