Multiple client source sending feature. (#1957)

Whit this enhancement the debugger can able handle more than one source file across the new source wait mode.
This feature can be used by the python client with the --client-source [paths] switch.
The client will store every source path, when the debugger send a signal about the waiting status, then the client will send one file from the list.

JerryScript-DCO-1.0-Signed-off-by: Imre Kiss kissi.szeged@partner.samsung.com
This commit is contained in:
Imre Kiss
2017-08-21 09:19:36 +02:00
committed by László Langó
parent 2888a6f488
commit 3b1d578050
14 changed files with 197 additions and 42 deletions
+15 -7
View File
@@ -26,7 +26,7 @@ can be used for transmitting debugger messages.
The debugger client must be connected to the server before the The debugger client must be connected to the server before the
JavaScript application runs. On-the-fly attachment is supported JavaScript application runs. On-the-fly attachment is supported
for one file, right after of engine initialization for more than one file, right after of engine initialization
(this feature available with the python client). The debugging (this feature available with the python client). The debugging
information (e.g. line index of each possible -breakpoint location) information (e.g. line index of each possible -breakpoint location)
is not preserved by JerryScript. The client is expected to be run is not preserved by JerryScript. The client is expected to be run
@@ -208,7 +208,8 @@ jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint)
Stops the engine and puts that into a waiting loop. If the client send Stops the engine and puts that into a waiting loop. If the client send
a source code and the JerryScript receive that, then the function will a source code and the JerryScript receive that, then the function will
run the source with the initialized options. run the source with the initialized options, after that the engine will
wait for a new source until the client send a close signal.
**Prototype** **Prototype**
@@ -222,12 +223,19 @@ jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value)
```c ```c
jerry_init (JERRY_INIT_DEBUGGER); jerry_init (JERRY_INIT_DEBUGGER);
jerry_value_t wait_and_run_value; jerry_value_t run_result;
jerry_debugger_wait_and_run_type_t receive_status;
if (jerry_debugger_wait_and_run_client_source (&wait_and_run_value) == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED) do
{ {
// Handle the fail (e.g. create an error). receive_status = jerry_debugger_wait_and_run_client_source (&run_result);
}
jerry_release_value (wait_and_run_value); if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
{
// Handle the fail (e.g. create an error).
}
jerry_release_value (run_result);
}
while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
``` ```
+12 -1
View File
@@ -121,7 +121,8 @@ jerry_debugger_cleanup (void)
* Sets whether the engine should wait and run a source. * Sets whether the engine should wait and run a source.
* *
* @return enum JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED - if the source is not received * @return enum JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED - if the source is not received
* JERRY_DEBUGGER_SOURCE_RECEIVED - if the source received * JERRY_DEBUGGER_SOURCE_RECEIVED - if a source code received
* JERRY_DEBUGGER_SOURCE_END - the end of the source codes
*/ */
jerry_debugger_wait_and_run_type_t jerry_debugger_wait_and_run_type_t
jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value) /**< [out] parse and run return value */ jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value) /**< [out] parse and run return value */
@@ -136,6 +137,9 @@ jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value) /**< [ou
jerry_debugger_uint8_data_t *client_source_data_p = NULL; jerry_debugger_uint8_data_t *client_source_data_p = NULL;
jerry_debugger_wait_and_run_type_t ret_type = JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED; jerry_debugger_wait_and_run_type_t ret_type = JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED;
/* Notify the client about that the engine is waiting for a source. */
jerry_debugger_send_type (JERRY_DEBUGGER_WAIT_FOR_SOURCE);
while (true) while (true)
{ {
if (jerry_debugger_receive (&client_source_data_p)) if (jerry_debugger_receive (&client_source_data_p))
@@ -145,6 +149,13 @@ jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value) /**< [ou
break; break;
} }
/* Stop waiting for a new source file. */
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_NO_SOURCE))
{
ret_type = JERRY_DEBUGGER_SOURCE_END;
break;
}
/* The source arrived. */ /* The source arrived. */
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)) if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{ {
+19
View File
@@ -568,6 +568,25 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec
return true; return true;
} }
case JERRY_DEBUGGER_NO_MORE_SOURCES:
{
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in client source mode\n");
jerry_debugger_close_connection ();
return false;
}
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE);
JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CLIENT_NO_SOURCE);
*resume_exec_p = true;
return true;
}
default: default:
{ {
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message."); jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message.");
+9 -7
View File
@@ -89,6 +89,7 @@ typedef enum
JERRY_DEBUGGER_VM_IGNORE = 1u << 3, /**< ignore all breakpoints */ JERRY_DEBUGGER_VM_IGNORE = 1u << 3, /**< ignore all breakpoints */
JERRY_DEBUGGER_VM_IGNORE_EXCEPTION = 1u << 4, /**< debugger stop at an exception */ JERRY_DEBUGGER_VM_IGNORE_EXCEPTION = 1u << 4, /**< debugger stop at an exception */
JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 5, /**< debugger waiting for client code */ JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 5, /**< debugger waiting for client code */
JERRY_DEBUGGER_CLIENT_NO_SOURCE = 1u << 6, /**< debugger leaving the client source loop */
} jerry_debugger_flags_t; } jerry_debugger_flags_t;
/** /**
@@ -119,6 +120,7 @@ typedef enum
JERRY_DEBUGGER_BACKTRACE_END = 20, /**< last backtrace data */ JERRY_DEBUGGER_BACKTRACE_END = 20, /**< last backtrace data */
JERRY_DEBUGGER_EVAL_RESULT = 21, /**< eval result */ JERRY_DEBUGGER_EVAL_RESULT = 21, /**< eval result */
JERRY_DEBUGGER_EVAL_RESULT_END = 22, /**< last part of eval result */ JERRY_DEBUGGER_EVAL_RESULT_END = 22, /**< last part of eval result */
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23, /**< engine waiting for a source code */
/* Messages sent by the client to server. */ /* Messages sent by the client to server. */
@@ -130,16 +132,17 @@ typedef enum
JERRY_DEBUGGER_STOP = 5, /**< stop execution */ JERRY_DEBUGGER_STOP = 5, /**< stop execution */
JERRY_DEBUGGER_CLIENT_SOURCE = 6, /**< first message of client source */ JERRY_DEBUGGER_CLIENT_SOURCE = 6, /**< first message of client source */
JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7, /**< next message of client source */ JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7, /**< next message of client source */
JERRY_DEBUGGER_NO_MORE_SOURCES = 8, /**< no more sources notification */
/* The following messages are only available in breakpoint /* The following messages are only available in breakpoint
* mode and they switch the engine to run mode. */ * mode and they switch the engine to run mode. */
JERRY_DEBUGGER_CONTINUE = 8, /**< continue execution */ JERRY_DEBUGGER_CONTINUE = 9, /**< continue execution */
JERRY_DEBUGGER_STEP = 9, /**< next breakpoint, step into functions */ JERRY_DEBUGGER_STEP = 10, /**< next breakpoint, step into functions */
JERRY_DEBUGGER_NEXT = 10, /**< next breakpoint in the same context */ JERRY_DEBUGGER_NEXT = 11, /**< next breakpoint in the same context */
/* The following messages are only available in breakpoint /* The following messages are only available in breakpoint
* mode and this mode is kept after the message is processed. */ * mode and this mode is kept after the message is processed. */
JERRY_DEBUGGER_GET_BACKTRACE = 11, /**< get backtrace */ JERRY_DEBUGGER_GET_BACKTRACE = 12, /**< get backtrace */
JERRY_DEBUGGER_EVAL = 12, /**< first message of evaluating a string */ JERRY_DEBUGGER_EVAL = 13, /**< first message of evaluating a string */
JERRY_DEBUGGER_EVAL_PART = 13, /**< next message of evaluating a string */ JERRY_DEBUGGER_EVAL_PART = 14, /**< next message of evaluating a string */
} jerry_debugger_header_type_t; } jerry_debugger_header_type_t;
/** /**
@@ -308,7 +311,6 @@ typedef struct
uint8_t eval_size[sizeof (uint32_t)]; /**< total size of the message */ uint8_t eval_size[sizeof (uint32_t)]; /**< total size of the message */
} jerry_debugger_receive_eval_first_t; } jerry_debugger_receive_eval_first_t;
/** /**
* Incoming message: first message of client source. * Incoming message: first message of client source.
*/ */
+2 -1
View File
@@ -33,7 +33,8 @@ extern "C"
typedef enum typedef enum
{ {
JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED = 0, /**< source is not received */ JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED = 0, /**< source is not received */
JERRY_DEBUGGER_SOURCE_RECEIVED = 1, /**< the source has been received */ JERRY_DEBUGGER_SOURCE_RECEIVED = 1, /**< a source has been received */
JERRY_DEBUGGER_SOURCE_END = 2, /**< the end of the sources signal received */
} jerry_debugger_wait_and_run_type_t; } jerry_debugger_wait_and_run_type_t;
/** /**
+14 -6
View File
@@ -58,6 +58,7 @@ var JERRY_DEBUGGER_BACKTRACE = 19;
var JERRY_DEBUGGER_BACKTRACE_END = 20; var JERRY_DEBUGGER_BACKTRACE_END = 20;
var JERRY_DEBUGGER_EVAL_RESULT = 21; var JERRY_DEBUGGER_EVAL_RESULT = 21;
var JERRY_DEBUGGER_EVAL_RESULT_END = 22; var JERRY_DEBUGGER_EVAL_RESULT_END = 22;
var JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23;
// Subtypes of eval // Subtypes of eval
var JERRY_DEBUGGER_EVAL_OK = 1; var JERRY_DEBUGGER_EVAL_OK = 1;
@@ -71,12 +72,13 @@ var JERRY_DEBUGGER_MEMSTATS = 4;
var JERRY_DEBUGGER_STOP = 5; var JERRY_DEBUGGER_STOP = 5;
var JERRY_DEBUGGER_CLIENT_SOURCE = 6; var JERRY_DEBUGGER_CLIENT_SOURCE = 6;
var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7; var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7;
var JERRY_DEBUGGER_CONTINUE = 8; var JERRY_DEBUGGER_NO_MORE_SOURCES = 8;
var JERRY_DEBUGGER_STEP = 9; var JERRY_DEBUGGER_CONTINUE = 9;
var JERRY_DEBUGGER_NEXT = 10; var JERRY_DEBUGGER_STEP = 10;
var JERRY_DEBUGGER_GET_BACKTRACE = 11; var JERRY_DEBUGGER_NEXT = 11;
var JERRY_DEBUGGER_EVAL = 12; var JERRY_DEBUGGER_GET_BACKTRACE = 12;
var JERRY_DEBUGGER_EVAL_PART = 13; var JERRY_DEBUGGER_EVAL = 13;
var JERRY_DEBUGGER_EVAL_PART = 14;
var textBox = document.getElementById("log"); var textBox = document.getElementById("log");
var commandBox = document.getElementById("command"); var commandBox = document.getElementById("command");
@@ -921,6 +923,12 @@ function DebuggerClient(address)
return; return;
} }
case JERRY_DEBUGGER_WAIT_FOR_SOURCE:
{
// This message does not have effect in this client.
return;
}
default: default:
{ {
abortConnection("unexpected message."); abortConnection("unexpected message.");
+31 -13
View File
@@ -48,6 +48,7 @@ JERRY_DEBUGGER_BACKTRACE = 19
JERRY_DEBUGGER_BACKTRACE_END = 20 JERRY_DEBUGGER_BACKTRACE_END = 20
JERRY_DEBUGGER_EVAL_RESULT = 21 JERRY_DEBUGGER_EVAL_RESULT = 21
JERRY_DEBUGGER_EVAL_RESULT_END = 22 JERRY_DEBUGGER_EVAL_RESULT_END = 22
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23
# Subtypes of eval # Subtypes of eval
JERRY_DEBUGGER_EVAL_OK = 1 JERRY_DEBUGGER_EVAL_OK = 1
@@ -62,12 +63,13 @@ JERRY_DEBUGGER_MEMSTATS = 4
JERRY_DEBUGGER_STOP = 5 JERRY_DEBUGGER_STOP = 5
JERRY_DEBUGGER_CLIENT_SOURCE = 6 JERRY_DEBUGGER_CLIENT_SOURCE = 6
JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7 JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7
JERRY_DEBUGGER_CONTINUE = 8 JERRY_DEBUGGER_NO_MORE_SOURCES = 8
JERRY_DEBUGGER_STEP = 9 JERRY_DEBUGGER_CONTINUE = 9
JERRY_DEBUGGER_NEXT = 10 JERRY_DEBUGGER_STEP = 10
JERRY_DEBUGGER_GET_BACKTRACE = 11 JERRY_DEBUGGER_NEXT = 11
JERRY_DEBUGGER_EVAL = 12 JERRY_DEBUGGER_GET_BACKTRACE = 12
JERRY_DEBUGGER_EVAL_PART = 13 JERRY_DEBUGGER_EVAL = 13
JERRY_DEBUGGER_EVAL_PART = 14
MAX_BUFFER_SIZE = 128 MAX_BUFFER_SIZE = 128
WEBSOCKET_BINARY_FRAME = 2 WEBSOCKET_BINARY_FRAME = 2
@@ -89,7 +91,7 @@ def arguments_parse():
help="set display range") help="set display range")
parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1], parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1],
help="set exception config, usage 1: [Enable] or 0: [Disable]") help="set exception config, usage 1: [Enable] or 0: [Disable]")
parser.add_argument("--client-source", action="store", default=None, type=str, parser.add_argument("--client-source", action="store", default=[], type=str, nargs="+",
help="specify a javascript source file to execute") help="specify a javascript source file to execute")
args = parser.parse_args() args = parser.parse_args()
@@ -181,6 +183,7 @@ class DebuggerPrompt(Cmd):
self.quit = False self.quit = False
self.cont = True self.cont = True
self.non_interactive = False self.non_interactive = False
self.client_sources = []
def precmd(self, line): def precmd(self, line):
self.stop = False self.stop = False
@@ -431,16 +434,28 @@ class DebuggerPrompt(Cmd):
do_ms = do_memstats do_ms = do_memstats
def send_client_source(self, args): def store_client_sources(self, args):
""" Send and execute the specified Javascript source file to the debugger """ self.client_sources = args
if not args.lower().endswith('.js'):
def send_client_source(self):
# Send no more source message if there is no source
if not self.client_sources:
self.send_no_more_source()
return
path = self.client_sources.pop(0)
if not path.lower().endswith('.js'):
sys.exit("Error: Javascript file expected!") sys.exit("Error: Javascript file expected!")
return return
with open(args, 'r') as f: with open(path, 'r') as f:
content = args + "\0" + f.read() content = path + "\0" + f.read()
self.send_string(content, JERRY_DEBUGGER_CLIENT_SOURCE) self.send_string(content, JERRY_DEBUGGER_CLIENT_SOURCE)
def send_no_more_source(self):
self.exec_command("", JERRY_DEBUGGER_NO_MORE_SOURCES)
self.cont = True
class Multimap(object): class Multimap(object):
def __init__(self): def __init__(self):
@@ -963,7 +978,7 @@ def main():
prompt.do_exception(str(args.exception)) prompt.do_exception(str(args.exception))
if args.client_source is not None: if args.client_source is not None:
prompt.send_client_source(str(args.client_source)) prompt.store_client_sources(args.client_source)
while True: while True:
if not non_interactive and prompt.cont: if not non_interactive and prompt.cont:
@@ -1106,6 +1121,9 @@ def main():
prompt.cmdloop() prompt.cmdloop()
elif buffer_type == JERRY_DEBUGGER_WAIT_FOR_SOURCE:
prompt.send_client_source()
else: else:
raise Exception("Unknown message") raise Exception("Unknown message")
+19 -5
View File
@@ -723,14 +723,28 @@ main (int argc,
{ {
is_repl_mode = false; is_repl_mode = false;
#ifdef JERRY_DEBUGGER #ifdef JERRY_DEBUGGER
jerry_value_t wait_and_run_value; jerry_value_t run_result;
jerry_debugger_wait_and_run_type_t receive_status;
if (jerry_debugger_wait_and_run_client_source (&wait_and_run_value) == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED) do
{ {
ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Connection aborted before source arrived."); receive_status = jerry_debugger_wait_and_run_client_source (&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);
jerry_release_value (wait_and_run_value);
#endif /* JERRY_DEBUGGER */ #endif /* JERRY_DEBUGGER */
} }
@@ -0,0 +1,7 @@
n
n
s
s
s
s
c
@@ -0,0 +1,15 @@
Connecting to: localhost:5001
Stopped at tests/debugger/client_source_multiple_2.js:15
(jerry-debugger) n
Stopped at tests/debugger/client_source_multiple_1.js:15
(jerry-debugger) n
Stopped at tests/debugger/client_source_multiple_1.js:27
(jerry-debugger) s
Stopped at tests/debugger/client_source_multiple_1.js:18 (in foo() at line:17, col:1)
(jerry-debugger) s
Stopped at tests/debugger/client_source_multiple_1.js:19 (in foo() at line:17, col:1)
(jerry-debugger) s
Stopped at tests/debugger/client_source_multiple_2.js:18 (in bar() at line:17, col:1)
(jerry-debugger) s
Stopped at tests/debugger/client_source_multiple_2.js:19 (in bar() at line:17, col:1)
(jerry-debugger) c
@@ -0,0 +1,27 @@
// 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.
print("multiple-client-source-test-file-1");
function foo() {
print("foo");
bar("called-from-test-file-1");
}
function crossFoo(str) {
print("crossFoo");
print("str-argument: " + str);
}
foo();
@@ -0,0 +1,21 @@
// 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.
print("multiple-client-source-test-file-2");
function bar(str) {
print("bar");
print("str-argument: " + str);
crossFoo("called-from-test-file-2");
}
+1 -1
View File
@@ -218,7 +218,7 @@ def run_jerry_debugger_tests(options):
break break
for test_file in os.listdir(settings.DEBUGGER_TESTS_DIR): for test_file in os.listdir(settings.DEBUGGER_TESTS_DIR):
if test_file.endswith(".js"): if test_file.endswith(".cmd"):
test_case, _ = os.path.splitext(test_file) test_case, _ = os.path.splitext(test_file)
test_case_path = os.path.join(settings.DEBUGGER_TESTS_DIR, test_case) test_case_path = os.path.join(settings.DEBUGGER_TESTS_DIR, test_case)
test_cmd = [ test_cmd = [
+5 -1
View File
@@ -21,7 +21,11 @@ CLIENT_ARGS=""
if [[ $TEST_CASE == *"client_source"* ]]; then if [[ $TEST_CASE == *"client_source"* ]]; then
START_DEBUG_SERVER="${JERRY} --start-debug-server --debugger-wait-source &" START_DEBUG_SERVER="${JERRY} --start-debug-server --debugger-wait-source &"
CLIENT_ARGS="--client-source ${TEST_CASE}.js" if [[ $TEST_CASE == *"client_source_multiple"* ]]; then
CLIENT_ARGS="--client-source ${TEST_CASE}_2.js ${TEST_CASE}_1.js"
else
CLIENT_ARGS="--client-source ${TEST_CASE}.js"
fi
else else
START_DEBUG_SERVER="${JERRY} ${TEST_CASE}.js --start-debug-server &" START_DEBUG_SERVER="${JERRY} ${TEST_CASE}.js --start-debug-server &"
fi fi