aboutsummaryrefslogtreecommitdiff
path: root/jerry-core
diff options
context:
space:
mode:
Diffstat (limited to 'jerry-core')
-rw-r--r--jerry-core/debugger/debugger.c277
-rw-r--r--jerry-core/debugger/debugger.h54
2 files changed, 325 insertions, 6 deletions
diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c
index 3f9ed5b4..ef524702 100644
--- a/jerry-core/debugger/debugger.c
+++ b/jerry-core/debugger/debugger.c
@@ -18,6 +18,7 @@
#include "ecma-builtin-helpers.h"
#include "ecma-conversion.h"
#include "ecma-eval.h"
+#include "ecma-function-object.h"
#include "ecma-objects.h"
#include "jcontext.h"
#include "jerryscript-port.h"
@@ -37,9 +38,9 @@ typedef struct
* The number of message types in the debugger should reflect the
* debugger versioning.
*/
-JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 28
- && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19
- && JERRY_DEBUGGER_VERSION == 6,
+JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 31
+ && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
+ && JERRY_DEBUGGER_VERSION == 7,
debugger_version_correlates_to_message_type_count);
/**
@@ -195,6 +196,258 @@ jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
} /* jerry_debugger_send_backtrace */
+
+/**
+ * Send the scope chain.
+ */
+static void
+jerry_debugger_send_scope_chain (void)
+{
+ vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
+
+ size_t count = 0;
+ const size_t send_max = JERRY_DEBUGGER_SEND_MAX (uint8_t);
+ bool prev_is_object_bound = false;
+
+ uint8_t scope_types[send_max];
+
+ for (ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
+ lex_env_p != NULL;
+ lex_env_p = ecma_get_lex_env_outer_reference(lex_env_p))
+ {
+ if (ecma_is_lexical_environment (lex_env_p))
+ {
+ if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
+ {
+ if (count == 0 || prev_is_object_bound)
+ {
+ scope_types[count++] = JERRY_DEBUGGER_SCOPE_LOCAL;
+ }
+ else {
+ scope_types[count++] = JERRY_DEBUGGER_SCOPE_CLOSURE;
+ }
+
+ prev_is_object_bound = false;
+ }
+ else
+ {
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ if (ecma_get_lex_env_outer_reference(lex_env_p) == NULL)
+ {
+ scope_types[count++] = JERRY_DEBUGGER_SCOPE_GLOBAL;
+ }
+ else {
+ scope_types[count++] = JERRY_DEBUGGER_SCOPE_WITH;
+ prev_is_object_bound = true;
+ }
+ }
+ }
+ }
+
+ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_type_p);
+
+ message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN;
+ memcpy (message_type_p->string, scope_types, count);
+
+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + count);
+
+} /* jerry_debugger_send_scope_chain */
+
+static jerry_debugger_scope_variable_type_t
+ecma_get_typeof_scope_variable (ecma_value_t value) /**< input ecma value */
+{
+ jerry_debugger_scope_variable_type_t ret_value = JERRY_DEBUGGER_VARIABLE_NONE;
+
+ if (ecma_is_value_undefined (value))
+ {
+ ret_value = JERRY_DEBUGGER_VARIABLE_UNDEFINED;
+ }
+ else if (ecma_is_value_null (value))
+ {
+ ret_value = JERRY_DEBUGGER_VARIABLE_OBJECT;
+ }
+ else if (ecma_is_value_boolean (value))
+ {
+ ret_value = JERRY_DEBUGGER_VARIABLE_BOOLEAN;
+ }
+ else if (ecma_is_value_number (value))
+ {
+ ret_value = JERRY_DEBUGGER_VARIABLE_NUMBER;
+ }
+ else if (ecma_is_value_string (value))
+ {
+ ret_value = JERRY_DEBUGGER_VARIABLE_STRING;
+ }
+ else
+ {
+ JERRY_ASSERT (ecma_is_value_object (value));
+
+ if (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL)
+ {
+ ret_value = JERRY_DEBUGGER_VARIABLE_ARRAY;
+ }
+ else
+ {
+ ret_value = ecma_op_is_callable (value) ? JERRY_DEBUGGER_VARIABLE_FUNCTION : JERRY_DEBUGGER_VARIABLE_OBJECT;
+ }
+ }
+
+ JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VARIABLE_NONE);
+
+ return ret_value;
+} /* ecma_get_typeof_scope_variable */
+
+static bool
+copy_value_to_string_message (jerry_debugger_scope_variable_type_t variable_type,
+ ecma_string_t *value_str,
+ jerry_debugger_send_string_t *message_string_p,
+ size_t *curr_msg_length)
+{
+ const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t);
+ const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t);
+
+ if (*curr_msg_length == max_byte_count)
+ {
+ if (!jerry_debugger_send (max_message_size))
+ {
+ return false;
+ }
+ }
+
+ if (variable_type != JERRY_DEBUGGER_VARIABLE_NONE)
+ {
+ uint8_t type_value = (uint8_t) variable_type;
+ memcpy (message_string_p->string + *curr_msg_length, &type_value, 1);
+ *curr_msg_length += 1;
+ }
+
+ ECMA_STRING_TO_UTF8_STRING (value_str, str_buff, str_buff_size);
+
+ if (*curr_msg_length == max_byte_count)
+ {
+ if (!jerry_debugger_send (max_message_size))
+ {
+ return false;
+ }
+ }
+
+ uint8_t str_size = (uint8_t) str_buff_size;
+ memcpy (message_string_p->string + *curr_msg_length, &str_size, 1);
+ *curr_msg_length += 1;
+
+ size_t free_bytes = max_byte_count - *curr_msg_length;
+ const uint8_t* string_p = str_buff;
+ size_t remained_size = str_buff_size;
+
+ while (remained_size > free_bytes)
+ {
+ memcpy (message_string_p->string + *curr_msg_length, string_p, free_bytes);
+
+ if (!jerry_debugger_send (max_message_size))
+ {
+ ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
+
+ return false;
+ }
+
+ string_p += free_bytes;
+ remained_size -= free_bytes;
+ free_bytes = max_byte_count;
+ *curr_msg_length = 0;
+ }
+
+ memcpy (message_string_p->string + *curr_msg_length, string_p, remained_size);
+ *curr_msg_length += remained_size;
+
+ ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
+
+ return true;
+} /* copy_value_to_string_message */
+
+static void
+jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p)
+{
+ JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_scope_variables_t, get_scope_variables_p);
+
+ uint32_t chain_index;
+ memcpy (&chain_index, get_scope_variables_p->chain_index, sizeof (uint32_t));
+
+ vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
+ ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
+
+ while (chain_index != 0)
+ {
+ lex_env_p = ecma_get_lex_env_outer_reference(lex_env_p);
+
+ if (lex_env_p == NULL)
+ {
+ jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END);
+ return;
+ }
+ chain_index--;
+ }
+
+ ecma_property_header_t* prop_iter_p;
+
+ if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) {
+ prop_iter_p = ecma_get_property_list (lex_env_p);
+ }
+ else {
+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
+ ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
+ prop_iter_p = ecma_get_property_list (binding_obj_p);
+ }
+
+ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p);
+
+ message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES;
+ size_t string_length = 0;
+
+ while (prop_iter_p != NULL)
+ {
+ JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
+
+ ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
+
+
+ for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
+ {
+ if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i]))
+ {
+ ecma_string_t* prop_name = ecma_string_from_property_name (prop_iter_p->types[i],
+ prop_pair_p->names_cp[i]);
+
+ if (!copy_value_to_string_message (JERRY_DEBUGGER_VARIABLE_NONE,
+ prop_name,
+ message_string_p,
+ &string_length))
+ {
+ return;
+ }
+
+ ecma_property_value_t prop_value_p = prop_pair_p->values[i];
+ ecma_value_t final_str = ecma_op_to_string (prop_value_p.value);
+
+ if (!copy_value_to_string_message (ecma_get_typeof_scope_variable (prop_value_p.value),
+ ecma_get_string_from_value (final_str),
+ message_string_p,
+ &string_length))
+ {
+ return;
+ }
+
+ ecma_free_value (final_str);
+ }
+ }
+
+ prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
+ prop_iter_p->next_property_cp);
+ }
+
+ message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES_END;
+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length);
+} /* jerry_debugger_send_scope_variables */
+
/**
* Send result of evaluated expression or throw an error.
*
@@ -525,6 +778,24 @@ jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to th
return true;
}
+ case JERRY_DEBUGGER_GET_SCOPE_CHAIN:
+ {
+ JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
+
+ jerry_debugger_send_scope_chain ();
+
+ return true;
+ }
+
+ case JERRY_DEBUGGER_GET_SCOPE_VARIABLES:
+ {
+ JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t);
+
+ jerry_debugger_send_scope_variables (recv_buffer_p);
+
+ return true;
+ }
+
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
{
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);
diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h
index 5b1db984..11caadcd 100644
--- a/jerry-core/debugger/debugger.h
+++ b/jerry-core/debugger/debugger.h
@@ -26,7 +26,7 @@
/**
* JerryScript debugger protocol version.
*/
-#define JERRY_DEBUGGER_VERSION (6)
+#define JERRY_DEBUGGER_VERSION (7)
/**
* Frequency of calling jerry_debugger_receive() by the VM.
@@ -157,7 +157,9 @@ typedef enum
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 25, /**< engine waiting for source code */
JERRY_DEBUGGER_OUTPUT_RESULT = 26, /**< output sent by the program to the debugger */
JERRY_DEBUGGER_OUTPUT_RESULT_END = 27, /**< last output result data */
-
+ JERRY_DEBUGGER_SCOPE_CHAIN = 28,
+ JERRY_DEBUGGER_SCOPE_VARIABLES = 29,
+ JERRY_DEBUGGER_SCOPE_VARIABLES_END = 30,
JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */
/* Messages sent by the client to server. */
@@ -187,7 +189,8 @@ typedef enum
JERRY_DEBUGGER_GET_BACKTRACE = 16, /**< get backtrace */
JERRY_DEBUGGER_EVAL = 17, /**< first message of evaluating a string */
JERRY_DEBUGGER_EVAL_PART = 18, /**< next message of evaluating a string */
-
+ JERRY_DEBUGGER_GET_SCOPE_CHAIN = 19, /**< get the lex env names from the scope chain */
+ JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20,
JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */
} jerry_debugger_header_type_t;
@@ -235,6 +238,33 @@ typedef enum
} jerry_debugger_output_subtype_t;
/**
+ * Types of scope chain.
+ *
+ */
+typedef enum
+{
+ JERRY_DEBUGGER_SCOPE_WITH = 1, /**< with */
+ JERRY_DEBUGGER_SCOPE_LOCAL = 2, /**< local */
+ JERRY_DEBUGGER_SCOPE_CLOSURE = 3, /**< closure */
+ JERRY_DEBUGGER_SCOPE_GLOBAL = 4, /**< global */
+ JERRY_DEBUGGER_SCOPE_CATCH = 5
+} jerry_debugger_scope_chain_type_t;
+
+
+typedef enum
+{
+ JERRY_DEBUGGER_VARIABLE_NONE = 1,
+ JERRY_DEBUGGER_VARIABLE_UNDEFINED = 2,
+ JERRY_DEBUGGER_VARIABLE_NULL = 3,
+ JERRY_DEBUGGER_VARIABLE_BOOLEAN = 4,
+ JERRY_DEBUGGER_VARIABLE_NUMBER = 5,
+ JERRY_DEBUGGER_VARIABLE_STRING = 6,
+ JERRY_DEBUGGER_VARIABLE_FUNCTION = 7,
+ JERRY_DEBUGGER_VARIABLE_ARRAY = 8,
+ JERRY_DEBUGGER_VARIABLE_OBJECT = 9
+} jerry_debugger_scope_variable_type_t;
+
+/**
* Byte data for evaluating expressions and receiving client source.
*/
typedef struct
@@ -370,6 +400,15 @@ typedef struct
} jerry_debugger_send_backtrace_t;
/**
+ * Outgoing message: scope chain information.
+ */
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+ uint8_t chain_types[]; /**< scope chain types */
+} jerry_debugger_send_scope_chain_t;
+
+/**
* Outgoing message: number of total frames in backtrace.
*/
typedef struct
@@ -417,6 +456,15 @@ typedef struct
} jerry_debugger_receive_eval_first_t;
/**
+ * Incoming message: get scope variables
+*/
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+ uint8_t chain_index[sizeof (uint32_t)]; /**< index element of the scope */
+} jerry_debugger_receive_get_scope_variables_t;
+
+/**
* Incoming message: first message of client source.
*/
typedef struct