Print exception hint in the debugger client when an exception is thrown. (#1841)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2017-05-23 16:06:25 +02:00 committed by GitHub
parent 7770b6237a
commit 29f57ec58f
8 changed files with 237 additions and 25 deletions

View File

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

View File

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

View File

@ -2550,7 +2550,10 @@ error:
&& !(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 */
}

View File

@ -51,12 +51,14 @@ var JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13;
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 @@ function DebuggerClient(address)
var pendingBreakpoints = [ ];
var backtraceFrame = 0;
var evalResult = null;
var exceptionData = null;
function assert(expr)
{
@ -830,6 +833,11 @@ function DebuggerClient(address)
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 @@ function DebuggerClient(address)
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:
{

View File

@ -42,12 +42,14 @@ JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13
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

View File

@ -1,2 +1,5 @@
c
c
c
c
quit

View File

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

View File

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