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

View File

@ -26,7 +26,7 @@ can be used for transmitting debugger messages.
The debugger client must be connected to the server before the
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
information (e.g. line index of each possible -breakpoint location)
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
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**
@ -222,12 +223,19 @@ jerry_debugger_wait_and_run_client_source (jerry_value_t *return_value)
```c
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);
```

View File

@ -121,7 +121,8 @@ jerry_debugger_cleanup (void)
* Sets whether the engine should wait and run a source.
*
* @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_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_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)
{
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;
}
/* 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. */
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{

View File

@ -568,6 +568,25 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec
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:
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message.");

View File

@ -89,6 +89,7 @@ typedef enum
JERRY_DEBUGGER_VM_IGNORE = 1u << 3, /**< ignore all breakpoints */
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_NO_SOURCE = 1u << 6, /**< debugger leaving the client source loop */
} jerry_debugger_flags_t;
/**
@ -119,6 +120,7 @@ typedef enum
JERRY_DEBUGGER_BACKTRACE_END = 20, /**< last backtrace data */
JERRY_DEBUGGER_EVAL_RESULT = 21, /**< 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. */
@ -130,16 +132,17 @@ typedef enum
JERRY_DEBUGGER_STOP = 5, /**< stop execution */
JERRY_DEBUGGER_CLIENT_SOURCE = 6, /**< first 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
* mode and they switch the engine to run mode. */
JERRY_DEBUGGER_CONTINUE = 8, /**< continue execution */
JERRY_DEBUGGER_STEP = 9, /**< next breakpoint, step into functions */
JERRY_DEBUGGER_NEXT = 10, /**< next breakpoint in the same context */
JERRY_DEBUGGER_CONTINUE = 9, /**< continue execution */
JERRY_DEBUGGER_STEP = 10, /**< next breakpoint, step into functions */
JERRY_DEBUGGER_NEXT = 11, /**< next breakpoint in the same context */
/* The following messages are only available in breakpoint
* mode and this mode is kept after the message is processed. */
JERRY_DEBUGGER_GET_BACKTRACE = 11, /**< get backtrace */
JERRY_DEBUGGER_EVAL = 12, /**< first message of evaluating a string */
JERRY_DEBUGGER_EVAL_PART = 13, /**< next message of evaluating a string */
JERRY_DEBUGGER_GET_BACKTRACE = 12, /**< get backtrace */
JERRY_DEBUGGER_EVAL = 13, /**< first message of evaluating a string */
JERRY_DEBUGGER_EVAL_PART = 14, /**< next message of evaluating a string */
} jerry_debugger_header_type_t;
/**
@ -308,7 +311,6 @@ typedef struct
uint8_t eval_size[sizeof (uint32_t)]; /**< total size of the message */
} jerry_debugger_receive_eval_first_t;
/**
* Incoming message: first message of client source.
*/

View File

@ -33,7 +33,8 @@ extern "C"
typedef enum
{
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;
/**

View File

@ -58,6 +58,7 @@ var JERRY_DEBUGGER_BACKTRACE = 19;
var JERRY_DEBUGGER_BACKTRACE_END = 20;
var JERRY_DEBUGGER_EVAL_RESULT = 21;
var JERRY_DEBUGGER_EVAL_RESULT_END = 22;
var JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23;
// Subtypes of eval
var JERRY_DEBUGGER_EVAL_OK = 1;
@ -71,12 +72,13 @@ var JERRY_DEBUGGER_MEMSTATS = 4;
var JERRY_DEBUGGER_STOP = 5;
var JERRY_DEBUGGER_CLIENT_SOURCE = 6;
var JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7;
var JERRY_DEBUGGER_CONTINUE = 8;
var JERRY_DEBUGGER_STEP = 9;
var JERRY_DEBUGGER_NEXT = 10;
var JERRY_DEBUGGER_GET_BACKTRACE = 11;
var JERRY_DEBUGGER_EVAL = 12;
var JERRY_DEBUGGER_EVAL_PART = 13;
var JERRY_DEBUGGER_NO_MORE_SOURCES = 8;
var JERRY_DEBUGGER_CONTINUE = 9;
var JERRY_DEBUGGER_STEP = 10;
var JERRY_DEBUGGER_NEXT = 11;
var JERRY_DEBUGGER_GET_BACKTRACE = 12;
var JERRY_DEBUGGER_EVAL = 13;
var JERRY_DEBUGGER_EVAL_PART = 14;
var textBox = document.getElementById("log");
var commandBox = document.getElementById("command");
@ -921,6 +923,12 @@ function DebuggerClient(address)
return;
}
case JERRY_DEBUGGER_WAIT_FOR_SOURCE:
{
// This message does not have effect in this client.
return;
}
default:
{
abortConnection("unexpected message.");

View File

@ -48,6 +48,7 @@ JERRY_DEBUGGER_BACKTRACE = 19
JERRY_DEBUGGER_BACKTRACE_END = 20
JERRY_DEBUGGER_EVAL_RESULT = 21
JERRY_DEBUGGER_EVAL_RESULT_END = 22
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23
# Subtypes of eval
JERRY_DEBUGGER_EVAL_OK = 1
@ -62,12 +63,13 @@ JERRY_DEBUGGER_MEMSTATS = 4
JERRY_DEBUGGER_STOP = 5
JERRY_DEBUGGER_CLIENT_SOURCE = 6
JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7
JERRY_DEBUGGER_CONTINUE = 8
JERRY_DEBUGGER_STEP = 9
JERRY_DEBUGGER_NEXT = 10
JERRY_DEBUGGER_GET_BACKTRACE = 11
JERRY_DEBUGGER_EVAL = 12
JERRY_DEBUGGER_EVAL_PART = 13
JERRY_DEBUGGER_NO_MORE_SOURCES = 8
JERRY_DEBUGGER_CONTINUE = 9
JERRY_DEBUGGER_STEP = 10
JERRY_DEBUGGER_NEXT = 11
JERRY_DEBUGGER_GET_BACKTRACE = 12
JERRY_DEBUGGER_EVAL = 13
JERRY_DEBUGGER_EVAL_PART = 14
MAX_BUFFER_SIZE = 128
WEBSOCKET_BINARY_FRAME = 2
@ -89,7 +91,7 @@ def arguments_parse():
help="set display range")
parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1],
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")
args = parser.parse_args()
@ -181,6 +183,7 @@ class DebuggerPrompt(Cmd):
self.quit = False
self.cont = True
self.non_interactive = False
self.client_sources = []
def precmd(self, line):
self.stop = False
@ -431,16 +434,28 @@ class DebuggerPrompt(Cmd):
do_ms = do_memstats
def send_client_source(self, args):
""" Send and execute the specified Javascript source file to the debugger """
if not args.lower().endswith('.js'):
def store_client_sources(self, args):
self.client_sources = args
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!")
return
with open(args, 'r') as f:
content = args + "\0" + f.read()
with open(path, 'r') as f:
content = path + "\0" + f.read()
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):
def __init__(self):
@ -963,7 +978,7 @@ def main():
prompt.do_exception(str(args.exception))
if args.client_source is not None:
prompt.send_client_source(str(args.client_source))
prompt.store_client_sources(args.client_source)
while True:
if not non_interactive and prompt.cont:
@ -1106,6 +1121,9 @@ def main():
prompt.cmdloop()
elif buffer_type == JERRY_DEBUGGER_WAIT_FOR_SOURCE:
prompt.send_client_source()
else:
raise Exception("Unknown message")

View File

@ -723,14 +723,28 @@ main (int argc,
{
is_repl_mode = false;
#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 */
}

View File

@ -0,0 +1,7 @@
n
n
s
s
s
s
c

View File

@ -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

View File

@ -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();

View File

@ -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");
}

View File

@ -218,7 +218,7 @@ def run_jerry_debugger_tests(options):
break
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_path = os.path.join(settings.DEBUGGER_TESTS_DIR, test_case)
test_cmd = [

View File

@ -21,7 +21,11 @@ CLIENT_ARGS=""
if [[ $TEST_CASE == *"client_source"* ]]; then
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
START_DEBUG_SERVER="${JERRY} ${TEST_CASE}.js --start-debug-server &"
fi