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
+43
-6
@@ -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);
|
||||
```
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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> " : "";
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
s
|
||||
s
|
||||
s
|
||||
continue
|
||||
@@ -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
|
||||
@@ -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();
|
||||
@@ -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=$?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user