diff --git a/jerry-core/debugger/jerry-debugger.c b/jerry-core/debugger/jerry-debugger.c index 0517d7cec1..65e67aa66c 100644 --- a/jerry-core/debugger/jerry-debugger.c +++ b/jerry-core/debugger/jerry-debugger.c @@ -16,12 +16,14 @@ #ifdef JERRY_DEBUGGER #include "byte-code.h" +#include "ecma-builtin-helpers.h" #include "ecma-conversion.h" #include "ecma-eval.h" #include "ecma-objects.h" #include "jcontext.h" #include "jerry-debugger.h" #include "jerryscript-port.h" +#include "lit-char-helpers.h" /** * Type cast the debugger send buffer into a specific type. @@ -715,4 +717,151 @@ jerry_debugger_send_memstats (void) jerry_debugger_send (sizeof (jerry_debugger_send_memstats_t)); } /* jerry_debugger_send_memstats */ +/* + * Converts an standard error into a string. + * + * @return standard error string + */ +static ecma_string_t * +jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /**< exception object */ +{ + ecma_object_t *object_p = ecma_get_object_from_value (exception_obj_value); + + ecma_object_t *prototype_p = ecma_get_object_prototype (object_p); + + if (prototype_p == NULL + || ecma_get_object_type (prototype_p) != ECMA_OBJECT_TYPE_GENERAL + || !ecma_get_object_is_builtin (prototype_p)) + { + return NULL; + } + + lit_magic_string_id_t string_id; + + switch (((ecma_extended_object_t *) prototype_p)->u.built_in.id) + { +#ifndef CONFIG_DISABLE_ERROR_BUILTINS + case ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_EVAL_ERROR_UL; + break; + } + case ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_RANGE_ERROR_UL; + break; + } + case ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_REFERENCE_ERROR_UL; + break; + } + case ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_SYNTAX_ERROR_UL; + break; + } + case ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_TYPE_ERROR_UL; + break; + } + case ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_URI_ERROR_UL; + break; + } +#endif /* !CONFIG_DISABLE_ERROR_BUILTINS */ + case ECMA_BUILTIN_ID_ERROR_PROTOTYPE: + { + string_id = LIT_MAGIC_STRING_ERROR_UL; + break; + } + default: + { + return NULL; + } + } + + lit_utf8_size_t size = lit_get_magic_string_size (string_id); + JERRY_ASSERT (size <= 14); + + lit_utf8_byte_t data[16]; + memcpy (data, lit_get_magic_string_utf8 (string_id), size); + + ecma_string_t message_string; + ecma_init_ecma_magic_string (&message_string, LIT_MAGIC_STRING_MESSAGE); + + ecma_property_t *property_p; + property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value), + &message_string); + + if (property_p == NULL + || ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA) + { + return ecma_new_ecma_string_from_utf8 (data, size); + } + + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + if (!ecma_is_value_string (prop_value_p->value)) + { + return ecma_new_ecma_string_from_utf8 (data, size); + } + + data[size] = LIT_CHAR_COLON; + data[size + 1] = LIT_CHAR_SP; + + ecma_string_t *type_string_p = ecma_new_ecma_string_from_utf8 (data, size + 2); + + ecma_string_t *string_p = ecma_concat_ecma_strings (type_string_p, + ecma_get_string_from_value (prop_value_p->value)); + ecma_deref_ecma_string (type_string_p); + return string_p; +} /* jerry_debugger_exception_object_to_string */ + +/** + * Send string representation of exception to the client. + * + * @return true - if the data sent successfully to the debugger client, + * false - otherwise + */ +bool +jerry_debugger_send_exception_string (ecma_value_t exception_value) /**< error value */ +{ + ecma_string_t *string_p = NULL; + + if (ecma_is_value_object (exception_value)) + { + ecma_value_t object_value = ecma_get_value_from_error_value (exception_value); + + string_p = jerry_debugger_exception_object_to_string (object_value); + if (string_p == NULL) + { + string_p = ecma_get_string_from_value (ecma_builtin_helper_object_to_string (object_value)); + } + } + else if (ecma_is_value_string (exception_value)) + { + string_p = ecma_get_string_from_value (exception_value); + ecma_ref_ecma_string (string_p); + } + else + { + exception_value = ecma_op_to_string (exception_value); + string_p = ecma_get_string_from_value (exception_value); + } + + ECMA_STRING_TO_UTF8_STRING (string_p, string_data_p, string_size); + + bool result = jerry_debugger_send_string (JERRY_DEBUGGER_EXCEPTION_STR, + string_data_p, + string_size); + + ECMA_FINALIZE_UTF8_STRING (string_data_p, string_size); + + ecma_deref_ecma_string (string_p); + return result; +} /* jerry_debugger_send_exception_string */ + #endif /* JERRY_DEBUGGER */ diff --git a/jerry-core/debugger/jerry-debugger.h b/jerry-core/debugger/jerry-debugger.h index 0232000f63..cbfcca0b2d 100644 --- a/jerry-core/debugger/jerry-debugger.h +++ b/jerry-core/debugger/jerry-debugger.h @@ -102,12 +102,14 @@ typedef enum JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14, /**< memstats sent to the client*/ JERRY_DEBUGGER_BREAKPOINT_HIT = 15, /**< notify breakpoint hit */ JERRY_DEBUGGER_EXCEPTION_HIT = 16, /**< notify exception hit */ - JERRY_DEBUGGER_BACKTRACE = 17, /**< backtrace data */ - JERRY_DEBUGGER_BACKTRACE_END = 18, /**< last backtrace data */ - JERRY_DEBUGGER_EVAL_RESULT = 19, /**< eval result */ - JERRY_DEBUGGER_EVAL_RESULT_END = 20, /**< last part of eval result */ - JERRY_DEBUGGER_EVAL_ERROR = 21, /**< eval result when an error is occured */ - JERRY_DEBUGGER_EVAL_ERROR_END = 22, /**< last part of eval result when an error is occured */ + JERRY_DEBUGGER_EXCEPTION_STR = 17, /**< exception string fragment */ + JERRY_DEBUGGER_EXCEPTION_STR_END = 18, /**< exception string last fragment */ + JERRY_DEBUGGER_BACKTRACE = 19, /**< backtrace data */ + 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_EVAL_ERROR = 23, /**< eval result when an error is occured */ + JERRY_DEBUGGER_EVAL_ERROR_END = 24, /**< last part of eval result when an error is occured */ /* Messages sent by the client to server. */ @@ -316,6 +318,7 @@ bool jerry_debugger_send_string (uint8_t message_type, const uint8_t *string_p, bool jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, ecma_compiled_code_t *compiled_code_p); bool jerry_debugger_send_parse_function (uint32_t line, uint32_t column); void jerry_debugger_send_memstats (void); +bool jerry_debugger_send_exception_string (ecma_value_t exception_value); #endif /* JERRY_DEBUGGER */ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index d66b7d5185..f364b9e391 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2550,7 +2550,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ && !(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE) && !(JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE))) { - jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT); + if (jerry_debugger_send_exception_string (result)) + { + jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT); + } } #endif /* JERRY_DEBUGGER */ } diff --git a/jerry-debugger/jerry-client-ws.html b/jerry-debugger/jerry-client-ws.html index 602cf175bf..c59da1d3bd 100644 --- a/jerry-debugger/jerry-client-ws.html +++ b/jerry-debugger/jerry-client-ws.html @@ -51,12 +51,14 @@

JerryScript HTML (WebSocket) Debugger Client

var JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14; var JERRY_DEBUGGER_BREAKPOINT_HIT = 15; var JERRY_DEBUGGER_EXCEPTION_HIT = 16; -var JERRY_DEBUGGER_BACKTRACE = 17; -var JERRY_DEBUGGER_BACKTRACE_END = 18; -var JERRY_DEBUGGER_EVAL_RESULT = 19; -var JERRY_DEBUGGER_EVAL_RESULT_END = 20; -var JERRY_DEBUGGER_EVAL_ERROR = 21; -var JERRY_DEBUGGER_EVAL_ERROR_END = 22; +var JERRY_DEBUGGER_EXCEPTION_STR = 17; +var JERRY_DEBUGGER_EXCEPTION_STR_END = 18; +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_EVAL_ERROR = 23; +var JERRY_DEBUGGER_EVAL_ERROR_END = 24; var JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1; var JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2; @@ -113,6 +115,7 @@

JerryScript HTML (WebSocket) Debugger Client

var pendingBreakpoints = [ ]; var backtraceFrame = 0; var evalResult = null; + var exceptionData = null; function assert(expr) { @@ -830,6 +833,11 @@

JerryScript HTML (WebSocket) Debugger Client

if (message[0] == JERRY_DEBUGGER_EXCEPTION_HIT) { appendLog("Exception throw detected (to disable automatic stop type exception 0)"); + if (exceptionData) + { + appendLog("Exception hint: " + cesu8ToString(exceptionData)); + exceptionData = null; + } } lastBreakpointHit = breakpoint; @@ -847,6 +855,13 @@

JerryScript HTML (WebSocket) Debugger Client

return; } + case JERRY_DEBUGGER_EXCEPTION_STR: + case JERRY_DEBUGGER_EXCEPTION_STR_END: + { + exceptionData = concatUint8Arrays(exceptionData, message); + return; + } + case JERRY_DEBUGGER_BACKTRACE: case JERRY_DEBUGGER_BACKTRACE_END: { diff --git a/jerry-debugger/jerry-client-ws.py b/jerry-debugger/jerry-client-ws.py index 92ac50bf13..6fa5ddb93e 100755 --- a/jerry-debugger/jerry-client-ws.py +++ b/jerry-debugger/jerry-client-ws.py @@ -42,12 +42,14 @@ JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14 JERRY_DEBUGGER_BREAKPOINT_HIT = 15 JERRY_DEBUGGER_EXCEPTION_HIT = 16 -JERRY_DEBUGGER_BACKTRACE = 17 -JERRY_DEBUGGER_BACKTRACE_END = 18 -JERRY_DEBUGGER_EVAL_RESULT = 19 -JERRY_DEBUGGER_EVAL_RESULT_END = 20 -JERRY_DEBUGGER_EVAL_ERROR = 21 -JERRY_DEBUGGER_EVAL_ERROR_END = 22 +JERRY_DEBUGGER_EXCEPTION_STR = 17 +JERRY_DEBUGGER_EXCEPTION_STR_END = 18 +JERRY_DEBUGGER_BACKTRACE = 19 +JERRY_DEBUGGER_BACKTRACE_END = 20 +JERRY_DEBUGGER_EVAL_RESULT = 21 +JERRY_DEBUGGER_EVAL_RESULT_END = 22 +JERRY_DEBUGGER_EVAL_ERROR = 23 +JERRY_DEBUGGER_EVAL_ERROR_END = 24 # Messages sent by the client to server. @@ -813,6 +815,7 @@ def main(): args = arguments_parse() debugger = JerryDebugger(args.address) + exception_string = "" non_interactive = args.non_interactive @@ -865,6 +868,9 @@ def main(): if buffer_type == JERRY_DEBUGGER_EXCEPTION_HIT: print("Exception throw detected (to disable automatic stop type exception 0)") + if exception_string: + print("Exception hint: %s" % (exception_string)) + exception_string = "" if breakpoint[1]: breakpoint_info = "at" @@ -880,6 +886,12 @@ def main(): if prompt.quit: break + elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR: + exception_string += data[3:] + + elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR_END: + exception_string += data[3:] + elif buffer_type in [JERRY_DEBUGGER_BACKTRACE, JERRY_DEBUGGER_BACKTRACE_END]: frame_index = 0 diff --git a/tests/debugger/do_exception.cmd b/tests/debugger/do_exception.cmd index c39e6424f9..c7df8d1ef4 100644 --- a/tests/debugger/do_exception.cmd +++ b/tests/debugger/do_exception.cmd @@ -1,2 +1,5 @@ c +c +c +c quit diff --git a/tests/debugger/do_exception.expected b/tests/debugger/do_exception.expected index a7c867ad52..beb78e2dac 100644 --- a/tests/debugger/do_exception.expected +++ b/tests/debugger/do_exception.expected @@ -2,5 +2,18 @@ Connecting to: localhost:5001 Stopped at tests/debugger/do_exception.js:15 (jerry-debugger) c Exception throw detected (to disable automatic stop type exception 0) -Stopped at tests/debugger/do_exception.js:19 (in foo() at line:17, col:1) +Exception hint: TypeError +Stopped around tests/debugger/do_exception.js:19 (in foo() at line:17, col:1) +(jerry-debugger) c +Exception throw detected (to disable automatic stop type exception 0) +Exception hint: ReferenceError +Stopped at tests/debugger/do_exception.js:24 (in foo() at line:17, col:1) +(jerry-debugger) c +Exception throw detected (to disable automatic stop type exception 0) +Exception hint: 456 +Stopped at tests/debugger/do_exception.js:29 (in foo() at line:17, col:1) +(jerry-debugger) c +Exception throw detected (to disable automatic stop type exception 0) +Exception hint: RangeError: Bad range! +Stopped around tests/debugger/do_exception.js:34 (in foo() at line:17, col:1) (jerry-debugger) quit diff --git a/tests/debugger/do_exception.js b/tests/debugger/do_exception.js index aeb9cecf87..a3c3e1c728 100644 --- a/tests/debugger/do_exception.js +++ b/tests/debugger/do_exception.js @@ -15,11 +15,25 @@ print("exception handler configuration test") function foo() { - try { - b = a / c; - } catch (e) { - print(e); // pass exception object to err handler - } + try { + undefined(); + } catch (e) { + } + + try { + xxx(); + } catch (e) { + } + + try { + throw 456; + } catch (e) { + } + + try { + throw new RangeError("Bad range!"); + } catch (e) { + } } foo()