Skip to content

Add eval support for JerryScript debugger #1588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions jerry-core/debugger/jerry-debugger-ws.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
* limitations under the License.
*/

#include "jerry-api.h"

#ifdef JERRY_DEBUGGER

#include <arpa/inet.h>
Expand Down Expand Up @@ -383,7 +381,7 @@ jerry_debugger_accept_connection ()
return false;
}

if (!jerry_debugger_send_configuration (JERRY_DEBUGGER_MAX_BUFFER_SIZE - sizeof (jerry_debugger_receive_header_t)))
if (!jerry_debugger_send_configuration (JERRY_DEBUGGER_MAX_RECEIVE_SIZE))
{
return false;
}
Expand Down Expand Up @@ -432,6 +430,9 @@ jerry_debugger_send (size_t data_size) /**< data size */
return jerry_debugger_send_tcp (JERRY_CONTEXT (debugger_send_buffer), data_size);
} /* jerry_debugger_send */

JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MAX_RECEIVE_SIZE < 126,
maximum_debug_message_receive_size_must_be_smaller_than_126);

/**
* Receive message from the client.
*
Expand All @@ -451,6 +452,8 @@ jerry_debugger_receive (void)

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)
{
Expand All @@ -468,22 +471,28 @@ jerry_debugger_receive (void)
return true;
}

if (expected_message_type != 0)
{
continue;
}

return resume_exec;
}

JERRY_CONTEXT (debugger_receive_buffer_offset) += (uint32_t) byte_recv;

if (JERRY_CONTEXT (debugger_receive_buffer_offset) < sizeof (jerry_debugger_receive_header_t))
{
if (expected_message_type != 0)
{
continue;
}

return resume_exec;
}

const size_t max_packet_size = JERRY_DEBUGGER_MAX_BUFFER_SIZE - sizeof (jerry_debugger_receive_header_t);

JERRY_ASSERT (max_packet_size < 126);

if ((recv_buffer_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT
|| (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) >= max_packet_size
|| (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRY_DEBUGGER_MAX_RECEIVE_SIZE
|| !(recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unsupported Websocket message.\n");
Expand All @@ -503,6 +512,11 @@ jerry_debugger_receive (void)

if (JERRY_CONTEXT (debugger_receive_buffer_offset) < message_total_size)
{
if (expected_message_type != 0)
{
continue;
}

return resume_exec;
}

Expand All @@ -526,9 +540,13 @@ jerry_debugger_receive (void)
}
}

/* The jerry_debugger_process_message function is inlined
* so passing these arguments is essentially free. */
if (!jerry_debugger_process_message (recv_buffer_p + sizeof (jerry_debugger_receive_header_t),
message_size,
&resume_exec))
&resume_exec,
&expected_message_type,
&message_data))
{
return true;
}
Expand Down
10 changes: 10 additions & 0 deletions jerry-core/debugger/jerry-debugger-ws.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@
*/
#define JERRY_DEBUGGER_MAX_BUFFER_SIZE 128

/**
* Maximum number of bytes can be received in a single message.
*/
#define JERRY_DEBUGGER_MAX_SEND_SIZE (JERRY_DEBUGGER_MAX_BUFFER_SIZE - 1)

/**
* Maximum number of bytes can be received in a single message.
*/
#define JERRY_DEBUGGER_MAX_RECEIVE_SIZE (JERRY_DEBUGGER_MAX_BUFFER_SIZE - 6)

/**
* Last fragment of a Websocket package.
*/
Expand Down
199 changes: 188 additions & 11 deletions jerry-core/debugger/jerry-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
* limitations under the License.
*/

#include "jerry-api.h"

#ifdef JERRY_DEBUGGER

#include "byte-code.h"
#include "ecma-conversion.h"
#include "ecma-eval.h"
#include "ecma-objects.h"
#include "jcontext.h"
#include "jerry-debugger.h"
#include "jerry-port.h"
Expand Down Expand Up @@ -87,7 +88,7 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece

while (frame_ctx_p != NULL && max_depth > 0)
{
if (current_frame >= JERRY_DEBUGGER_MAX_SIZE (jerry_debugger_frame_t))
if (current_frame >= JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t))
{
if (!jerry_debugger_send (sizeof (jerry_debugger_send_backtrace_t)))
{
Expand Down Expand Up @@ -118,6 +119,79 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
} /* jerry_debugger_send_backtrace */

/**
* Send result of evaluated expression.
*
* @return true - if no error is occured
* false - otherwise
*/
static bool
jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */
size_t eval_string_size) /**< evaluated string size */
{
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);

JERRY_CONTEXT (jerry_init_flags) &= (uint32_t) ~JERRY_INIT_DEBUGGER;
ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p, eval_string_size, true, false);
JERRY_CONTEXT (jerry_init_flags) |= (uint32_t) JERRY_INIT_DEBUGGER;

if (!ECMA_IS_VALUE_ERROR (result))
{
ecma_value_t to_string_value = ecma_op_to_string (result);
ecma_free_value (result);
result = to_string_value;
}

ecma_value_t message = result;
uint8_t type = JERRY_DEBUGGER_EVAL_RESULT;

if (ECMA_IS_VALUE_ERROR (result))
{
type = JERRY_DEBUGGER_EVAL_ERROR;

if (ecma_is_value_object (result))
{
ecma_string_t *message_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE);

message = ecma_op_object_find (ecma_get_object_from_value (result),
message_string_p);

ecma_deref_ecma_string (message_string_p);

if (!ecma_is_value_string (message)
|| ecma_string_is_empty (ecma_get_string_from_value (message)))
{
ecma_free_value (message);
lit_magic_string_id_t id = ecma_object_get_class_name (ecma_get_object_from_value (result));
ecma_free_value (result);

const lit_utf8_byte_t *string_p = lit_get_magic_string_utf8 (id);
return jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_ERROR,
string_p,
strlen ((const char *) string_p));
}
}
else
{
/* Primitve type. */
message = ecma_op_to_string (result);
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (message));
}

ecma_free_value (result);
}

ecma_string_t *string_p = ecma_get_string_from_value (message);

ECMA_STRING_TO_UTF8_STRING (string_p, buffer_p, buffer_size);
bool success = jerry_debugger_send_string (type, buffer_p, buffer_size);
ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size);

ecma_free_value (message);

return success;
} /* jerry_debugger_send_eval */

/**
* Check received packet size.
*/
Expand All @@ -138,9 +212,65 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece
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 */
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 */
{
/* Process the received message. */

if (*expected_message_type_p != 0)
{
JERRY_ASSERT (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART);

jerry_debugger_eval_data_t *eval_data_p = (jerry_debugger_eval_data_t *) *message_data_p;

if (recv_buffer_p[0] != JERRY_DEBUGGER_EVAL_PART)
{
jmem_heap_free_block (eval_data_p, eval_data_p->eval_size + sizeof (jerry_debugger_eval_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);

if (message_size < sizeof (jerry_debugger_receive_eval_part_t) + 1)
{
jmem_heap_free_block (eval_data_p, eval_data_p->eval_size + sizeof (jerry_debugger_eval_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;

message_size -= (uint32_t) sizeof (jerry_debugger_receive_eval_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));
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),
message_size);

if (message_size < expected_data)
{
eval_data_p->eval_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));
*expected_message_type_p = 0;
return result;
}

switch (recv_buffer_p[0])
{
case JERRY_DEBUGGER_FREE_BYTE_CODE_CP:
Expand Down Expand Up @@ -253,6 +383,50 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec
return true;
}

case JERRY_DEBUGGER_EVAL:
{
if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 1)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
jerry_debugger_close_connection ();
return false;
}

JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_eval_first_t, eval_first_p);

uint32_t eval_size;
memcpy (&eval_size, eval_first_p->eval_size, sizeof (uint32_t));

if (eval_size <= JERRY_DEBUGGER_MAX_RECEIVE_SIZE - sizeof (jerry_debugger_receive_eval_first_t))
{
if (eval_size != message_size - sizeof (jerry_debugger_receive_eval_first_t))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n");
jerry_debugger_close_connection ();
return false;
}

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;

eval_data_p = (jerry_debugger_eval_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));

lit_utf8_byte_t *eval_string_p = (lit_utf8_byte_t *) (eval_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;
*expected_message_type_p = JERRY_DEBUGGER_EVAL_PART;
return true;
}

default:
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message.");
Expand Down Expand Up @@ -355,7 +529,7 @@ jerry_debugger_send_data (jerry_debugger_header_type_t type, /**< message type *
const void *data, /**< raw data */
size_t size) /**< size of data */
{
JERRY_ASSERT (size < JERRY_DEBUGGER_MAX_SIZE (uint8_t));
JERRY_ASSERT (size <= JERRY_DEBUGGER_SEND_MAX (uint8_t));

JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p);

Expand All @@ -369,15 +543,18 @@ jerry_debugger_send_data (jerry_debugger_header_type_t type, /**< message type *

/**
* Send string to the debugger client.
*
* @return true - if the data sent successfully to the debugger client,
* false - otherwise
*/
void
bool
jerry_debugger_send_string (uint8_t message_type, /**< message type */
const jerry_char_t *string_p, /**< string data */
const uint8_t *string_p, /**< string data */
size_t string_length) /**< length of string */
{
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);

const size_t max_fragment_len = JERRY_DEBUGGER_MAX_SIZE (char);
const size_t max_fragment_len = JERRY_DEBUGGER_SEND_MAX (uint8_t);

JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p);

Expand All @@ -391,7 +568,7 @@ jerry_debugger_send_string (uint8_t message_type, /**< message type */

if (!jerry_debugger_send (sizeof (jerry_debugger_send_string_t)))
{
return;
return false;
}

string_length -= max_fragment_len;
Expand All @@ -403,14 +580,14 @@ jerry_debugger_send_string (uint8_t message_type, /**< message type */

memcpy (message_string_p->string, string_p, string_length);

jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length);
return jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length);
} /* jerry_debugger_send_string */

/**
* Send the function name to the debugger client.
*/
void
jerry_debugger_send_function_name (const jerry_char_t *function_name_p, /**< function name */
jerry_debugger_send_function_name (const uint8_t *function_name_p, /**< function name */
size_t function_name_length) /**< length of function name */
{
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
Expand Down
Loading