diff options
Diffstat (limited to 'jerry-core')
-rw-r--r-- | jerry-core/debugger/debugger.c | 277 | ||||
-rw-r--r-- | jerry-core/debugger/debugger.h | 54 |
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 |