Support getting scope chain in the Debugger.

Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2020-03-24 02:21:45 -07:00 committed by Hyukwoo Park
commit a7a24cf22e
4 changed files with 132 additions and 11 deletions

View file

@ -22,6 +22,8 @@
#include "DebuggerTcp.h"
#include "interpreter/ByteCode.h"
#include "runtime/Context.h"
#include "runtime/Environment.h"
#include "runtime/EnvironmentRecord.h"
#include "runtime/GlobalObject.h"
#include "runtime/SandBox.h"
#include "parser/Script.h"
@ -254,6 +256,13 @@ bool Debugger::processIncomingMessages(ExecutionState* state, ByteCodeBlock* byt
getBacktrace(state, minDepth, maxDepth, buffer[1 + sizeof(uint32_t) + sizeof(uint32_t)] != 0);
return true;
}
case ESCARGOT_MESSAGE_GET_SCOPE_CHAIN: {
if (length != 1 || m_stopState != ESCARGOT_DEBUGGER_IN_WAIT_MODE) {
break;
}
getScopeChain(state);
return true;
}
}
ESCARGOT_LOG_ERROR("Invalid message received. Closing connection.\n");
@ -384,6 +393,50 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m
}
}
void Debugger::getScopeChain(ExecutionState* state)
{
const size_t maxMessageLength = ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH - 1;
uint8_t buffer[maxMessageLength];
size_t nextScope = 0;
LexicalEnvironment* lexEnv = state->lexicalEnvironment();
while (lexEnv) {
EnvironmentRecord* record = lexEnv->record();
uint8_t type;
if (nextScope >= maxMessageLength) {
if (!send(ESCARGOT_MESSAGE_SCOPE_CHAIN, buffer, maxMessageLength)) {
return;
}
nextScope = 0;
}
if (record->isGlobalEnvironmentRecord()) {
type = ESCARGOT_RECORD_GLOBAL_ENVIRONMENT;
} else if (record->isDeclarativeEnvironmentRecord()) {
DeclarativeEnvironmentRecord* declarativeRecord = record->asDeclarativeEnvironmentRecord();
if (declarativeRecord->isFunctionEnvironmentRecord()) {
type = ESCARGOT_RECORD_FUNCTION_ENVIRONMENT;
} else {
type = ESCARGOT_RECORD_DECLARATIVE_ENVIRONMENT;
}
} else if (record->isObjectEnvironmentRecord()) {
type = ESCARGOT_RECORD_OBJECT_ENVIRONMENT;
} else if (record->isModuleEnvironmentRecord()) {
type = ESCARGOT_RECORD_MODULE_ENVIRONMENT;
} else {
type = ESCARGOT_RECORD_UNKNOWN_ENVIRONMENT;
}
buffer[nextScope++] = type;
lexEnv = lexEnv->outerEnvironment();
}
send(ESCARGOT_MESSAGE_SCOPE_CHAIN_END, buffer, nextScope);
}
Debugger* createDebugger(const char* options, bool* debuggerEnabled)
{
Debugger* debugger = new DebuggerTcp();

View file

@ -85,6 +85,8 @@ public:
ESCARGOT_MESSAGE_BACKTRACE_8BIT_END = 32,
ESCARGOT_MESSAGE_BACKTRACE_16BIT = 33,
ESCARGOT_MESSAGE_BACKTRACE_16BIT_END = 34,
ESCARGOT_MESSAGE_SCOPE_CHAIN = 35,
ESCARGOT_MESSAGE_SCOPE_CHAIN_END = 36,
};
// Messages sent by the debugger client to Escargot
@ -100,6 +102,17 @@ public:
ESCARGOT_MESSAGE_EVAL_16BIT_START = 7,
ESCARGOT_MESSAGE_EVAL_16BIT = 8,
ESCARGOT_MESSAGE_GET_BACKTRACE = 9,
ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 10,
};
// Environment record types
enum {
ESCARGOT_RECORD_GLOBAL_ENVIRONMENT = 0,
ESCARGOT_RECORD_FUNCTION_ENVIRONMENT = 1,
ESCARGOT_RECORD_DECLARATIVE_ENVIRONMENT = 2,
ESCARGOT_RECORD_OBJECT_ENVIRONMENT = 3,
ESCARGOT_RECORD_MODULE_ENVIRONMENT = 4,
ESCARGOT_RECORD_UNKNOWN_ENVIRONMENT = 5,
};
struct BreakpointLocation {
@ -175,6 +188,7 @@ protected:
bool processIncomingMessages(ExecutionState* state, ByteCodeBlock* byteCodeBlock);
bool doEval(ExecutionState* state, ByteCodeBlock* byteCodeBlock, uint8_t* buffer, size_t length);
void getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t maxDepth, bool getTotal);
void getScopeChain(ExecutionState* state);
bool* m_debuggerEnabled;
bool m_enabled;

View file

@ -159,6 +159,11 @@ class DebuggerPrompt(Cmd):
self.stop = True
do_bt = do_backtrace
def do_scope(self, _):
""" Get lexical environment chain """
self.debugger.scope_chain()
self.stop = True
def do_dump(self, args):
""" Dump all of the debugger data """
if args:

View file

@ -61,6 +61,8 @@ ESCARGOT_MESSAGE_BACKTRACE_8BIT = 31
ESCARGOT_MESSAGE_BACKTRACE_8BIT_END = 32
ESCARGOT_MESSAGE_BACKTRACE_16BIT = 33
ESCARGOT_MESSAGE_BACKTRACE_16BIT_END = 34
ESCARGOT_MESSAGE_SCOPE_CHAIN = 35
ESCARGOT_MESSAGE_SCOPE_CHAIN_END = 36
# Messages sent by the debugger client to Escargot.
@ -74,6 +76,16 @@ ESCARGOT_MESSAGE_EVAL_8BIT = 6
ESCARGOT_MESSAGE_EVAL_16BIT_START = 7
ESCARGOT_MESSAGE_EVAL_16BIT = 8
ESCARGOT_MESSAGE_GET_BACKTRACE = 9
ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 10
# Environment record types
ESCARGOT_RECORD_GLOBAL_ENVIRONMENT = 0
ESCARGOT_RECORD_FUNCTION_ENVIRONMENT = 1
ESCARGOT_RECORD_DECLARATIVE_ENVIRONMENT = 2
ESCARGOT_RECORD_OBJECT_ENVIRONMENT = 3
ESCARGOT_RECORD_MODULE_ENVIRONMENT = 4
ESCARGOT_RECORD_UNKNOWN_ENVIRONMENT = 5
def arguments_parse():
@ -344,6 +356,20 @@ class Debugger(object):
result += "Total number of frames: %d\n" % (total)
return DebuggerAction(DebuggerAction.TEXT, result)
elif buffer_type in [ESCARGOT_MESSAGE_EVAL_RESULT_8BIT,
ESCARGOT_MESSAGE_EVAL_RESULT_8BIT_END,
ESCARGOT_MESSAGE_EVAL_RESULT_16BIT,
ESCARGOT_MESSAGE_EVAL_RESULT_16BIT_END]:
self.prompt = True
return self._receive_string(ESCARGOT_MESSAGE_EVAL_RESULT_8BIT, "", data);
elif buffer_type in [ESCARGOT_MESSAGE_EVAL_FAILED_8BIT,
ESCARGOT_MESSAGE_EVAL_FAILED_8BIT_END,
ESCARGOT_MESSAGE_EVAL_FAILED_16BIT,
ESCARGOT_MESSAGE_EVAL_FAILED_16BIT_END]:
self.prompt = True
return self._receive_string(ESCARGOT_MESSAGE_EVAL_FAILED_8BIT, self.red + "Exception: ", data);
elif buffer_type in [ESCARGOT_MESSAGE_BACKTRACE_8BIT,
ESCARGOT_MESSAGE_BACKTRACE_8BIT_END,
ESCARGOT_MESSAGE_BACKTRACE_16BIT,
@ -369,19 +395,38 @@ class Debugger(object):
self.prompt = True
return DebuggerAction(DebuggerAction.TEXT, backtrace.replace("\0", "\n"))
elif buffer_type in [ESCARGOT_MESSAGE_EVAL_RESULT_8BIT,
ESCARGOT_MESSAGE_EVAL_RESULT_8BIT_END,
ESCARGOT_MESSAGE_EVAL_RESULT_16BIT,
ESCARGOT_MESSAGE_EVAL_RESULT_16BIT_END]:
self.prompt = True
return self._receive_string(ESCARGOT_MESSAGE_EVAL_RESULT_8BIT, "", data);
elif buffer_type in [ESCARGOT_MESSAGE_SCOPE_CHAIN,
ESCARGOT_MESSAGE_SCOPE_CHAIN_END]:
scope_chain = ""
while buffer_type == ESCARGOT_MESSAGE_SCOPE_CHAIN:
scope_chain += data[1:]
data = self.channel.get_message(True)
buffer_type = ord(data[0])
if buffer_type != ESCARGOT_MESSAGE_SCOPE_CHAIN_END:
raise Exception("Unexpected message")
scope_chain += data[1:]
result = ""
for env_type in scope_chain:
env_type = ord(env_type)
if env_type == ESCARGOT_RECORD_GLOBAL_ENVIRONMENT:
result += "Global Environment\n"
elif env_type == ESCARGOT_RECORD_FUNCTION_ENVIRONMENT:
result += "Function Environment\n"
elif env_type == ESCARGOT_RECORD_DECLARATIVE_ENVIRONMENT:
result += "Declarative Environment\n"
elif env_type == ESCARGOT_RECORD_OBJECT_ENVIRONMENT:
result += "Object Environment\n"
elif env_type == ESCARGOT_RECORD_MODULE_ENVIRONMENT:
result += "Module Environment\n"
else:
result += "Unknown Environment\n"
elif buffer_type in [ESCARGOT_MESSAGE_EVAL_FAILED_8BIT,
ESCARGOT_MESSAGE_EVAL_FAILED_8BIT_END,
ESCARGOT_MESSAGE_EVAL_FAILED_16BIT,
ESCARGOT_MESSAGE_EVAL_FAILED_16BIT_END]:
self.prompt = True
return self._receive_string(ESCARGOT_MESSAGE_EVAL_FAILED_8BIT, self.red + "Exception: ", data);
return DebuggerAction(DebuggerAction.TEXT, result)
else:
raise Exception("Unknown message: %d" % (buffer_type))
@ -553,6 +598,10 @@ class Debugger(object):
self.prompt = False
return ""
def scope_chain(self):
self.prompt = False
self._exec_command(ESCARGOT_MESSAGE_GET_SCOPE_CHAIN)
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
def _parse_source(self, data):
source = ""