Add restart command to the debugger (#2401)
With this feature the use can restart the actual debug session (similar to the multiple source context reset) within a client. JerryScript-DCO-1.0-Signed-off-by: Imre Kiss kissi.szeged@partner.samsung.com
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 27
|
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 27
|
||||||
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19
|
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19
|
||||||
&& JERRY_DEBUGGER_VERSION == 3,
|
&& JERRY_DEBUGGER_VERSION == 4,
|
||||||
debugger_version_correlates_to_message_type_count);
|
debugger_version_correlates_to_message_type_count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
/**
|
/**
|
||||||
* JerryScript debugger protocol version.
|
* JerryScript debugger protocol version.
|
||||||
*/
|
*/
|
||||||
#define JERRY_DEBUGGER_VERSION (3)
|
#define JERRY_DEBUGGER_VERSION (4)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frequency of calling jerry_debugger_receive() by the VM.
|
* Frequency of calling jerry_debugger_receive() by the VM.
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import math
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
# Expected debugger protocol version.
|
# Expected debugger protocol version.
|
||||||
JERRY_DEBUGGER_VERSION = 3
|
JERRY_DEBUGGER_VERSION = 4
|
||||||
|
|
||||||
# Messages sent by the server to client.
|
# Messages sent by the server to client.
|
||||||
JERRY_DEBUGGER_CONFIGURATION = 1
|
JERRY_DEBUGGER_CONFIGURATION = 1
|
||||||
@@ -513,6 +513,12 @@ class DebuggerPrompt(Cmd):
|
|||||||
|
|
||||||
do_ms = do_memstats
|
do_ms = do_memstats
|
||||||
|
|
||||||
|
def do_restart(self, _):
|
||||||
|
""" Restart the engine's debug session """
|
||||||
|
self._send_string(JERRY_DEBUGGER_EVAL_ABORT + "\"r353t\"", JERRY_DEBUGGER_EVAL)
|
||||||
|
|
||||||
|
do_res = do_restart
|
||||||
|
|
||||||
def store_client_sources(self, args):
|
def store_client_sources(self, args):
|
||||||
self.client_sources = args
|
self.client_sources = args
|
||||||
|
|
||||||
|
|||||||
+138
-87
@@ -412,6 +412,25 @@ instance_alloc (size_t size,
|
|||||||
|
|
||||||
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
|
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits the engine and the debugger
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
init_engine (jerry_init_flag_t flags, /**< initialized flags for the engine */
|
||||||
|
bool debug_server, /**< enable the debugger init or not */
|
||||||
|
uint16_t debug_port) /**< the debugger port */
|
||||||
|
{
|
||||||
|
jerry_init (flags);
|
||||||
|
if (debug_server)
|
||||||
|
{
|
||||||
|
jerry_debugger_init (debug_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
register_js_function ("assert", jerryx_handler_assert);
|
||||||
|
register_js_function ("gc", jerryx_handler_gc);
|
||||||
|
register_js_function ("print", jerryx_handler_print);
|
||||||
|
} /* init_engine */
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char **argv)
|
char **argv)
|
||||||
@@ -591,15 +610,7 @@ main (int argc,
|
|||||||
|
|
||||||
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
|
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
|
||||||
|
|
||||||
jerry_init (flags);
|
init_engine (flags, start_debug_server, debug_port);
|
||||||
if (start_debug_server)
|
|
||||||
{
|
|
||||||
jerry_debugger_init (debug_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
register_js_function ("assert", jerryx_handler_assert);
|
|
||||||
register_js_function ("gc", jerryx_handler_gc);
|
|
||||||
register_js_function ("print", jerryx_handler_print);
|
|
||||||
|
|
||||||
jerry_value_t ret_value = jerry_create_undefined ();
|
jerry_value_t ret_value = jerry_create_undefined ();
|
||||||
|
|
||||||
@@ -629,99 +640,139 @@ main (int argc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!jerry_value_is_error (ret_value))
|
while (true)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < files_counter; i++)
|
|
||||||
|
if (!jerry_value_is_error (ret_value))
|
||||||
{
|
{
|
||||||
size_t source_size;
|
for (int i = 0; i < files_counter; i++)
|
||||||
const jerry_char_t *source_p = (jerry_char_t *) read_file (file_names[i], &source_size);
|
|
||||||
|
|
||||||
if (source_p == NULL)
|
|
||||||
{
|
{
|
||||||
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Source file load error");
|
size_t source_size;
|
||||||
break;
|
const jerry_char_t *source_p = (jerry_char_t *) read_file (file_names[i], &source_size);
|
||||||
}
|
|
||||||
|
|
||||||
if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_size))
|
if (source_p == NULL)
|
||||||
{
|
|
||||||
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) ("Input must be a valid UTF-8 string."));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret_value = jerry_parse ((jerry_char_t *) file_names[i],
|
|
||||||
strlen (file_names[i]),
|
|
||||||
source_p,
|
|
||||||
source_size,
|
|
||||||
JERRY_PARSE_NO_OPTS);
|
|
||||||
|
|
||||||
if (!jerry_value_is_error (ret_value) && !is_parse_only)
|
|
||||||
{
|
|
||||||
jerry_value_t func_val = ret_value;
|
|
||||||
ret_value = jerry_run (func_val);
|
|
||||||
jerry_release_value (func_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jerry_value_is_error (ret_value))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
jerry_release_value (ret_value);
|
|
||||||
ret_value = jerry_create_undefined ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_wait_mode)
|
|
||||||
{
|
|
||||||
is_repl_mode = false;
|
|
||||||
|
|
||||||
if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER))
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
jerry_debugger_wait_for_source_status_t receive_status;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
jerry_value_t run_result;
|
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Source file load error");
|
||||||
|
break;
|
||||||
receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback,
|
|
||||||
NULL,
|
|
||||||
&run_result);
|
|
||||||
|
|
||||||
if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
|
|
||||||
{
|
|
||||||
ret_value = jerry_create_error (JERRY_ERROR_COMMON,
|
|
||||||
(jerry_char_t *) "Connection aborted before source arrived.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (receive_status == JERRY_DEBUGGER_SOURCE_END)
|
|
||||||
{
|
|
||||||
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
jerry_release_value (run_result);
|
|
||||||
}
|
}
|
||||||
while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
|
|
||||||
|
|
||||||
if (receive_status != JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED)
|
if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_size))
|
||||||
|
{
|
||||||
|
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) ("Input must be a valid UTF-8 string."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_value = jerry_parse ((jerry_char_t *) file_names[i],
|
||||||
|
strlen (file_names[i]),
|
||||||
|
source_p,
|
||||||
|
source_size,
|
||||||
|
JERRY_PARSE_NO_OPTS);
|
||||||
|
|
||||||
|
if (!jerry_value_is_error (ret_value) && !is_parse_only)
|
||||||
|
{
|
||||||
|
jerry_value_t func_val = ret_value;
|
||||||
|
ret_value = jerry_run (func_val);
|
||||||
|
jerry_release_value (func_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jerry_value_is_error (ret_value))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
jerry_cleanup ();
|
jerry_release_value (ret_value);
|
||||||
|
|
||||||
jerry_init (flags);
|
|
||||||
jerry_debugger_init (debug_port);
|
|
||||||
|
|
||||||
register_js_function ("assert", jerryx_handler_assert);
|
|
||||||
register_js_function ("gc", jerryx_handler_gc);
|
|
||||||
register_js_function ("print", jerryx_handler_print);
|
|
||||||
|
|
||||||
ret_value = jerry_create_undefined ();
|
ret_value = jerry_create_undefined ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_wait_mode)
|
||||||
|
{
|
||||||
|
is_repl_mode = false;
|
||||||
|
|
||||||
|
if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER))
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
jerry_debugger_wait_for_source_status_t receive_status;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
jerry_value_t run_result;
|
||||||
|
|
||||||
|
receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback,
|
||||||
|
NULL,
|
||||||
|
&run_result);
|
||||||
|
|
||||||
|
if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
|
||||||
|
{
|
||||||
|
ret_value = jerry_create_error (JERRY_ERROR_COMMON,
|
||||||
|
(jerry_char_t *) "Connection aborted before source arrived.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receive_status == JERRY_DEBUGGER_SOURCE_END)
|
||||||
|
{
|
||||||
|
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jerry_value_is_abort (run_result))
|
||||||
|
{
|
||||||
|
ret_value = jerry_acquire_value (run_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (run_result);
|
||||||
|
}
|
||||||
|
while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
|
||||||
|
|
||||||
|
if (receive_status != JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_engine (flags, true, debug_port);
|
||||||
|
|
||||||
|
ret_value = jerry_create_undefined ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool restart = false;
|
||||||
|
|
||||||
|
if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER) && jerry_value_is_abort (ret_value))
|
||||||
|
{
|
||||||
|
jerry_value_t abort_value = jerry_get_value_from_error (ret_value, false);
|
||||||
|
if (jerry_value_is_string (abort_value))
|
||||||
|
{
|
||||||
|
jerry_char_t str_buf[5];
|
||||||
|
jerry_value_t str_val = jerry_value_to_string (abort_value);
|
||||||
|
jerry_size_t str_size = jerry_get_string_size (str_val);
|
||||||
|
|
||||||
|
if (str_size == 5)
|
||||||
|
{
|
||||||
|
jerry_string_to_char_buffer (str_val, str_buf, str_size);
|
||||||
|
if (memcmp ("r353t", (char *) (str_buf), 5) == 0)
|
||||||
|
{
|
||||||
|
jerry_release_value (ret_value);
|
||||||
|
restart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (str_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (abort_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!restart)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
|
||||||
|
init_engine (flags, true, debug_port);
|
||||||
|
|
||||||
|
ret_value = jerry_create_undefined ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_repl_mode)
|
if (is_repl_mode)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ Stopped at tests/debugger/do_help.js:15
|
|||||||
|
|
||||||
Documented commands (type help <topic>):
|
Documented commands (type help <topic>):
|
||||||
========================================
|
========================================
|
||||||
abort bt display exception list next source
|
abort bt display exception list next s step
|
||||||
b c dump f memstats quit src
|
b c dump f memstats quit scroll throw
|
||||||
backtrace continue e finish ms s step
|
backtrace continue e finish ms res source
|
||||||
break delete eval help n scroll throw
|
break delete eval help n restart src
|
||||||
|
|
||||||
(jerry-debugger) quit
|
(jerry-debugger) quit
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
n
|
||||||
|
n
|
||||||
|
n
|
||||||
|
restart
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
Connecting to: localhost:5001
|
||||||
|
Stopped at tests/debugger/do_restart.js:23
|
||||||
|
(jerry-debugger) n
|
||||||
|
Stopped at tests/debugger/do_restart.js:24
|
||||||
|
(jerry-debugger) n
|
||||||
|
out: foo
|
||||||
|
Stopped at tests/debugger/do_restart.js:25
|
||||||
|
(jerry-debugger) n
|
||||||
|
out: bar
|
||||||
|
Stopped at tests/debugger/do_restart.js:24
|
||||||
|
(jerry-debugger) restart
|
||||||
|
Connecting to: localhost:5001
|
||||||
|
Stopped at tests/debugger/do_restart.js:23
|
||||||
|
(jerry-debugger) continue
|
||||||
|
out: foo
|
||||||
|
out: bar
|
||||||
|
out: foo
|
||||||
|
out: bar
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
print("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
function bar() {
|
||||||
|
print("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 2; i++) {
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
@@ -37,6 +37,12 @@ sleep 1s
|
|||||||
RESULT_TEMP=`mktemp ${TEST_CASE}.out.XXXXXXXXXX`
|
RESULT_TEMP=`mktemp ${TEST_CASE}.out.XXXXXXXXXX`
|
||||||
|
|
||||||
(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) &> ${RESULT_TEMP}
|
(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) &> ${RESULT_TEMP}
|
||||||
|
|
||||||
|
if [[ $TEST_CASE == *"restart"* ]]; then
|
||||||
|
CONTINUE_CASE=$(sed "s/restart/continue/g" <<< "$TEST_CASE")
|
||||||
|
(cat "${CONTINUE_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive ${CLIENT_ARGS}) &>> ${RESULT_TEMP}
|
||||||
|
fi
|
||||||
|
|
||||||
diff -U0 ${TEST_CASE}.expected ${RESULT_TEMP}
|
diff -U0 ${TEST_CASE}.expected ${RESULT_TEMP}
|
||||||
STATUS_CODE=$?
|
STATUS_CODE=$?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user