Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions jerry-core/debugger/jerry-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 */
15 changes: 9 additions & 6 deletions jerry-core/debugger/jerry-debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand Down Expand Up @@ -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 */

Expand Down
5 changes: 4 additions & 1 deletion jerry-core/vm/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
}
Expand Down
27 changes: 21 additions & 6 deletions jerry-debugger/jerry-client-ws.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
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;
Expand Down Expand Up @@ -113,6 +115,7 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
var pendingBreakpoints = [ ];
var backtraceFrame = 0;
var evalResult = null;
var exceptionData = null;

function assert(expr)
{
Expand Down Expand Up @@ -830,6 +833,11 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
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;
Expand All @@ -847,6 +855,13 @@ <h2>JerryScript HTML (WebSocket) Debugger Client</h2>
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:
{
Expand Down
24 changes: 18 additions & 6 deletions jerry-debugger/jerry-client-ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -813,6 +815,7 @@ def main():
args = arguments_parse()

debugger = JerryDebugger(args.address)
exception_string = ""

non_interactive = args.non_interactive

Expand Down Expand Up @@ -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"
Expand All @@ -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

Expand Down
3 changes: 3 additions & 0 deletions tests/debugger/do_exception.cmd
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
c
c
c
c
quit
15 changes: 14 additions & 1 deletion tests/debugger/do_exception.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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
24 changes: 19 additions & 5 deletions tests/debugger/do_exception.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()