Add Stop at exception feature to the debugger (#1693)
JerryScript-DCO-1.0-Signed-off-by: Levente Orban orbanl@inf.u-szeged.hu
This commit is contained in:
committed by
Zoltan Herczeg
parent
da07252c45
commit
21cec3eb16
@@ -42,22 +42,24 @@ var JERRY_DEBUGGER_FUNCTION_NAME = 11;
|
||||
var JERRY_DEBUGGER_FUNCTION_NAME_END = 12;
|
||||
var JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13;
|
||||
var JERRY_DEBUGGER_BREAKPOINT_HIT = 14;
|
||||
var JERRY_DEBUGGER_BACKTRACE = 15;
|
||||
var JERRY_DEBUGGER_BACKTRACE_END = 16;
|
||||
var JERRY_DEBUGGER_EVAL_RESULT = 17;
|
||||
var JERRY_DEBUGGER_EVAL_RESULT_END = 18;
|
||||
var JERRY_DEBUGGER_EVAL_ERROR = 19;
|
||||
var JERRY_DEBUGGER_EVAL_ERROR_END = 20;
|
||||
var JERRY_DEBUGGER_EXCEPTION_HIT = 15;
|
||||
var JERRY_DEBUGGER_BACKTRACE = 16;
|
||||
var JERRY_DEBUGGER_BACKTRACE_END = 17;
|
||||
var JERRY_DEBUGGER_EVAL_RESULT = 18;
|
||||
var JERRY_DEBUGGER_EVAL_RESULT_END = 19;
|
||||
var JERRY_DEBUGGER_EVAL_ERROR = 20;
|
||||
var JERRY_DEBUGGER_EVAL_ERROR_END = 21;
|
||||
|
||||
var JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1;
|
||||
var JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2;
|
||||
var JERRY_DEBUGGER_STOP = 3;
|
||||
var JERRY_DEBUGGER_CONTINUE = 4;
|
||||
var JERRY_DEBUGGER_STEP = 5;
|
||||
var JERRY_DEBUGGER_NEXT = 6;
|
||||
var JERRY_DEBUGGER_GET_BACKTRACE = 7;
|
||||
var JERRY_DEBUGGER_EVAL = 8;
|
||||
var JERRY_DEBUGGER_EVAL_PART = 9;
|
||||
var JERRY_DEBUGGER_EXCEPTION_CONFIG = 3;
|
||||
var JERRY_DEBUGGER_STOP = 4;
|
||||
var JERRY_DEBUGGER_CONTINUE = 5;
|
||||
var JERRY_DEBUGGER_STEP = 6;
|
||||
var JERRY_DEBUGGER_NEXT = 7;
|
||||
var JERRY_DEBUGGER_GET_BACKTRACE = 8;
|
||||
var JERRY_DEBUGGER_EVAL = 9;
|
||||
var JERRY_DEBUGGER_EVAL_PART = 10;
|
||||
|
||||
var textBox = document.getElementById("log");
|
||||
var commandBox = document.getElementById("command");
|
||||
@@ -495,6 +497,41 @@ function DebuggerClient(address)
|
||||
socket.send(message);
|
||||
}
|
||||
|
||||
function getBreakpoint(breakpointData)
|
||||
{
|
||||
var returnValue = {};
|
||||
var func = functions[breakpointData[0]];
|
||||
var offset = breakpointData[1];
|
||||
|
||||
if (offset in functions)
|
||||
{
|
||||
returnValue.breakpoint = func.offsets[offset];
|
||||
returnValue.at = true;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
if (offset < functions.firstBreakpointOffset)
|
||||
{
|
||||
returnValue.breakpoint = func.offsets[firstBreakpointOffset];
|
||||
returnValue.at = true;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
nearest_offset = -1;
|
||||
|
||||
for (var current_offset in func.offsets)
|
||||
{
|
||||
if ((current_offset <= offset) && (current_offset > nearest_offset))
|
||||
{
|
||||
nearest_offset = current_offset;
|
||||
}
|
||||
}
|
||||
|
||||
returnValue.breakpoint = func.offsets[nearest_offset];
|
||||
returnValue.at = false;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
this.encodeMessage = encodeMessage;
|
||||
|
||||
function ParseSource()
|
||||
@@ -606,6 +643,7 @@ function DebuggerClient(address)
|
||||
offsets = {}
|
||||
|
||||
func.firstBreakpointLine = func.lines[0];
|
||||
func.firstBreakpointOffset = func.offsets[0];
|
||||
|
||||
for (var i = 0; i < func.lines.length; i++)
|
||||
{
|
||||
@@ -729,20 +767,29 @@ function DebuggerClient(address)
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_BREAKPOINT_HIT:
|
||||
case JERRY_DEBUGGER_EXCEPTION_HIT:
|
||||
{
|
||||
var breakpoint = decodeMessage("CI", message, 1);
|
||||
var breakpointData = decodeMessage("CI", message, 1);
|
||||
var breakpointRef = getBreakpoint(breakpointData);
|
||||
var breakpoint = breakpointRef.breakpoint;
|
||||
|
||||
breakpoint = functions[breakpoint[0]].offsets[breakpoint[1]];
|
||||
if (message[0] == JERRY_DEBUGGER_EXCEPTION_HIT)
|
||||
{
|
||||
appendLog("Exception throw detected (to disable automatic stop type exception 0)");
|
||||
}
|
||||
|
||||
lastBreakpointHit = breakpoint;
|
||||
|
||||
breakpointIndex = "";
|
||||
if (breakpoint.activeIndex >= 0)
|
||||
var breakpointInfo = "";
|
||||
if (breakpoint.offset.activeIndex >= 0)
|
||||
{
|
||||
breakpointIndex = "breakpoint:" + breakpoint.activeIndex + " ";
|
||||
breakpointInfo = " breakpoint:" + breakpoint.offset.activeIndex + " ";
|
||||
}
|
||||
|
||||
appendLog("Stopped at " + breakpointIndex + breakpointToString(breakpoint));
|
||||
appendLog("Stopped "
|
||||
+ (breakpoint.at ? "at " : "around ")
|
||||
+ breakpointInfo
|
||||
+ breakpointToString(breakpoint));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -751,31 +798,14 @@ function DebuggerClient(address)
|
||||
{
|
||||
for (var i = 1; i < message.byteLength; i += cpointerSize + 4)
|
||||
{
|
||||
var breakpoint = decodeMessage("CI", message, i);
|
||||
var func = functions[breakpoint[0]];
|
||||
var best_offset = -1;
|
||||
var breakpointData = decodeMessage("CI", message, i);
|
||||
|
||||
for (var offset in func.offsets)
|
||||
{
|
||||
if (offset <= breakpoint[1] && offset > best_offset)
|
||||
{
|
||||
best_offset = offset;
|
||||
}
|
||||
}
|
||||
breakpoint = getBreakpoint(breakpointData).breakpoint;
|
||||
|
||||
if (best_offset >= 0)
|
||||
{
|
||||
breakpoint = func.offsets[best_offset];
|
||||
appendLog(" frame " + backtraceFrame + ": " + breakpointToString(breakpoint));
|
||||
}
|
||||
else if (func.name)
|
||||
{
|
||||
appendLog(" frame " + backtraceFrame + ": " + func.name + "()");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendLog(" frame " + backtraceFrame + ": <unknown>()");
|
||||
}
|
||||
appendLog(" frame "
|
||||
+ backtraceFrame
|
||||
+ ": "
|
||||
+ breakpointToString(breakpoint));
|
||||
|
||||
++backtraceFrame;
|
||||
}
|
||||
@@ -873,6 +903,31 @@ function DebuggerClient(address)
|
||||
}
|
||||
}
|
||||
|
||||
this.sendExceptionConfig = function(enable)
|
||||
{
|
||||
if (enable == "")
|
||||
{
|
||||
appendLog("Argument required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable == 1)
|
||||
{
|
||||
appendLog("Stop at exception enabled");
|
||||
}
|
||||
else if (enable == 0)
|
||||
{
|
||||
appendLog("Stop at exception disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendLog("Invalid input. Usage 1: [Enable] or 0: [Disable].");
|
||||
return;
|
||||
}
|
||||
|
||||
encodeMessage("BB", [ JERRY_DEBUGGER_EXCEPTION_CONFIG, enable ]);
|
||||
}
|
||||
|
||||
this.deleteBreakpoint = function(index)
|
||||
{
|
||||
breakpoint = activeBreakpoints[index];
|
||||
@@ -1178,6 +1233,10 @@ function debuggerCommand(event)
|
||||
debuggerObj.sendGetBacktrace(max_depth);
|
||||
break;
|
||||
|
||||
case "exception":
|
||||
debuggerObj.sendExceptionConfig(args[2]);
|
||||
break;
|
||||
|
||||
case "src":
|
||||
debuggerObj.printSource();
|
||||
break;
|
||||
|
||||
@@ -40,23 +40,26 @@ JERRY_DEBUGGER_FUNCTION_NAME = 11
|
||||
JERRY_DEBUGGER_FUNCTION_NAME_END = 12
|
||||
JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13
|
||||
JERRY_DEBUGGER_BREAKPOINT_HIT = 14
|
||||
JERRY_DEBUGGER_BACKTRACE = 15
|
||||
JERRY_DEBUGGER_BACKTRACE_END = 16
|
||||
JERRY_DEBUGGER_EVAL_RESULT = 17
|
||||
JERRY_DEBUGGER_EVAL_RESULT_END = 18
|
||||
JERRY_DEBUGGER_EVAL_ERROR = 19
|
||||
JERRY_DEBUGGER_EVAL_ERROR_END = 20
|
||||
JERRY_DEBUGGER_EXCEPTION_HIT = 15
|
||||
JERRY_DEBUGGER_BACKTRACE = 16
|
||||
JERRY_DEBUGGER_BACKTRACE_END = 17
|
||||
JERRY_DEBUGGER_EVAL_RESULT = 18
|
||||
JERRY_DEBUGGER_EVAL_RESULT_END = 19
|
||||
JERRY_DEBUGGER_EVAL_ERROR = 20
|
||||
JERRY_DEBUGGER_EVAL_ERROR_END = 21
|
||||
|
||||
|
||||
# Messages sent by the client to server.
|
||||
JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1
|
||||
JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2
|
||||
JERRY_DEBUGGER_STOP = 3
|
||||
JERRY_DEBUGGER_CONTINUE = 4
|
||||
JERRY_DEBUGGER_STEP = 5
|
||||
JERRY_DEBUGGER_NEXT = 6
|
||||
JERRY_DEBUGGER_GET_BACKTRACE = 7
|
||||
JERRY_DEBUGGER_EVAL = 8
|
||||
JERRY_DEBUGGER_EVAL_PART = 9
|
||||
JERRY_DEBUGGER_EXCEPTION_CONFIG = 3
|
||||
JERRY_DEBUGGER_STOP = 4
|
||||
JERRY_DEBUGGER_CONTINUE = 5
|
||||
JERRY_DEBUGGER_STEP = 6
|
||||
JERRY_DEBUGGER_NEXT = 7
|
||||
JERRY_DEBUGGER_GET_BACKTRACE = 8
|
||||
JERRY_DEBUGGER_EVAL = 9
|
||||
JERRY_DEBUGGER_EVAL_PART = 10
|
||||
|
||||
MAX_BUFFER_SIZE = 128
|
||||
WEBSOCKET_BINARY_FRAME = 2
|
||||
@@ -122,6 +125,7 @@ class JerryFunction(object):
|
||||
self.line = line
|
||||
self.column = column
|
||||
self.first_breakpoint_line = lines[0]
|
||||
self.first_breakpoint_offset = offsets[0]
|
||||
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
@@ -332,6 +336,24 @@ class DebuggerPrompt(Cmd):
|
||||
|
||||
do_e = do_eval
|
||||
|
||||
def do_exception(self, args):
|
||||
""" Config the exception handler module """
|
||||
if not args:
|
||||
print("Error: Status expected!")
|
||||
return
|
||||
|
||||
enable = int(args)
|
||||
|
||||
if enable == 1:
|
||||
logging.debug("Stop at exception enabled")
|
||||
elif enable == 0:
|
||||
logging.debug("Stop at exception disabled")
|
||||
else:
|
||||
print("Error: Invalid input! Usage 1: [Enable] or 0: [Disable].")
|
||||
return
|
||||
|
||||
self.debugger.send_exception_config(enable)
|
||||
|
||||
|
||||
class Multimap(object):
|
||||
|
||||
@@ -475,13 +497,13 @@ class JerryDebugger(object):
|
||||
self.send_message(message)
|
||||
|
||||
def send_bytecode_cp(self, byte_code_cp):
|
||||
message = struct.pack(self.byte_order + "BBIB" + self.cp_format,
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + self.cp_size,
|
||||
0,
|
||||
JERRY_DEBUGGER_FREE_BYTE_CODE_CP,
|
||||
byte_code_cp)
|
||||
self.send_message(message)
|
||||
message = struct.pack(self.byte_order + "BBIB" + self.cp_format,
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + self.cp_size,
|
||||
0,
|
||||
JERRY_DEBUGGER_FREE_BYTE_CODE_CP,
|
||||
byte_code_cp)
|
||||
self.send_message(message)
|
||||
|
||||
def send_command(self, command):
|
||||
message = struct.pack(self.byte_order + "BBIB",
|
||||
@@ -491,6 +513,15 @@ class JerryDebugger(object):
|
||||
command)
|
||||
self.send_message(message)
|
||||
|
||||
def send_exception_config(self, enable):
|
||||
message = struct.pack(self.byte_order + "BBIBB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 1,
|
||||
0,
|
||||
JERRY_DEBUGGER_EXCEPTION_CONFIG,
|
||||
enable)
|
||||
self.send_message(message)
|
||||
|
||||
def get_message(self, blocking):
|
||||
# Connection was closed
|
||||
if self.message_data is None:
|
||||
@@ -698,6 +729,23 @@ def set_breakpoint(debugger, string):
|
||||
print("Breakpoint not found")
|
||||
return
|
||||
|
||||
def get_breakpoint(debugger, breakpoint_data):
|
||||
function = debugger.function_list[breakpoint_data[0]]
|
||||
offset = breakpoint_data[1]
|
||||
|
||||
if offset in function.offsets:
|
||||
return (function.offsets[offset], True)
|
||||
|
||||
if offset < function.first_breakpoint_offset:
|
||||
return (function.offsets[function.first_breakpoint_offset], False)
|
||||
|
||||
nearest_offset = -1
|
||||
|
||||
for current_offset in function.offsets:
|
||||
if current_offset <= offset and current_offset > nearest_offset:
|
||||
nearest_offset = current_offset
|
||||
|
||||
return (function.offsets[nearest_offset], False)
|
||||
|
||||
def main():
|
||||
args = arguments_parse()
|
||||
@@ -747,19 +795,24 @@ def main():
|
||||
elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
|
||||
release_function(debugger, data)
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_BREAKPOINT_HIT:
|
||||
elif buffer_type in [JERRY_DEBUGGER_BREAKPOINT_HIT, JERRY_DEBUGGER_EXCEPTION_HIT]:
|
||||
breakpoint_data = struct.unpack(debugger.byte_order + debugger.cp_format + debugger.idx_format, data[3:])
|
||||
|
||||
function = debugger.function_list[breakpoint_data[0]]
|
||||
breakpoint = function.offsets[breakpoint_data[1]]
|
||||
breakpoint = get_breakpoint(debugger, breakpoint_data)
|
||||
debugger.last_breakpoint_hit = breakpoint[0]
|
||||
|
||||
debugger.last_breakpoint_hit = breakpoint
|
||||
if buffer_type == JERRY_DEBUGGER_EXCEPTION_HIT:
|
||||
print("Exception throw detected (to disable automatic stop type exception 0)")
|
||||
|
||||
breakpoint_index = ""
|
||||
if breakpoint.active_index >= 0:
|
||||
breakpoint_index = " breakpoint:%d" % (breakpoint.active_index)
|
||||
if breakpoint[1]:
|
||||
breakpoint_info = "at"
|
||||
else:
|
||||
breakpoint_info = "around"
|
||||
|
||||
print("Stopped at%s %s" % (breakpoint_index, breakpoint.to_string()))
|
||||
if breakpoint[0].active_index >= 0:
|
||||
breakpoint_info += " breakpoint:%d" % (breakpoint[0].active_index)
|
||||
|
||||
print("Stopped %s %s" % (breakpoint_info, breakpoint[0].to_string()))
|
||||
|
||||
prompt.cmdloop()
|
||||
if prompt.quit:
|
||||
@@ -775,20 +828,9 @@ def main():
|
||||
breakpoint_data = struct.unpack(debugger.byte_order + debugger.cp_format + debugger.idx_format,
|
||||
data[buffer_pos: buffer_pos + debugger.cp_size + 4])
|
||||
|
||||
function = debugger.function_list[breakpoint_data[0]]
|
||||
best_offset = -1
|
||||
breakpoint = get_breakpoint(debugger, breakpoint_data)
|
||||
|
||||
for offset in function.offsets:
|
||||
if offset <= breakpoint_data[1] and offset > best_offset:
|
||||
best_offset = offset
|
||||
|
||||
if best_offset >= 0:
|
||||
breakpoint = function.offsets[best_offset]
|
||||
print("Frame %d: %s" % (frame_index, breakpoint.to_string()))
|
||||
elif function.name:
|
||||
print("Frame %d: %s()" % (frame_index, function.name))
|
||||
else:
|
||||
print("Frame %d: <unknown>()" % (frame_index))
|
||||
print("Frame %d: %s" % (frame_index, breakpoint[0].to_string()))
|
||||
|
||||
frame_index += 1
|
||||
buffer_pos += 6
|
||||
|
||||
Reference in New Issue
Block a user