/** * Send backtrace. */ static void jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer to 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); backtrace_p->type = JERRY_DEBUGGER_BACKTRACE; vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); size_t current_frame = 0; const size_t max_frame_count = JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t); const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_frame_count, jerry_debugger_frame_t); 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 >= max_frame_count) { if (!jerry_debugger_send (max_message_size)) { 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); backtrace_p->type = JERRY_DEBUGGER_BACKTRACE_END; jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size); } /* jerry_debugger_send_backtrace */
/** * 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); 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 */
/** * 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); 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_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE, JERRY_DEBUGGER_VM_EXCEPTION_THROWN); jerry_debugger_uint8_data_t *uint8_data = NULL; while (!jerry_debugger_receive (&uint8_data)) { jerry_debugger_sleep (); } if (uint8_data != NULL) { jmem_heap_free_block (uint8_data, uint8_data->uint8_size + sizeof (jerry_debugger_uint8_data_t)); } JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE); JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; } /* jerry_debugger_breakpoint_hit */
/** * Decrease reference counter of Compact * Byte Code or regexp byte code. */ void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ { JERRY_ASSERT (bytecode_p->refs > 0); bytecode_p->refs--; if (bytecode_p->refs > 0) { /* Non-zero reference counter. */ return; } if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) { jmem_cpointer_t *literal_start_p = NULL; uint32_t literal_end; uint32_t const_literal_end; if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { uint8_t *byte_p = (uint8_t *) bytecode_p; literal_start_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t)); cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_p; literal_end = args_p->literal_end; const_literal_end = args_p->const_literal_end; } else { uint8_t *byte_p = (uint8_t *) bytecode_p; literal_start_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t)); cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_p; literal_end = args_p->literal_end; const_literal_end = args_p->const_literal_end; } for (uint32_t i = const_literal_end; i < literal_end; i++) { jmem_cpointer_t bytecode_cpointer = literal_start_p[i]; ecma_compiled_code_t *bytecode_literal_p = ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, bytecode_cpointer); /* Self references are ignored. */ if (bytecode_literal_p != bytecode_p) { ecma_bytecode_deref (bytecode_literal_p); } } #ifdef JERRY_DEBUGGER if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(bytecode_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE) && jerry_debugger_send_function_cp (JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP, bytecode_p)) { /* Delay the byte code free until the debugger client is notified. * If the connection is aborted the pointer is still freed by * jerry_debugger_close_connection(). */ jerry_debugger_byte_code_free_t *byte_code_free_p = (jerry_debugger_byte_code_free_t *) bytecode_p; jmem_cpointer_t byte_code_free_head = JERRY_CONTEXT (debugger_byte_code_free_head); byte_code_free_p->prev_cp = ECMA_NULL_POINTER; jmem_cpointer_t byte_code_free_cp; JMEM_CP_SET_NON_NULL_POINTER (byte_code_free_cp, byte_code_free_p); if (byte_code_free_head == ECMA_NULL_POINTER) { JERRY_CONTEXT (debugger_byte_code_free_tail) = byte_code_free_cp; } else { jerry_debugger_byte_code_free_t *first_byte_code_free_p; first_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t, byte_code_free_head); first_byte_code_free_p->prev_cp = byte_code_free_cp; } JERRY_CONTEXT (debugger_byte_code_free_head) = byte_code_free_cp; return; } #endif /* JERRY_DEBUGGER */ #ifdef JMEM_STATS jmem_stats_free_byte_code_bytes (((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG); #endif /* JMEM_STATS */ } else { #ifndef CONFIG_DISABLE_REGEXP_BUILTIN re_compiled_code_t *re_bytecode_p = (re_compiled_code_t *) bytecode_p; ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (ecma_string_t, re_bytecode_p->pattern_cp)); #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ } jmem_heap_free_block (bytecode_p, ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG); } /* ecma_bytecode_deref */