Skip to content

Commit 4a0af3f

Browse files
author
Daniel Balla
committed
Add the ability to throw an error to python debugger
This patch makes it possible to throw an error from the python debugger client using the `throw` command. JerryScript-DCO-1.0-Signed-off-by: Daniel Balla dballa@inf.u-szeged.hu
1 parent 29b337d commit 4a0af3f

File tree

8 files changed

+98
-8
lines changed

8 files changed

+98
-8
lines changed

jerry-core/debugger/debugger.c

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,15 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer to the recei
142142
} /* jerry_debugger_send_backtrace */
143143

144144
/**
145-
* Send result of evaluated expression.
145+
* Send result of evaluated expression or throw an error.
146146
*
147147
* @return true - if no error is occured
148148
* false - otherwise
149149
*/
150150
static bool
151-
jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */
152-
size_t eval_string_size) /**< evaluated string size */
151+
jerry_debugger_send_eval_or_throw (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */
152+
size_t eval_string_size, /**< evaluated string size */
153+
bool *is_eval) /**< [in,out] throw or eval call */
153154
{
154155
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
155156
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE));
@@ -160,11 +161,21 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
160161

161162
if (!ECMA_IS_VALUE_ERROR (result))
162163
{
164+
if (!*is_eval)
165+
{
166+
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_THROW_ERROR_FLAG);
167+
JERRY_CONTEXT (error_value) = result;
168+
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP);
169+
JERRY_CONTEXT (debugger_stop_context) = NULL;
170+
return true;
171+
}
172+
163173
ecma_value_t to_string_value = ecma_op_to_string (result);
164174
ecma_free_value (result);
165175
result = to_string_value;
166176
}
167177

178+
*is_eval = true;
168179
ecma_value_t message = result;
169180
uint8_t type = JERRY_DEBUGGER_EVAL_OK;
170181

@@ -211,7 +222,7 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
211222
ecma_free_value (message);
212223

213224
return success;
214-
} /* jerry_debugger_send_eval */
225+
} /* jerry_debugger_send_eval_or_throw */
215226

216227
/**
217228
* Suspend execution for a given time.
@@ -268,6 +279,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
268279
if (*expected_message_type_p != 0)
269280
{
270281
JERRY_ASSERT (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART
282+
|| *expected_message_type_p == JERRY_DEBUGGER_THROW_PART
271283
|| *expected_message_type_p == JERRY_DEBUGGER_CLIENT_SOURCE_PART);
272284

273285
jerry_debugger_uint8_data_t *uint8_data_p = (jerry_debugger_uint8_data_t *) *message_data_p;
@@ -314,9 +326,19 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
314326
}
315327

316328
bool result = false;
329+
bool is_eval = true;
317330
if (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART)
318331
{
319-
result = jerry_debugger_send_eval (string_p, uint8_data_p->uint8_size);
332+
result = jerry_debugger_send_eval_or_throw (string_p, uint8_data_p->uint8_size, &is_eval);
333+
}
334+
else if (*expected_message_type_p == JERRY_DEBUGGER_THROW_PART)
335+
{
336+
is_eval = false;
337+
result = jerry_debugger_send_eval_or_throw (string_p, uint8_data_p->uint8_size, &is_eval);
338+
if (!is_eval)
339+
{
340+
*resume_exec_p = true;
341+
}
320342
}
321343
else
322344
{
@@ -500,6 +522,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
500522
}
501523

502524
case JERRY_DEBUGGER_EVAL:
525+
case JERRY_DEBUGGER_THROW:
503526
{
504527
if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 1)
505528
{
@@ -512,6 +535,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
512535

513536
uint32_t eval_size;
514537
memcpy (&eval_size, eval_first_p->eval_size, sizeof (uint32_t));
538+
bool is_eval = (recv_buffer_p[0] == JERRY_DEBUGGER_EVAL);
515539

516540
if (eval_size <= JERRY_DEBUGGER_MAX_RECEIVE_SIZE - sizeof (jerry_debugger_receive_eval_first_t))
517541
{
@@ -521,8 +545,13 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
521545
jerry_debugger_close_connection ();
522546
return false;
523547
}
548+
bool ret_val = jerry_debugger_send_eval_or_throw ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size, &is_eval);
549+
if (!is_eval)
550+
{
551+
*resume_exec_p = true;
552+
}
524553

525-
return jerry_debugger_send_eval ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size);
554+
return ret_val;
526555
}
527556

528557
jerry_debugger_uint8_data_t *eval_uint8_data_p;
@@ -539,7 +568,8 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
539568
message_size - sizeof (jerry_debugger_receive_eval_first_t));
540569

541570
*message_data_p = eval_uint8_data_p;
542-
*expected_message_type_p = JERRY_DEBUGGER_EVAL_PART;
571+
*expected_message_type_p = is_eval ? JERRY_DEBUGGER_EVAL_PART : JERRY_DEBUGGER_THROW_PART;
572+
543573
return true;
544574
}
545575

jerry-core/debugger/debugger.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ typedef enum
9898
JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 7, /**< debugger waiting for client code */
9999
JERRY_DEBUGGER_CLIENT_NO_SOURCE = 1u << 8, /**< debugger leaving the client source loop */
100100
JERRY_DEBUGGER_CONTEXT_RESET_MODE = 1u << 9, /**< debugger and engine reinitialization mode */
101+
JERRY_DEBUGGER_THROW_ERROR_FLAG = 1u << 10, /**< debugger client sent an error throw */
101102
} jerry_debugger_flags_t;
102103

103104
/**
@@ -185,6 +186,8 @@ typedef enum
185186
JERRY_DEBUGGER_EVAL_PART = 17, /**< next message of evaluating a string */
186187

187188
JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */
189+
JERRY_DEBUGGER_THROW = 18, /**< first message of the throw string */
190+
JERRY_DEBUGGER_THROW_PART = 19, /**< next part of the throw message */
188191
} jerry_debugger_header_type_t;
189192

190193
/**

jerry-core/vm/vm.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,6 +2495,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
24952495
frame_ctx_p->byte_code_p = byte_code_start_p;
24962496

24972497
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
2498+
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
2499+
{
2500+
result = JERRY_CONTEXT (error_value);
2501+
goto error;
2502+
}
24982503
#endif /* JERRY_DEBUGGER */
24992504
continue;
25002505
}
@@ -2517,6 +2522,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
25172522
|| JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p)))
25182523
{
25192524
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
2525+
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
2526+
{
2527+
result = JERRY_CONTEXT (error_value);
2528+
goto error;
2529+
}
25202530
continue;
25212531
}
25222532

@@ -2538,6 +2548,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
25382548
|| JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p)))
25392549
{
25402550
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT);
2551+
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
2552+
{
2553+
result = JERRY_CONTEXT (error_value);
2554+
goto error;
2555+
}
25412556
}
25422557
#endif /* JERRY_DEBUGGER */
25432558
continue;
@@ -2677,9 +2692,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
26772692
&& !(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
26782693
&& !(JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE)))
26792694
{
2695+
/* Save the error to a local value, because the engine enters breakpoint mode after,
2696+
therefore an evaluation error, or user-created error throw would overwrite it. */
2697+
ecma_value_t current_error_value = JERRY_CONTEXT (error_value);
26802698
if (jerry_debugger_send_exception_string ())
26812699
{
26822700
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT);
2701+
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_THROW_ERROR_FLAG)
2702+
{
2703+
ecma_free_value (current_error_value);
2704+
}
2705+
else
2706+
{
2707+
JERRY_CONTEXT (error_value) = current_error_value;
2708+
}
26832709
}
26842710
}
26852711
#endif /* JERRY_DEBUGGER */

jerry-debugger/jerry-client-ws.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@
8787
JERRY_DEBUGGER_GET_BACKTRACE = 15
8888
JERRY_DEBUGGER_EVAL = 16
8989
JERRY_DEBUGGER_EVAL_PART = 17
90+
JERRY_DEBUGGER_THROW = 18
91+
JERRY_DEBUGGER_THROW_PART = 19
9092

9193
MAX_BUFFER_SIZE = 128
9294
WEBSOCKET_BINARY_FRAME = 2
@@ -425,6 +427,8 @@ def _send_string(self, args, message_type):
425427

426428
if message_type == JERRY_DEBUGGER_EVAL:
427429
message_type = JERRY_DEBUGGER_EVAL_PART
430+
elif message_type == JERRY_DEBUGGER_THROW:
431+
message_type = JERRY_DEBUGGER_THROW_PART
428432
else:
429433
message_type = JERRY_DEBUGGER_CLIENT_SOURCE_PART
430434

@@ -453,6 +457,10 @@ def do_eval(self, args):
453457

454458
do_e = do_eval
455459

460+
def do_throw(self, args):
461+
""" Throw an exception """
462+
self._send_string(args, JERRY_DEBUGGER_THROW)
463+
456464
def do_exception(self, args):
457465
""" Config the exception handler module """
458466
if not args:

tests/debugger/do_help.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Stopped at tests/debugger/do_help.js:15
44

55
Documented commands (type help <topic>):
66
========================================
7-
b bt delete e help ms quit source
7+
b bt delete e help ms quit source throw
88
backtrace c display eval list n s src
99
break continue dump exception memstats next scroll step
1010

tests/debugger/do_throw.cmd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
throw new Error('Once upon a time there lived in a certain village a little country girl, the prettiest creature who was ever seen. Her mother was excessively fond of her; and her grandmother doted on her still more. This good woman had a little red riding hood made for her. It suited the girl so extremely well that everybody called her Little Red Riding Hood. One day her mother, having made some cakes, said to her, "Go, my dear, and see how your grandmother is doing, for I hear she has been very ill. Take her a cake, and this little pot of butter."')

tests/debugger/do_throw.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Connecting to: localhost:5001
2+
Stopped at tests/debugger/do_throw.js:19
3+
(jerry-debugger) throw new Error('Once upon a time there lived in a certain village a little country girl, the prettiest creature who was ever seen. Her mother was excessively fond of her; and her grandmother doted on her still more. This good woman had a little red riding hood made for her. It suited the girl so extremely well that everybody called her Little Red Riding Hood. One day her mother, having made some cakes, said to her, "Go, my dear, and see how your grandmother is doing, for I hear she has been very ill. Take her a cake, and this little pot of butter."')

tests/debugger/do_throw.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
function inevitable() {
16+
print("An error will be thrown.");
17+
}
18+
19+
inevitable();

0 commit comments

Comments
 (0)