Skip to content

Commit 3d3e6fd

Browse files
authored
[Debugger] Create a simplified transmission layer (#2781)
It supports the raw packet sending over a TCP/IP protocol JerryScript-DCO-1.0-Signed-off-by: Robert Sipka rsipka.uszeged@partner.samsung.com
1 parent fbd734e commit 3d3e6fd

File tree

10 files changed

+330
-37
lines changed

10 files changed

+330
-37
lines changed

docs/07.DEBUGGER.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ debugger can be enabled by calling `jerryx_debugger_after_connect
6969
(jerryx_debugger_tcp_create (debug_port) && jerryx_debugger_ws_create ())`
7070
after the `jerry_init ()` function. It initializes the debugger and
7171
blocks until a client connects. (Custom transport layers may be
72-
implemented and initialized similarly.)
72+
implemented and initialized similarly. Currently, `jerryx_debugger_rp_create()` for
73+
raw packet transport layer is also available.)
7374

7475
The resource name provided to `jerry_parse ()` is used by the client
7576
to identify the resource name of the source code. This resource name

jerry-debugger/jerry_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def src_check_args(args):
250250
def main():
251251
args = jerry_client_main.arguments_parse()
252252

253-
debugger = jerry_client_main.JerryDebugger(args.address)
253+
debugger = jerry_client_main.JerryDebugger(args.address, args.channel)
254254
debugger.non_interactive = args.non_interactive
255255

256256
logging.debug("Connected to JerryScript on %d port", debugger.port)

jerry-debugger/jerry_client_main.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import struct
2323
import sys
2424
from jerry_client_websocket import WebSocket
25+
from jerry_client_rawpacket import RawPacket
26+
from jerry_client_tcp import Socket
2527

2628
# Expected debugger protocol version.
2729
JERRY_DEBUGGER_VERSION = 8
@@ -134,7 +136,8 @@ def arguments_parse():
134136
help="set exception config, usage 1: [Enable] or 0: [Disable]")
135137
parser.add_argument("--client-source", action="store", default=[], type=str, nargs="+",
136138
help="specify a javascript source file to execute")
137-
139+
parser.add_argument("--channel", choices=["websocket", "rawpacket"], default="websocket",
140+
help="specify the communication channel (default: %(default)s)")
138141
args = parser.parse_args()
139142

140143
if args.verbose:
@@ -262,8 +265,8 @@ def get_text(self):
262265

263266

264267
class JerryDebugger(object):
265-
# pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use
266-
def __init__(self, address):
268+
# pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use,redefined-variable-type
269+
def __init__(self, address, channel):
267270

268271
if ":" not in address:
269272
self.host = address
@@ -301,8 +304,15 @@ def __init__(self, address):
301304
self.non_interactive = False
302305
self.current_out = b""
303306
self.current_log = b""
307+
self.channel = None
304308

305-
self.channel = WebSocket(address=(self.host, self.port))
309+
protocol = Socket()
310+
if channel == "websocket":
311+
self.channel = WebSocket(address=(self.host, self.port), protocol=protocol)
312+
elif channel == "rawpacket":
313+
self.channel = RawPacket(address=(self.host, self.port), protocol=protocol)
314+
else:
315+
raise Exception("Unsupported communication channel")
306316

307317
config_size = 8
308318
# The server will send the configuration message after connection established
@@ -342,7 +352,8 @@ def __init__(self, address):
342352
logging.debug("Compressed pointer size: %d", self.cp_size)
343353

344354
def __del__(self):
345-
self.channel.close()
355+
if self.channel is not None:
356+
self.channel.close()
346357

347358
def _exec_command(self, command_id):
348359
self.send_command(command_id)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright JS Foundation and other contributors, http://js.foundation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import struct
18+
19+
MAX_BUFFER_SIZE = 256
20+
21+
class RawPacket(object):
22+
""" Simplified transmission layer. """
23+
def __init__(self, address, protocol):
24+
self.protocol = protocol
25+
self.data_buffer = b""
26+
self.address = address
27+
28+
def connect(self, config_size):
29+
""" Create connection. """
30+
self.protocol.connect(self.address)
31+
self.data_buffer = b""
32+
33+
# It will return with the Network configurations, which has the following struct:
34+
# header [1] - size[1]
35+
# configuration [config_size]
36+
len_expected = config_size + 1
37+
38+
while len(self.data_buffer) < len_expected:
39+
self.data_buffer += self.protocol.receive_data()
40+
41+
expected = struct.pack("B", config_size)
42+
43+
if self.data_buffer[0:1] != expected:
44+
raise Exception("Unexpected configuration")
45+
46+
result = self.data_buffer[1:len_expected]
47+
self.data_buffer = self.data_buffer[len_expected:]
48+
49+
return result
50+
51+
def close(self):
52+
""" Close connection. """
53+
self.protocol.close()
54+
55+
def send_message(self, _, data):
56+
""" Send message. """
57+
msg_size = len(data)
58+
59+
while msg_size > 0:
60+
bytes_send = self.protocol.send_data(data)
61+
if bytes_send < msg_size:
62+
data = data[bytes_send:]
63+
msg_size -= bytes_send
64+
65+
def get_message(self, blocking):
66+
""" Receive message. """
67+
68+
# Connection was closed
69+
if self.data_buffer is None:
70+
return None
71+
72+
while True:
73+
if len(self.data_buffer) >= 1:
74+
size = ord(self.data_buffer[0])
75+
if size == 0:
76+
raise Exception("Unexpected data frame")
77+
78+
if len(self.data_buffer) >= size + 1:
79+
result = self.data_buffer[1:size + 1]
80+
self.data_buffer = self.data_buffer[size + 1:]
81+
return result
82+
83+
if not blocking and not self.protocol.ready():
84+
return b''
85+
86+
received_data = self.protocol.receive_data(MAX_BUFFER_SIZE)
87+
88+
if not received_data:
89+
return None
90+
91+
self.data_buffer += received_data

jerry-debugger/jerry_client_websocket.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@
1515
# limitations under the License.
1616

1717
import struct
18-
from jerry_client_tcp import Socket
1918

2019
MAX_BUFFER_SIZE = 128
2120
WEBSOCKET_BINARY_FRAME = 2
2221
WEBSOCKET_FIN_BIT = 0x80
2322

2423
class WebSocket(object):
25-
def __init__(self, address, protocol=Socket()):
24+
def __init__(self, address, protocol):
2625

2726
self.data_buffer = b""
2827
self.protocol = protocol

jerry-ext/debugger/debugger-rp.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#include "jerryscript-ext/debugger.h"
17+
#include "jext-common.h"
18+
19+
#ifdef JERRY_DEBUGGER
20+
21+
/* A simplified transmission layer. */
22+
23+
/**
24+
* Size of the raw packet header.
25+
*/
26+
#define JERRYX_DEBUGGER_RAWPACKET_HEADER_SIZE 1
27+
/**
28+
* Maximum message size with 1 byte size field.
29+
*/
30+
#define JERRYX_DEBUGGER_RAWPACKET_ONE_BYTE_LEN_MAX 255
31+
32+
/**
33+
* Header for incoming packets.
34+
*/
35+
typedef struct
36+
{
37+
uint8_t size; /**< size of the message */
38+
} jerryx_rawpacket_receive_header_t;
39+
40+
/**
41+
* Close a tcp connection.
42+
*/
43+
static void
44+
jerryx_debugger_rp_close (jerry_debugger_transport_header_t *header_p) /**< header for the transport interface */
45+
{
46+
JERRYX_ASSERT (!jerry_debugger_transport_is_connected ());
47+
48+
jerry_heap_free ((void *) header_p, sizeof (jerry_debugger_transport_header_t));
49+
} /* jerryx_debugger_rp_close */
50+
51+
/**
52+
* Send data over a simple raw packet connection.
53+
*
54+
* @return true - if the data has been sent successfully
55+
* false - otherwise
56+
*/
57+
static bool
58+
jerryx_debugger_rp_send (jerry_debugger_transport_header_t *header_p, /**< header for the transport interface */
59+
uint8_t *message_p, /**< message to be sent */
60+
size_t message_length) /**< message length in bytes */
61+
{
62+
JERRYX_ASSERT (message_length <= JERRYX_DEBUGGER_RAWPACKET_ONE_BYTE_LEN_MAX);
63+
64+
message_p[-1] = (uint8_t) message_length;
65+
66+
return header_p->next_p->send (header_p->next_p, message_p - 1, message_length + 1);
67+
} /* jerryx_debugger_rp_send */
68+
69+
/**
70+
* Receive data from a rawpacket connection.
71+
*
72+
* @return true - if data has been received successfully
73+
* false - otherwise
74+
*/
75+
static bool
76+
jerryx_debugger_rp_receive (jerry_debugger_transport_header_t *header_p, /**< header for the transport interface */
77+
jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
78+
{
79+
if (!header_p->next_p->receive (header_p->next_p, receive_context_p))
80+
{
81+
return false;
82+
}
83+
84+
if (receive_context_p->message_p == NULL)
85+
{
86+
return true;
87+
}
88+
89+
JERRYX_ASSERT (receive_context_p->message_length >= sizeof (jerryx_rawpacket_receive_header_t));
90+
91+
uint8_t *message_p = receive_context_p->message_p;
92+
size_t message_length = (size_t) (message_p[0]);
93+
94+
size_t message_total_length = receive_context_p->message_total_length;
95+
96+
if (message_total_length == 0)
97+
{
98+
size_t new_total_length = message_length + sizeof (jerryx_rawpacket_receive_header_t);
99+
receive_context_p->message_total_length = new_total_length;
100+
}
101+
else
102+
{
103+
/* Datagram packet. */
104+
JERRYX_ASSERT (receive_context_p->message_length == (message_length + sizeof (jerryx_rawpacket_receive_header_t)));
105+
}
106+
107+
message_p += sizeof (jerryx_rawpacket_receive_header_t);
108+
109+
receive_context_p->message_p = message_p;
110+
receive_context_p->message_length = message_length;
111+
112+
return true;
113+
} /* jerryx_debugger_rp_receive */
114+
115+
/**
116+
* Initialize a simple raw packet transmission layer.
117+
*
118+
* @return true - if the connection succeeded
119+
* false - otherwise
120+
*/
121+
bool
122+
jerryx_debugger_rp_create (void)
123+
{
124+
const size_t interface_size = sizeof (jerry_debugger_transport_header_t);
125+
jerry_debugger_transport_header_t *header_p;
126+
header_p = (jerry_debugger_transport_header_t *) jerry_heap_alloc (interface_size);
127+
128+
if (!header_p)
129+
{
130+
return false;
131+
}
132+
133+
header_p->close = jerryx_debugger_rp_close;
134+
header_p->send = jerryx_debugger_rp_send;
135+
header_p->receive = jerryx_debugger_rp_receive;
136+
137+
jerry_debugger_transport_add (header_p,
138+
JERRYX_DEBUGGER_RAWPACKET_HEADER_SIZE,
139+
JERRYX_DEBUGGER_RAWPACKET_ONE_BYTE_LEN_MAX,
140+
JERRYX_DEBUGGER_RAWPACKET_HEADER_SIZE,
141+
JERRYX_DEBUGGER_RAWPACKET_ONE_BYTE_LEN_MAX);
142+
143+
return true;
144+
} /* jerryx_debugger_rp_create */
145+
146+
#else /* !JERRY_DEBUGGER */
147+
148+
/**
149+
* Dummy function when debugger is disabled.
150+
*
151+
* @return false
152+
*/
153+
bool
154+
jerryx_debugger_rp_create (void)
155+
{
156+
return false;
157+
} /* jerryx_debugger_rp_create */
158+
159+
#endif /* JERRY_DEBUGGER */

jerry-ext/include/jerryscript-ext/debugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ bool jerryx_debugger_tcp_create (uint16_t port);
3535
* Message encoding interfaces.
3636
*/
3737
bool jerryx_debugger_ws_create (void);
38+
bool jerryx_debugger_rp_create (void);
3839

3940
#ifdef __cplusplus
4041
}

0 commit comments

Comments
 (0)