Skip to content

Commit 29f57ec

Browse files
authored
Print exception hint in the debugger client when an exception is thrown. (jerryscript-project#1841)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
1 parent 7770b62 commit 29f57ec

File tree

8 files changed

+237
-25
lines changed

8 files changed

+237
-25
lines changed

jerry-core/debugger/jerry-debugger.c

+149
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
#ifdef JERRY_DEBUGGER
1717

1818
#include "byte-code.h"
19+
#include "ecma-builtin-helpers.h"
1920
#include "ecma-conversion.h"
2021
#include "ecma-eval.h"
2122
#include "ecma-objects.h"
2223
#include "jcontext.h"
2324
#include "jerry-debugger.h"
2425
#include "jerryscript-port.h"
26+
#include "lit-char-helpers.h"
2527

2628
/**
2729
* Type cast the debugger send buffer into a specific type.
@@ -715,4 +717,151 @@ jerry_debugger_send_memstats (void)
715717
jerry_debugger_send (sizeof (jerry_debugger_send_memstats_t));
716718
} /* jerry_debugger_send_memstats */
717719

720+
/*
721+
* Converts an standard error into a string.
722+
*
723+
* @return standard error string
724+
*/
725+
static ecma_string_t *
726+
jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /**< exception object */
727+
{
728+
ecma_object_t *object_p = ecma_get_object_from_value (exception_obj_value);
729+
730+
ecma_object_t *prototype_p = ecma_get_object_prototype (object_p);
731+
732+
if (prototype_p == NULL
733+
|| ecma_get_object_type (prototype_p) != ECMA_OBJECT_TYPE_GENERAL
734+
|| !ecma_get_object_is_builtin (prototype_p))
735+
{
736+
return NULL;
737+
}
738+
739+
lit_magic_string_id_t string_id;
740+
741+
switch (((ecma_extended_object_t *) prototype_p)->u.built_in.id)
742+
{
743+
#ifndef CONFIG_DISABLE_ERROR_BUILTINS
744+
case ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE:
745+
{
746+
string_id = LIT_MAGIC_STRING_EVAL_ERROR_UL;
747+
break;
748+
}
749+
case ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE:
750+
{
751+
string_id = LIT_MAGIC_STRING_RANGE_ERROR_UL;
752+
break;
753+
}
754+
case ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE:
755+
{
756+
string_id = LIT_MAGIC_STRING_REFERENCE_ERROR_UL;
757+
break;
758+
}
759+
case ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE:
760+
{
761+
string_id = LIT_MAGIC_STRING_SYNTAX_ERROR_UL;
762+
break;
763+
}
764+
case ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE:
765+
{
766+
string_id = LIT_MAGIC_STRING_TYPE_ERROR_UL;
767+
break;
768+
}
769+
case ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE:
770+
{
771+
string_id = LIT_MAGIC_STRING_URI_ERROR_UL;
772+
break;
773+
}
774+
#endif /* !CONFIG_DISABLE_ERROR_BUILTINS */
775+
case ECMA_BUILTIN_ID_ERROR_PROTOTYPE:
776+
{
777+
string_id = LIT_MAGIC_STRING_ERROR_UL;
778+
break;
779+
}
780+
default:
781+
{
782+
return NULL;
783+
}
784+
}
785+
786+
lit_utf8_size_t size = lit_get_magic_string_size (string_id);
787+
JERRY_ASSERT (size <= 14);
788+
789+
lit_utf8_byte_t data[16];
790+
memcpy (data, lit_get_magic_string_utf8 (string_id), size);
791+
792+
ecma_string_t message_string;
793+
ecma_init_ecma_magic_string (&message_string, LIT_MAGIC_STRING_MESSAGE);
794+
795+
ecma_property_t *property_p;
796+
property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value),
797+
&message_string);
798+
799+
if (property_p == NULL
800+
|| ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA)
801+
{
802+
return ecma_new_ecma_string_from_utf8 (data, size);
803+
}
804+
805+
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
806+
807+
if (!ecma_is_value_string (prop_value_p->value))
808+
{
809+
return ecma_new_ecma_string_from_utf8 (data, size);
810+
}
811+
812+
data[size] = LIT_CHAR_COLON;
813+
data[size + 1] = LIT_CHAR_SP;
814+
815+
ecma_string_t *type_string_p = ecma_new_ecma_string_from_utf8 (data, size + 2);
816+
817+
ecma_string_t *string_p = ecma_concat_ecma_strings (type_string_p,
818+
ecma_get_string_from_value (prop_value_p->value));
819+
ecma_deref_ecma_string (type_string_p);
820+
return string_p;
821+
} /* jerry_debugger_exception_object_to_string */
822+
823+
/**
824+
* Send string representation of exception to the client.
825+
*
826+
* @return true - if the data sent successfully to the debugger client,
827+
* false - otherwise
828+
*/
829+
bool
830+
jerry_debugger_send_exception_string (ecma_value_t exception_value) /**< error value */
831+
{
832+
ecma_string_t *string_p = NULL;
833+
834+
if (ecma_is_value_object (exception_value))
835+
{
836+
ecma_value_t object_value = ecma_get_value_from_error_value (exception_value);
837+
838+
string_p = jerry_debugger_exception_object_to_string (object_value);
839+
if (string_p == NULL)
840+
{
841+
string_p = ecma_get_string_from_value (ecma_builtin_helper_object_to_string (object_value));
842+
}
843+
}
844+
else if (ecma_is_value_string (exception_value))
845+
{
846+
string_p = ecma_get_string_from_value (exception_value);
847+
ecma_ref_ecma_string (string_p);
848+
}
849+
else
850+
{
851+
exception_value = ecma_op_to_string (exception_value);
852+
string_p = ecma_get_string_from_value (exception_value);
853+
}
854+
855+
ECMA_STRING_TO_UTF8_STRING (string_p, string_data_p, string_size);
856+
857+
bool result = jerry_debugger_send_string (JERRY_DEBUGGER_EXCEPTION_STR,
858+
string_data_p,
859+
string_size);
860+
861+
ECMA_FINALIZE_UTF8_STRING (string_data_p, string_size);
862+
863+
ecma_deref_ecma_string (string_p);
864+
return result;
865+
} /* jerry_debugger_send_exception_string */
866+
718867
#endif /* JERRY_DEBUGGER */

jerry-core/debugger/jerry-debugger.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,14 @@ typedef enum
102102
JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14, /**< memstats sent to the client*/
103103
JERRY_DEBUGGER_BREAKPOINT_HIT = 15, /**< notify breakpoint hit */
104104
JERRY_DEBUGGER_EXCEPTION_HIT = 16, /**< notify exception hit */
105-
JERRY_DEBUGGER_BACKTRACE = 17, /**< backtrace data */
106-
JERRY_DEBUGGER_BACKTRACE_END = 18, /**< last backtrace data */
107-
JERRY_DEBUGGER_EVAL_RESULT = 19, /**< eval result */
108-
JERRY_DEBUGGER_EVAL_RESULT_END = 20, /**< last part of eval result */
109-
JERRY_DEBUGGER_EVAL_ERROR = 21, /**< eval result when an error is occured */
110-
JERRY_DEBUGGER_EVAL_ERROR_END = 22, /**< last part of eval result when an error is occured */
105+
JERRY_DEBUGGER_EXCEPTION_STR = 17, /**< exception string fragment */
106+
JERRY_DEBUGGER_EXCEPTION_STR_END = 18, /**< exception string last fragment */
107+
JERRY_DEBUGGER_BACKTRACE = 19, /**< backtrace data */
108+
JERRY_DEBUGGER_BACKTRACE_END = 20, /**< last backtrace data */
109+
JERRY_DEBUGGER_EVAL_RESULT = 21, /**< eval result */
110+
JERRY_DEBUGGER_EVAL_RESULT_END = 22, /**< last part of eval result */
111+
JERRY_DEBUGGER_EVAL_ERROR = 23, /**< eval result when an error is occured */
112+
JERRY_DEBUGGER_EVAL_ERROR_END = 24, /**< last part of eval result when an error is occured */
111113

112114
/* Messages sent by the client to server. */
113115

@@ -316,6 +318,7 @@ bool jerry_debugger_send_string (uint8_t message_type, const uint8_t *string_p,
316318
bool jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, ecma_compiled_code_t *compiled_code_p);
317319
bool jerry_debugger_send_parse_function (uint32_t line, uint32_t column);
318320
void jerry_debugger_send_memstats (void);
321+
bool jerry_debugger_send_exception_string (ecma_value_t exception_value);
319322

320323
#endif /* JERRY_DEBUGGER */
321324

jerry-core/vm/vm.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -2550,7 +2550,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
25502550
&& !(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
25512551
&& !(JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE)))
25522552
{
2553-
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT);
2553+
if (jerry_debugger_send_exception_string (result))
2554+
{
2555+
jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT);
2556+
}
25542557
}
25552558
#endif /* JERRY_DEBUGGER */
25562559
}

jerry-debugger/jerry-client-ws.html

+21-6
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
5151
var JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14;
5252
var JERRY_DEBUGGER_BREAKPOINT_HIT = 15;
5353
var JERRY_DEBUGGER_EXCEPTION_HIT = 16;
54-
var JERRY_DEBUGGER_BACKTRACE = 17;
55-
var JERRY_DEBUGGER_BACKTRACE_END = 18;
56-
var JERRY_DEBUGGER_EVAL_RESULT = 19;
57-
var JERRY_DEBUGGER_EVAL_RESULT_END = 20;
58-
var JERRY_DEBUGGER_EVAL_ERROR = 21;
59-
var JERRY_DEBUGGER_EVAL_ERROR_END = 22;
54+
var JERRY_DEBUGGER_EXCEPTION_STR = 17;
55+
var JERRY_DEBUGGER_EXCEPTION_STR_END = 18;
56+
var JERRY_DEBUGGER_BACKTRACE = 19;
57+
var JERRY_DEBUGGER_BACKTRACE_END = 20;
58+
var JERRY_DEBUGGER_EVAL_RESULT = 21;
59+
var JERRY_DEBUGGER_EVAL_RESULT_END = 22;
60+
var JERRY_DEBUGGER_EVAL_ERROR = 23;
61+
var JERRY_DEBUGGER_EVAL_ERROR_END = 24;
6062

6163
var JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1;
6264
var JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2;
@@ -113,6 +115,7 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
113115
var pendingBreakpoints = [ ];
114116
var backtraceFrame = 0;
115117
var evalResult = null;
118+
var exceptionData = null;
116119

117120
function assert(expr)
118121
{
@@ -830,6 +833,11 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
830833
if (message[0] == JERRY_DEBUGGER_EXCEPTION_HIT)
831834
{
832835
appendLog("Exception throw detected (to disable automatic stop type exception 0)");
836+
if (exceptionData)
837+
{
838+
appendLog("Exception hint: " + cesu8ToString(exceptionData));
839+
exceptionData = null;
840+
}
833841
}
834842

835843
lastBreakpointHit = breakpoint;
@@ -847,6 +855,13 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
847855
return;
848856
}
849857

858+
case JERRY_DEBUGGER_EXCEPTION_STR:
859+
case JERRY_DEBUGGER_EXCEPTION_STR_END:
860+
{
861+
exceptionData = concatUint8Arrays(exceptionData, message);
862+
return;
863+
}
864+
850865
case JERRY_DEBUGGER_BACKTRACE:
851866
case JERRY_DEBUGGER_BACKTRACE_END:
852867
{

jerry-debugger/jerry-client-ws.py

+18-6
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@
4242
JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14
4343
JERRY_DEBUGGER_BREAKPOINT_HIT = 15
4444
JERRY_DEBUGGER_EXCEPTION_HIT = 16
45-
JERRY_DEBUGGER_BACKTRACE = 17
46-
JERRY_DEBUGGER_BACKTRACE_END = 18
47-
JERRY_DEBUGGER_EVAL_RESULT = 19
48-
JERRY_DEBUGGER_EVAL_RESULT_END = 20
49-
JERRY_DEBUGGER_EVAL_ERROR = 21
50-
JERRY_DEBUGGER_EVAL_ERROR_END = 22
45+
JERRY_DEBUGGER_EXCEPTION_STR = 17
46+
JERRY_DEBUGGER_EXCEPTION_STR_END = 18
47+
JERRY_DEBUGGER_BACKTRACE = 19
48+
JERRY_DEBUGGER_BACKTRACE_END = 20
49+
JERRY_DEBUGGER_EVAL_RESULT = 21
50+
JERRY_DEBUGGER_EVAL_RESULT_END = 22
51+
JERRY_DEBUGGER_EVAL_ERROR = 23
52+
JERRY_DEBUGGER_EVAL_ERROR_END = 24
5153

5254

5355
# Messages sent by the client to server.
@@ -813,6 +815,7 @@ def main():
813815
args = arguments_parse()
814816

815817
debugger = JerryDebugger(args.address)
818+
exception_string = ""
816819

817820
non_interactive = args.non_interactive
818821

@@ -865,6 +868,9 @@ def main():
865868

866869
if buffer_type == JERRY_DEBUGGER_EXCEPTION_HIT:
867870
print("Exception throw detected (to disable automatic stop type exception 0)")
871+
if exception_string:
872+
print("Exception hint: %s" % (exception_string))
873+
exception_string = ""
868874

869875
if breakpoint[1]:
870876
breakpoint_info = "at"
@@ -880,6 +886,12 @@ def main():
880886
if prompt.quit:
881887
break
882888

889+
elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR:
890+
exception_string += data[3:]
891+
892+
elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR_END:
893+
exception_string += data[3:]
894+
883895
elif buffer_type in [JERRY_DEBUGGER_BACKTRACE, JERRY_DEBUGGER_BACKTRACE_END]:
884896
frame_index = 0
885897

tests/debugger/do_exception.cmd

+3
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
c
2+
c
3+
c
4+
c
25
quit

tests/debugger/do_exception.expected

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,18 @@ Connecting to: localhost:5001
22
Stopped at tests/debugger/do_exception.js:15
33
(jerry-debugger) c
44
Exception throw detected (to disable automatic stop type exception 0)
5-
Stopped at tests/debugger/do_exception.js:19 (in foo() at line:17, col:1)
5+
Exception hint: TypeError
6+
Stopped around tests/debugger/do_exception.js:19 (in foo() at line:17, col:1)
7+
(jerry-debugger) c
8+
Exception throw detected (to disable automatic stop type exception 0)
9+
Exception hint: ReferenceError
10+
Stopped at tests/debugger/do_exception.js:24 (in foo() at line:17, col:1)
11+
(jerry-debugger) c
12+
Exception throw detected (to disable automatic stop type exception 0)
13+
Exception hint: 456
14+
Stopped at tests/debugger/do_exception.js:29 (in foo() at line:17, col:1)
15+
(jerry-debugger) c
16+
Exception throw detected (to disable automatic stop type exception 0)
17+
Exception hint: RangeError: Bad range!
18+
Stopped around tests/debugger/do_exception.js:34 (in foo() at line:17, col:1)
619
(jerry-debugger) quit

tests/debugger/do_exception.js

+19-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,25 @@
1515
print("exception handler configuration test")
1616

1717
function foo() {
18-
try {
19-
b = a / c;
20-
} catch (e) {
21-
print(e); // pass exception object to err handler
22-
}
18+
try {
19+
undefined();
20+
} catch (e) {
21+
}
22+
23+
try {
24+
xxx();
25+
} catch (e) {
26+
}
27+
28+
try {
29+
throw 456;
30+
} catch (e) {
31+
}
32+
33+
try {
34+
throw new RangeError("Bad range!");
35+
} catch (e) {
36+
}
2337
}
2438

2539
foo()

0 commit comments

Comments
 (0)