diff --git a/src/debugger/Debugger.cpp b/src/debugger/Debugger.cpp index b3ac7fcf1..b79a0fcc3 100644 --- a/src/debugger/Debugger.cpp +++ b/src/debugger/Debugger.cpp @@ -112,6 +112,18 @@ void Debugger::sendBreakpointLocations(std::vector send(ESCARGOT_MESSAGE_BREAKPOINT_LOCATION, ptr, length * sizeof(BreakpointLocation)); } +void Debugger::sendBacktraceInfo(uint8_t type, ByteCodeBlock* byteCodeBlock, uint32_t line, uint32_t column) +{ + BacktraceInfo backtraceInfo; + + char* byteCode = byteCodeBlock->m_code.data(); + memcpy(&backtraceInfo.byteCode, &byteCode, sizeof(void*)); + memcpy(&backtraceInfo.line, &line, sizeof(uint32_t)); + memcpy(&backtraceInfo.column, &column, sizeof(uint32_t)); + + send(type, &backtraceInfo, sizeof(BacktraceInfo)); +} + void Debugger::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) { if (m_stopState == ESCARGOT_DEBUGGER_IN_EVAL_MODE) { @@ -227,7 +239,6 @@ bool Debugger::doEval(ExecutionState* state, ByteCodeBlock* byteCodeBlock, uint8 void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t maxDepth, bool getTotal) { - BacktraceInfo backtraceInfo; SandBox::StackTraceDataVector stackTraceData; SandBox::createStackTraceData(stackTraceData, *state); @@ -251,16 +262,11 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m ByteCodeBlock* byteCodeBlock = stackTraceData[i].second.loc.actualCodeBlock; size_t byteCodePosition = stackTraceData[i].second.loc.byteCodePosition; - char* byteCode = byteCodeBlock->m_code.data(); - memcpy(&backtraceInfo.byteCode, &byteCode, sizeof(void*)); - ExtendedNodeLOC loc = byteCodeBlock->computeNodeLOCFromByteCode(state->context(), byteCodePosition, byteCodeBlock->m_codeBlock); - uint32_t data = (uint32_t)loc.line; - memcpy(&backtraceInfo.line, &data, sizeof(uint32_t)); - data = (uint32_t)loc.column; - memcpy(&backtraceInfo.column, &data, sizeof(uint32_t)); - if (!send(ESCARGOT_MESSAGE_BACKTRACE, &backtraceInfo, sizeof(BacktraceInfo))) { + sendBacktraceInfo(ESCARGOT_MESSAGE_BACKTRACE, byteCodeBlock, (uint32_t)loc.line, (uint32_t)loc.column); + + if (!enabled()) { return; } } @@ -373,11 +379,11 @@ static void sendProperty(Debugger* debugger, ExecutionState* state, AtomicString if (debugger->enabled()) { StringView* nameView = new StringView(name.string(), 0, nameLength); - debugger->sendString(Debugger::ESCARGOT_MESSAGE_VARIABLE_8BIT, nameView); + debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, nameView); } if (valueView && debugger->enabled()) { - debugger->sendString(Debugger::ESCARGOT_MESSAGE_VARIABLE_8BIT, valueView); + debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, valueView); } } @@ -395,7 +401,7 @@ static void sendUnaccessibleProperty(Debugger* debugger, AtomicString name) if (debugger->enabled()) { StringView* nameView = new StringView(name.string(), 0, nameLength); - debugger->sendString(Debugger::ESCARGOT_MESSAGE_VARIABLE_8BIT, nameView); + debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, nameView); } } diff --git a/src/debugger/Debugger.h b/src/debugger/Debugger.h index 41ae623b3..793307775 100644 --- a/src/debugger/Debugger.h +++ b/src/debugger/Debugger.h @@ -85,18 +85,15 @@ class Debugger : public gc { ESCARGOT_MESSAGE_BACKTRACE_END = 32, ESCARGOT_MESSAGE_SCOPE_CHAIN = 33, ESCARGOT_MESSAGE_SCOPE_CHAIN_END = 34, - ESCARGOT_MESSAGE_VARIABLE = 35, // These four must be in the same order. - ESCARGOT_MESSAGE_VARIABLE_8BIT = 36, - ESCARGOT_MESSAGE_VARIABLE_8BIT_END = 37, - ESCARGOT_MESSAGE_VARIABLE_16BIT = 38, - ESCARGOT_MESSAGE_VARIABLE_16BIT_END = 39, - // These four must be in the same order. - // These four must be in the same order. - ESCARGOT_MESSAGE_PRINT_8BIT = 40, - ESCARGOT_MESSAGE_PRINT_8BIT_END = 41, - ESCARGOT_MESSAGE_PRINT_16BIT = 42, - ESCARGOT_MESSAGE_PRINT_16BIT_END = 43, + ESCARGOT_MESSAGE_STRING_8BIT = 35, + ESCARGOT_MESSAGE_STRING_8BIT_END = 36, + ESCARGOT_MESSAGE_STRING_16BIT = 37, + ESCARGOT_MESSAGE_STRING_16BIT_END = 38, + ESCARGOT_MESSAGE_VARIABLE = 39, + ESCARGOT_MESSAGE_PRINT = 40, + ESCARGOT_MESSAGE_EXCEPTION = 41, + ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE = 42, }; // Messages sent by the debugger client to Escargot @@ -199,6 +196,7 @@ class Debugger : public gc { void sendPointer(uint8_t type, const void* ptr); void sendFunctionInfo(InterpretedCodeBlock* codeBlock); void sendBreakpointLocations(std::vector& locations); + void sendBacktraceInfo(uint8_t type, ByteCodeBlock* byteCodeBlock, uint32_t line, uint32_t column); void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state); void releaseFunction(const void* ptr); diff --git a/src/runtime/Context.cpp b/src/runtime/Context.cpp index f5cba29d3..12f1853b8 100644 --- a/src/runtime/Context.cpp +++ b/src/runtime/Context.cpp @@ -119,7 +119,10 @@ void Context::printDebugger(StringView* output) if (!m_debugger || !m_debugger->enabled()) { return; } - m_debugger->sendString(Debugger::ESCARGOT_MESSAGE_PRINT_8BIT, output); + m_debugger->sendType(Debugger::ESCARGOT_MESSAGE_PRINT); + if (m_debugger->enabled()) { + m_debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, output); + } } #endif /* ESCARGOT_DEBUGGER */ diff --git a/src/runtime/SandBox.cpp b/src/runtime/SandBox.cpp index 7a3895797..14df031bc 100644 --- a/src/runtime/SandBox.cpp +++ b/src/runtime/SandBox.cpp @@ -52,6 +52,20 @@ void SandBox::processCatch(const Value& error, SandBoxResult& result) fillStackDataIntoErrorObject(error); +#ifdef ESCARGOT_DEBUGGER + Debugger* debugger = m_context->debugger(); + if (debugger && debugger->enabled()) { + ExecutionState state(m_context); + String* message = error.toStringWithoutException(state); + + debugger->sendType(Debugger::ESCARGOT_MESSAGE_EXCEPTION); + if (debugger->enabled()) { + StringView* messageView = new StringView(message); + debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, messageView); + } + } +#endif /* ESCARGOT_DEBUGGER */ + for (size_t i = 0; i < m_stackTraceData.size(); i++) { if ((size_t)m_stackTraceData[i].second.loc.index == SIZE_MAX && (size_t)m_stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) { // this means loc not computed yet. @@ -69,6 +83,13 @@ void SandBox::processCatch(const Value& error, SandBoxResult& result) traceData.isEval = m_stackTraceData[i].second.isEval; result.stackTraceData.pushBack(traceData); + +#ifdef ESCARGOT_DEBUGGER + if (i < 8 && debugger && debugger->enabled()) { + debugger->sendBacktraceInfo(Debugger::ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE, + m_stackTraceData[i].second.loc.actualCodeBlock, (uint32_t)loc.line, (uint32_t)loc.column); + } +#endif /* ESCARGOT_DEBUGGER */ } else { result.stackTraceData.pushBack(m_stackTraceData[i].second); } diff --git a/tools/debugger/debugger_core.py b/tools/debugger/debugger_core.py index 6092099b4..560ee8eb0 100644 --- a/tools/debugger/debugger_core.py +++ b/tools/debugger/debugger_core.py @@ -61,15 +61,14 @@ ESCARGOT_MESSAGE_BACKTRACE_END = 32 ESCARGOT_MESSAGE_SCOPE_CHAIN = 33 ESCARGOT_MESSAGE_SCOPE_CHAIN_END = 34 -ESCARGOT_MESSAGE_VARIABLE = 35 -ESCARGOT_MESSAGE_VARIABLE_8BIT = 36 -ESCARGOT_MESSAGE_VARIABLE_8BIT_END = 37 -ESCARGOT_MESSAGE_VARIABLE_16BIT = 38 -ESCARGOT_MESSAGE_VARIABLE_16BIT_END = 39 -ESCARGOT_MESSAGE_PRINT_8BIT = 40 -ESCARGOT_MESSAGE_PRINT_8BIT_END = 41 -ESCARGOT_MESSAGE_PRINT_16BIT = 42 -ESCARGOT_MESSAGE_PRINT_16BIT_END = 43 +ESCARGOT_MESSAGE_STRING_8BIT = 35 +ESCARGOT_MESSAGE_STRING_8BIT_END = 36 +ESCARGOT_MESSAGE_STRING_16BIT = 37 +ESCARGOT_MESSAGE_STRING_16BIT_END = 38 +ESCARGOT_MESSAGE_VARIABLE = 39 +ESCARGOT_MESSAGE_PRINT = 40 +ESCARGOT_MESSAGE_EXCEPTION = 41 +ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE = 42 # Messages sent by the debugger client to Escargot. @@ -397,7 +396,8 @@ def process_messages(self): result = self._receive_string(ESCARGOT_MESSAGE_EVAL_RESULT_8BIT, data); return DebuggerAction(DebuggerAction.TEXT, "%sException: %s%s" % (self.red, result, self.no_color)); - elif buffer_type == ESCARGOT_MESSAGE_BACKTRACE: + elif buffer_type in [ESCARGOT_MESSAGE_BACKTRACE, + ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE]: backtrace_info = struct.unpack(self.byte_order + self.pointer_format + self.idx_format + self.idx_format, data[1:]) function = self.function_list[backtrace_info[0]] @@ -405,7 +405,9 @@ def process_messages(self): if function.name != "": result += " (in %s)" % (function.name) - return DebuggerAction(DebuggerAction.TEXT, result + "\n") + if buffer_type == ESCARGOT_MESSAGE_BACKTRACE: + return DebuggerAction(DebuggerAction.TEXT, result + "\n") + return DebuggerAction(DebuggerAction.TEXT, "%s%s%s\n" % (self.red, result, self.nocolor)) elif buffer_type == ESCARGOT_MESSAGE_BACKTRACE_END: self.prompt = True @@ -478,25 +480,25 @@ def process_messages(self): elif variable_type == ESCARGOT_VARIABLE_FUNCTION: value_str = "function" - name = self._receive_string(ESCARGOT_MESSAGE_VARIABLE_8BIT, self.channel.get_message(True)); + name = self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True)); if variable_full_type & ESCARGOT_VARIABLE_LONG_NAME != 0: name += "..." if variable_has_value: - value_str += self._receive_string(ESCARGOT_MESSAGE_VARIABLE_8BIT, self.channel.get_message(True)); + value_str += self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True)); if variable_full_type & ESCARGOT_VARIABLE_LONG_VALUE: value_str += "..." return DebuggerAction(DebuggerAction.TEXT, "%s: %s\n" % (name, value_str)) - elif buffer_type in [ESCARGOT_MESSAGE_PRINT_8BIT, - ESCARGOT_MESSAGE_PRINT_8BIT_END, - ESCARGOT_MESSAGE_PRINT_16BIT, - ESCARGOT_MESSAGE_PRINT_16BIT_END]: - - printMessage ="Print: %s\n" % (self._receive_string(ESCARGOT_MESSAGE_PRINT_8BIT, data)) + elif buffer_type == ESCARGOT_MESSAGE_PRINT: + printMessage ="Print: %s\n" % (self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True))) return DebuggerAction(DebuggerAction.TEXT, printMessage); + elif buffer_type == ESCARGOT_MESSAGE_EXCEPTION: + exceptionMessage ="%sException: %s%s\n" % (self.red, self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True)), self.nocolor) + return DebuggerAction(DebuggerAction.TEXT, exceptionMessage); + else: raise Exception("Unknown message: %d" % (buffer_type)) diff --git a/tools/debugger/tests/do_exception.cmd b/tools/debugger/tests/do_exception.cmd new file mode 100644 index 000000000..f2ad6c76f --- /dev/null +++ b/tools/debugger/tests/do_exception.cmd @@ -0,0 +1 @@ +c diff --git a/tools/debugger/tests/do_exception.expected b/tools/debugger/tests/do_exception.expected new file mode 100644 index 000000000..a980dd9fc --- /dev/null +++ b/tools/debugger/tests/do_exception.expected @@ -0,0 +1,9 @@ +Connecting to: localhost:6501 +Connection created!!! +Stopped at tools/debugger/tests/do_exception.js:28 +(escargot-debugger) c +Exception: RangeError: Test exception +tools/debugger/tests/do_exception.js:22:2 (in g) +tools/debugger/tests/do_exception.js:25:4 (in f) +tools/debugger/tests/do_exception.js:28:1 +Connection closed. diff --git a/tools/debugger/tests/do_exception.js b/tools/debugger/tests/do_exception.js new file mode 100644 index 000000000..94f13f0e8 --- /dev/null +++ b/tools/debugger/tests/do_exception.js @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020-present Samsung Electronics Co., Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +function g() { + throw RangeError("Test exception"); +} + +function f() { + g(); +} + +f();