mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Without the file renaming there are two jerry-debugger.c files. Thus when the jerry-core archive is created there are two objects in it with the same name. Generally this does not create any problems. However if the archive is extracted then the second object file will overwrite the first one which results in undefined reference linkage error. The jerry- prefix was removed from the file names and fixed the include oreders where it was needed. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
868 lines
29 KiB
C
868 lines
29 KiB
C
/* 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.
|
|
*/
|
|
|
|
#include "byte-code.h"
|
|
#include "debugger.h"
|
|
#include "ecma-builtin-helpers.h"
|
|
#include "ecma-conversion.h"
|
|
#include "ecma-eval.h"
|
|
#include "ecma-objects.h"
|
|
#include "jcontext.h"
|
|
#include "jerryscript-port.h"
|
|
#include "lit-char-helpers.h"
|
|
|
|
#ifdef JERRY_DEBUGGER
|
|
|
|
/**
|
|
* Type cast the debugger send buffer into a specific type.
|
|
*/
|
|
#define JERRY_DEBUGGER_SEND_BUFFER_AS(type, name_p) \
|
|
type *name_p = (type *) (&JERRY_CONTEXT (debugger_send_buffer))
|
|
|
|
/**
|
|
* Type cast the debugger receive buffer into a specific type.
|
|
*/
|
|
#define JERRY_DEBUGGER_RECEIVE_BUFFER_AS(type, name_p) \
|
|
type *name_p = ((type *) recv_buffer_p)
|
|
|
|
/**
|
|
* Free all unreferenced byte code structures which
|
|
* were not acknowledged by the debugger client.
|
|
*/
|
|
void
|
|
jerry_debugger_free_unreferenced_byte_code (void)
|
|
{
|
|
jerry_debugger_byte_code_free_t *byte_code_free_p;
|
|
|
|
byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t,
|
|
JERRY_CONTEXT (debugger_byte_code_free_tail));
|
|
|
|
while (byte_code_free_p != NULL)
|
|
{
|
|
jerry_debugger_byte_code_free_t *prev_byte_code_free_p;
|
|
prev_byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t,
|
|
byte_code_free_p->prev_cp);
|
|
|
|
jmem_heap_free_block (byte_code_free_p,
|
|
((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG);
|
|
|
|
byte_code_free_p = prev_byte_code_free_p;
|
|
}
|
|
} /* jerry_debugger_free_unreferenced_byte_code */
|
|
|
|
/**
|
|
* Send backtrace.
|
|
*/
|
|
static void
|
|
jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the received data */
|
|
{
|
|
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_backtrace_t, get_backtrace_p);
|
|
|
|
uint32_t max_depth;
|
|
memcpy (&max_depth, get_backtrace_p->max_depth, sizeof (uint32_t));
|
|
|
|
if (max_depth == 0)
|
|
{
|
|
max_depth = UINT32_MAX;
|
|
}
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_t, backtrace_p);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (backtrace_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (backtrace_p, jerry_debugger_send_backtrace_t);
|
|
backtrace_p->type = JERRY_DEBUGGER_BACKTRACE;
|
|
|
|
vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
|
|
|
|
uint32_t current_frame = 0;
|
|
|
|
while (frame_ctx_p != NULL && max_depth > 0)
|
|
{
|
|
if (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
|
|
{
|
|
frame_ctx_p = frame_ctx_p->prev_context_p;
|
|
continue;
|
|
}
|
|
|
|
if (current_frame >= JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t))
|
|
{
|
|
if (!jerry_debugger_send (sizeof (jerry_debugger_send_backtrace_t)))
|
|
{
|
|
return;
|
|
}
|
|
current_frame = 0;
|
|
}
|
|
|
|
jerry_debugger_frame_t *frame_p = backtrace_p->frames + current_frame;
|
|
|
|
jmem_cpointer_t byte_code_cp;
|
|
JMEM_CP_SET_NON_NULL_POINTER (byte_code_cp, frame_ctx_p->bytecode_header_p);
|
|
memcpy (frame_p->byte_code_cp, &byte_code_cp, sizeof (jmem_cpointer_t));
|
|
|
|
uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->bytecode_header_p);
|
|
memcpy (frame_p->offset, &offset, sizeof (uint32_t));
|
|
|
|
frame_ctx_p = frame_ctx_p->prev_context_p;
|
|
current_frame++;
|
|
max_depth--;
|
|
}
|
|
|
|
size_t message_size = current_frame * sizeof (jerry_debugger_frame_t);
|
|
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (backtrace_p, 1 + message_size);
|
|
backtrace_p->type = JERRY_DEBUGGER_BACKTRACE_END;
|
|
|
|
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 (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE));
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_IGNORE);
|
|
ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p, eval_string_size, true, false);
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_IGNORE);
|
|
|
|
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.
|
|
*/
|
|
#define JERRY_DEBUGGER_CHECK_PACKET_SIZE(type) \
|
|
if (message_size != sizeof (type)) \
|
|
{ \
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n"); \
|
|
jerry_debugger_close_connection (); \
|
|
return false; \
|
|
}
|
|
|
|
/**
|
|
* Receive message from the client.
|
|
*
|
|
* @return true - if message is processed successfully
|
|
* false - otherwise
|
|
*/
|
|
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 */
|
|
{
|
|
/* Process the received message. */
|
|
|
|
if (recv_buffer_p[0] >= JERRY_DEBUGGER_CONTINUE
|
|
&& !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Message requires breakpoint mode\n");
|
|
jerry_debugger_close_connection ();
|
|
return false;
|
|
}
|
|
|
|
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:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_byte_code_cp_t);
|
|
|
|
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_byte_code_cp_t, byte_code_p);
|
|
|
|
jmem_cpointer_t byte_code_free_cp;
|
|
memcpy (&byte_code_free_cp, byte_code_p->byte_code_cp, sizeof (jmem_cpointer_t));
|
|
|
|
if (byte_code_free_cp != JERRY_CONTEXT (debugger_byte_code_free_tail))
|
|
{
|
|
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid byte code free order\n");
|
|
jerry_debugger_close_connection ();
|
|
return false;
|
|
}
|
|
|
|
jerry_debugger_byte_code_free_t *byte_code_free_p;
|
|
byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
|
|
byte_code_free_cp);
|
|
|
|
if (byte_code_free_p->prev_cp != ECMA_NULL_POINTER)
|
|
{
|
|
JERRY_CONTEXT (debugger_byte_code_free_tail) = byte_code_free_p->prev_cp;
|
|
}
|
|
else
|
|
{
|
|
JERRY_CONTEXT (debugger_byte_code_free_head) = ECMA_NULL_POINTER;
|
|
JERRY_CONTEXT (debugger_byte_code_free_tail) = ECMA_NULL_POINTER;
|
|
}
|
|
|
|
#ifdef JMEM_STATS
|
|
jmem_stats_free_byte_code_bytes (((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG);
|
|
#endif /* JMEM_STATS */
|
|
|
|
jmem_heap_free_block (byte_code_free_p,
|
|
((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG);
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_UPDATE_BREAKPOINT:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_update_breakpoint_t);
|
|
|
|
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_update_breakpoint_t, update_breakpoint_p);
|
|
|
|
jmem_cpointer_t byte_code_cp;
|
|
memcpy (&byte_code_cp, update_breakpoint_p->byte_code_cp, sizeof (jmem_cpointer_t));
|
|
uint8_t *byte_code_p = JMEM_CP_GET_NON_NULL_POINTER (uint8_t, byte_code_cp);
|
|
|
|
uint32_t offset;
|
|
memcpy (&offset, update_breakpoint_p->offset, sizeof (uint32_t));
|
|
byte_code_p += offset;
|
|
|
|
JERRY_ASSERT (*byte_code_p == CBC_BREAKPOINT_ENABLED || *byte_code_p == CBC_BREAKPOINT_DISABLED);
|
|
|
|
*byte_code_p = update_breakpoint_p->is_set_breakpoint ? CBC_BREAKPOINT_ENABLED : CBC_BREAKPOINT_DISABLED;
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_MEMSTATS:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
|
|
|
jerry_debugger_send_memstats ();
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_STOP:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP);
|
|
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
|
*resume_exec_p = false;
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_CONTINUE:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_STOP);
|
|
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
|
*resume_exec_p = true;
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_STEP:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP);
|
|
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
|
*resume_exec_p = true;
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_NEXT:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP);
|
|
JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p);
|
|
*resume_exec_p = true;
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_GET_BACKTRACE:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_backtrace_t);
|
|
|
|
jerry_debugger_send_backtrace (recv_buffer_p);
|
|
return true;
|
|
}
|
|
|
|
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
|
|
{
|
|
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);
|
|
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_exception_config_t, exception_config_p);
|
|
|
|
uint8_t debugger_flags = JERRY_CONTEXT (debugger_flags);
|
|
|
|
if (exception_config_p->enable == 0)
|
|
{
|
|
debugger_flags = (uint8_t) (debugger_flags | JERRY_DEBUGGER_VM_IGNORE_EXCEPTION);
|
|
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception disabled\n");
|
|
}
|
|
else
|
|
{
|
|
debugger_flags = (uint8_t) (debugger_flags & ~JERRY_DEBUGGER_VM_IGNORE_EXCEPTION);
|
|
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception enabled\n");
|
|
}
|
|
|
|
JERRY_CONTEXT (debugger_flags) = debugger_flags;
|
|
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.");
|
|
jerry_debugger_close_connection ();
|
|
return false;
|
|
}
|
|
}
|
|
} /* jerry_debugger_process_message */
|
|
|
|
#undef JERRY_DEBUGGER_CHECK_PACKET_SIZE
|
|
|
|
/**
|
|
* Tell the client that a breakpoint has been hit and wait for further debugger commands.
|
|
*/
|
|
void
|
|
jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_breakpoint_hit_t, breakpoint_hit_p);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (breakpoint_hit_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (breakpoint_hit_p, jerry_debugger_send_breakpoint_hit_t);
|
|
breakpoint_hit_p->type = message_type;
|
|
|
|
vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
|
|
|
|
jmem_cpointer_t byte_code_header_cp;
|
|
JMEM_CP_SET_NON_NULL_POINTER (byte_code_header_cp, frame_ctx_p->bytecode_header_p);
|
|
memcpy (breakpoint_hit_p->byte_code_cp, &byte_code_header_cp, sizeof (jmem_cpointer_t));
|
|
|
|
uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->bytecode_header_p);
|
|
memcpy (breakpoint_hit_p->offset, &offset, sizeof (uint32_t));
|
|
|
|
if (!jerry_debugger_send (sizeof (jerry_debugger_send_breakpoint_hit_t)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_BREAKPOINT_MODE);
|
|
|
|
while (!jerry_debugger_receive ())
|
|
{
|
|
}
|
|
|
|
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_BREAKPOINT_MODE);
|
|
|
|
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
|
|
} /* jerry_debugger_breakpoint_hit */
|
|
|
|
/**
|
|
* Send the type signal to the client.
|
|
*/
|
|
void
|
|
jerry_debugger_send_type (jerry_debugger_header_type_t type) /**< message type */
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_type_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_type_p, jerry_debugger_send_type_t);
|
|
message_type_p->type = (uint8_t) type;
|
|
|
|
jerry_debugger_send (sizeof (jerry_debugger_send_type_t));
|
|
} /* jerry_debugger_send_type */
|
|
|
|
|
|
/**
|
|
* Send the type signal to the client.
|
|
*
|
|
* @return true - if the data sent successfully to the debugger client,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_debugger_send_configuration (uint8_t max_message_size) /**< maximum message size */
|
|
{
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_configuration_t, configuration_p);
|
|
|
|
/* Helper structure for endianness check. */
|
|
union
|
|
{
|
|
uint16_t uint16_value; /**< a 16-bit value */
|
|
uint8_t uint8_value[2]; /**< lower and upper byte of a 16-bit value */
|
|
} endian_data;
|
|
|
|
endian_data.uint16_value = 1;
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (configuration_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (configuration_p, jerry_debugger_send_configuration_t);
|
|
configuration_p->type = JERRY_DEBUGGER_CONFIGURATION;
|
|
configuration_p->max_message_size = max_message_size;
|
|
configuration_p->cpointer_size = sizeof (jmem_cpointer_t);
|
|
configuration_p->little_endian = (endian_data.uint8_value[0] == 1);
|
|
|
|
return jerry_debugger_send (sizeof (jerry_debugger_send_configuration_t));
|
|
} /* jerry_debugger_send_configuration */
|
|
|
|
/**
|
|
* Send raw data to the debugger client.
|
|
*/
|
|
void
|
|
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_SEND_MAX (uint8_t));
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_type_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (message_type_p, 1 + size);
|
|
message_type_p->type = type;
|
|
memcpy (message_type_p + 1, data, size);
|
|
|
|
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + size);
|
|
} /* jerry_debugger_send_data */
|
|
|
|
/**
|
|
* Send string to the debugger client.
|
|
*
|
|
* @return true - if the data sent successfully to the debugger client,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_debugger_send_string (uint8_t message_type, /**< message type */
|
|
const uint8_t *string_p, /**< string data */
|
|
size_t string_length) /**< length of string */
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
|
|
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);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_string_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_string_p, jerry_debugger_send_string_t);
|
|
message_string_p->type = message_type;
|
|
|
|
while (string_length > max_fragment_len)
|
|
{
|
|
memcpy (message_string_p->string, string_p, max_fragment_len);
|
|
|
|
if (!jerry_debugger_send (sizeof (jerry_debugger_send_string_t)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string_length -= max_fragment_len;
|
|
string_p += max_fragment_len;
|
|
}
|
|
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (message_string_p, 1 + string_length);
|
|
message_string_p->type = (uint8_t) (message_type + 1);
|
|
|
|
memcpy (message_string_p->string, string_p, string_length);
|
|
|
|
return jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length);
|
|
} /* jerry_debugger_send_string */
|
|
|
|
/**
|
|
* Send the function compressed pointer to the debugger client.
|
|
*
|
|
* @return true - if the data was sent successfully to the debugger client,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, /**< message type */
|
|
ecma_compiled_code_t *compiled_code_p) /**< byte code pointer */
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_byte_code_cp_t, byte_code_cp_p);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (byte_code_cp_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (byte_code_cp_p, jerry_debugger_send_byte_code_cp_t);
|
|
byte_code_cp_p->type = (uint8_t) type;
|
|
|
|
jmem_cpointer_t compiled_code_cp;
|
|
JMEM_CP_SET_NON_NULL_POINTER (compiled_code_cp, compiled_code_p);
|
|
memcpy (byte_code_cp_p->byte_code_cp, &compiled_code_cp, sizeof (jmem_cpointer_t));
|
|
|
|
return jerry_debugger_send (sizeof (jerry_debugger_send_byte_code_cp_t));
|
|
} /* jerry_debugger_send_function_cp */
|
|
|
|
/**
|
|
* Send function data to the debugger client.
|
|
*
|
|
* @return true - if the data sent successfully to the debugger client,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_debugger_send_parse_function (uint32_t line, /**< line */
|
|
uint32_t column) /**< column */
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_parse_function_t, message_parse_function_p);
|
|
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_parse_function_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_parse_function_p, jerry_debugger_send_parse_function_t);
|
|
message_parse_function_p->type = JERRY_DEBUGGER_PARSE_FUNCTION;
|
|
memcpy (message_parse_function_p->line, &line, sizeof (uint32_t));
|
|
memcpy (message_parse_function_p->column, &column, sizeof (uint32_t));
|
|
|
|
return jerry_debugger_send (sizeof (jerry_debugger_send_parse_function_t));
|
|
} /* jerry_debugger_send_parse_function */
|
|
|
|
/**
|
|
* Send memory statistics to the debugger client.
|
|
*/
|
|
void
|
|
jerry_debugger_send_memstats (void)
|
|
{
|
|
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
|
|
|
|
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_memstats_t, memstats_p);
|
|
JERRY_DEBUGGER_INIT_SEND_MESSAGE (memstats_p);
|
|
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (memstats_p, jerry_debugger_send_memstats_t);
|
|
|
|
memstats_p->type = JERRY_DEBUGGER_MEMSTATS_RECEIVE;
|
|
|
|
#ifdef JMEM_STATS /* if jmem_stats are defined */
|
|
jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats);
|
|
|
|
uint32_t allocated_bytes = (uint32_t) heap_stats->allocated_bytes;
|
|
memcpy (memstats_p->allocated_bytes, &allocated_bytes, sizeof (uint32_t));
|
|
uint32_t byte_code_bytes = (uint32_t) heap_stats->byte_code_bytes;
|
|
memcpy (memstats_p->byte_code_bytes, &byte_code_bytes, sizeof (uint32_t));
|
|
uint32_t string_bytes = (uint32_t) heap_stats->string_bytes;
|
|
memcpy (memstats_p->string_bytes, &string_bytes, sizeof (uint32_t));
|
|
uint32_t object_bytes = (uint32_t) heap_stats->object_bytes;
|
|
memcpy (memstats_p->object_bytes, &object_bytes, sizeof (uint32_t));
|
|
uint32_t property_bytes = (uint32_t) heap_stats->property_bytes;
|
|
memcpy (memstats_p->property_bytes, &property_bytes, sizeof (uint32_t));
|
|
#else /* if not, just put zeros */
|
|
memset (memstats_p->allocated_bytes, 0, sizeof (uint32_t));
|
|
memset (memstats_p->byte_code_bytes, 0, sizeof (uint32_t));
|
|
memset (memstats_p->string_bytes, 0, sizeof (uint32_t));
|
|
memset (memstats_p->object_bytes, 0, sizeof (uint32_t));
|
|
memset (memstats_p->property_bytes, 0, sizeof (uint32_t));
|
|
#endif
|
|
|
|
jerry_debugger_send (sizeof (jerry_debugger_send_memstats_t));
|
|
} /* jerry_debugger_send_memstats */
|
|
|
|
/*
|
|
* Converts an standard error into a string.
|
|
*
|
|
* @return standard error string
|
|
*/
|
|
static ecma_string_t *
|
|
jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /**< exception object */
|
|
{
|
|
ecma_object_t *object_p = ecma_get_object_from_value (exception_obj_value);
|
|
|
|
ecma_object_t *prototype_p = ecma_get_object_prototype (object_p);
|
|
|
|
if (prototype_p == NULL
|
|
|| ecma_get_object_type (prototype_p) != ECMA_OBJECT_TYPE_GENERAL
|
|
|| !ecma_get_object_is_builtin (prototype_p))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
lit_magic_string_id_t string_id;
|
|
|
|
switch (((ecma_extended_object_t *) prototype_p)->u.built_in.id)
|
|
{
|
|
#ifndef CONFIG_DISABLE_ERROR_BUILTINS
|
|
case ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_EVAL_ERROR_UL;
|
|
break;
|
|
}
|
|
case ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_RANGE_ERROR_UL;
|
|
break;
|
|
}
|
|
case ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_REFERENCE_ERROR_UL;
|
|
break;
|
|
}
|
|
case ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_SYNTAX_ERROR_UL;
|
|
break;
|
|
}
|
|
case ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_TYPE_ERROR_UL;
|
|
break;
|
|
}
|
|
case ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_URI_ERROR_UL;
|
|
break;
|
|
}
|
|
#endif /* !CONFIG_DISABLE_ERROR_BUILTINS */
|
|
case ECMA_BUILTIN_ID_ERROR_PROTOTYPE:
|
|
{
|
|
string_id = LIT_MAGIC_STRING_ERROR_UL;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
lit_utf8_size_t size = lit_get_magic_string_size (string_id);
|
|
JERRY_ASSERT (size <= 14);
|
|
|
|
lit_utf8_byte_t data[16];
|
|
memcpy (data, lit_get_magic_string_utf8 (string_id), size);
|
|
|
|
ecma_string_t message_string;
|
|
ecma_init_ecma_magic_string (&message_string, LIT_MAGIC_STRING_MESSAGE);
|
|
|
|
ecma_property_t *property_p;
|
|
property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value),
|
|
&message_string);
|
|
|
|
if (property_p == NULL
|
|
|| ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA)
|
|
{
|
|
return ecma_new_ecma_string_from_utf8 (data, size);
|
|
}
|
|
|
|
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
|
|
|
|
if (!ecma_is_value_string (prop_value_p->value))
|
|
{
|
|
return ecma_new_ecma_string_from_utf8 (data, size);
|
|
}
|
|
|
|
data[size] = LIT_CHAR_COLON;
|
|
data[size + 1] = LIT_CHAR_SP;
|
|
|
|
ecma_string_t *type_string_p = ecma_new_ecma_string_from_utf8 (data, size + 2);
|
|
|
|
ecma_string_t *string_p = ecma_concat_ecma_strings (type_string_p,
|
|
ecma_get_string_from_value (prop_value_p->value));
|
|
ecma_deref_ecma_string (type_string_p);
|
|
return string_p;
|
|
} /* jerry_debugger_exception_object_to_string */
|
|
|
|
/**
|
|
* Send string representation of exception to the client.
|
|
*
|
|
* @return true - if the data sent successfully to the debugger client,
|
|
* false - otherwise
|
|
*/
|
|
bool
|
|
jerry_debugger_send_exception_string (ecma_value_t exception_value) /**< error value */
|
|
{
|
|
ecma_string_t *string_p = NULL;
|
|
|
|
if (ecma_is_value_object (exception_value))
|
|
{
|
|
ecma_value_t object_value = ecma_get_value_from_error_value (exception_value);
|
|
|
|
string_p = jerry_debugger_exception_object_to_string (object_value);
|
|
if (string_p == NULL)
|
|
{
|
|
string_p = ecma_get_string_from_value (ecma_builtin_helper_object_to_string (object_value));
|
|
}
|
|
}
|
|
else if (ecma_is_value_string (exception_value))
|
|
{
|
|
string_p = ecma_get_string_from_value (exception_value);
|
|
ecma_ref_ecma_string (string_p);
|
|
}
|
|
else
|
|
{
|
|
exception_value = ecma_op_to_string (exception_value);
|
|
string_p = ecma_get_string_from_value (exception_value);
|
|
}
|
|
|
|
ECMA_STRING_TO_UTF8_STRING (string_p, string_data_p, string_size);
|
|
|
|
bool result = jerry_debugger_send_string (JERRY_DEBUGGER_EXCEPTION_STR,
|
|
string_data_p,
|
|
string_size);
|
|
|
|
ECMA_FINALIZE_UTF8_STRING (string_data_p, string_size);
|
|
|
|
ecma_deref_ecma_string (string_p);
|
|
return result;
|
|
} /* jerry_debugger_send_exception_string */
|
|
|
|
#endif /* JERRY_DEBUGGER */
|