Move debug-related code into separate file.
The build was successful. Details

This commit is contained in:
Rafal Kupiec 2019-12-15 13:32:45 +01:00
parent 0b5e94bacc
commit 9d762a2350
Signed by: belliash
GPG Key ID: 4E829243E0CFE6B4
3 changed files with 374 additions and 365 deletions

373
engine/debug.c Normal file
View File

@ -0,0 +1,373 @@
/**
* @PROJECT PH7 Engine for the AerScript Interpreter
* @COPYRIGHT See COPYING in the top level directory
* @FILE engine/debug.c
* @DESCRIPTION AerScript Virtual Machine Debugger for the PH7 Engine
* @DEVELOPERS Symisc Systems <devel@symisc.net>
* Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include "ph7int.h"
/*
* This routine is used to dump the debug stacktrace based on all active frames.
*/
PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace) {
sxi32 iDepth = 0;
sxi32 rc = SXRET_OK;
/* Initialize the container */
SySetInit(pDebugTrace, &pVm->sAllocator, sizeof(VmDebugTrace));
/* Backup current frame */
VmFrame *oFrame = pVm->pFrame;
while(pVm->pFrame) {
if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) {
/* Iterate through all frames */
ph7_vm_func *pFunc;
pFunc = (ph7_vm_func *)pVm->pFrame->pUserData;
if(pFunc && (pVm->pFrame->iFlags & VM_FRAME_EXCEPTION) == 0) {
VmDebugTrace aTrace;
SySet *aByteCode = &pFunc->aByteCode;
/* Extract closure/method name and passed arguments */
aTrace.pFuncName = &pFunc->sName;
aTrace.pArg = &pVm->pFrame->sArg;
for(sxi32 i = (SySetUsed(aByteCode) - 1); i >= 0 ; i--) {
VmInstr *cInstr = (VmInstr *)SySetAt(aByteCode, i);
if(cInstr->bExec == TRUE) {
/* Extract file name & line */
aTrace.pFile = cInstr->pFile;
aTrace.nLine = cInstr->iLine;
break;
}
}
if(aTrace.pFile) {
aTrace.pClassName = NULL;
aTrace.bThis = FALSE;
if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) {
/* Extract class name */
ph7_class *pClass;
pClass = PH7_VmExtractActiveClass(pVm, iDepth++);
if(pClass) {
aTrace.pClassName = &pClass->sName;
if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) {
aTrace.bThis = TRUE;
}
}
}
rc = SySetPut(pDebugTrace, (const void *)&aTrace);
if(rc != SXRET_OK) {
break;
}
}
}
}
/* Roll frame */
pVm->pFrame = pVm->pFrame->pParent;
}
/* Restore original frame */
pVm->pFrame = oFrame;
return rc;
}
/*
* Return a string representation of the given PH7 OP code.
* This function never fail and always return a pointer
* to a null terminated string.
*/
static const char *VmInstrToString(sxi32 nOp) {
const char *zOp = "UNKNOWN";
switch(nOp) {
case PH7_OP_DONE:
zOp = "DONE";
break;
case PH7_OP_HALT:
zOp = "HALT";
break;
case PH7_OP_IMPORT:
zOp = "IMPORT";
break;
case PH7_OP_INCLUDE:
zOp = "INCLUDE";
break;
case PH7_OP_DECLARE:
zOp = "DECLARE";
break;
case PH7_OP_LOADV:
zOp = "LOADV";
break;
case PH7_OP_LOADC:
zOp = "LOADC";
break;
case PH7_OP_LOAD_MAP:
zOp = "LOAD_MAP";
break;
case PH7_OP_LOAD_IDX:
zOp = "LOAD_IDX";
break;
case PH7_OP_LOAD_CLOSURE:
zOp = "LOAD_CLOSR";
break;
case PH7_OP_NOOP:
zOp = "NOOP";
break;
case PH7_OP_JMP:
zOp = "JMP";
break;
case PH7_OP_JMPZ:
zOp = "JMPZ";
break;
case PH7_OP_JMPNZ:
zOp = "JMPNZ";
break;
case PH7_OP_LF_START:
zOp = "LF_START";
break;
case PH7_OP_LF_STOP:
zOp = "LF_STOP";
break;
case PH7_OP_POP:
zOp = "POP";
break;
case PH7_OP_CVT_INT:
zOp = "CVT_INT";
break;
case PH7_OP_CVT_STR:
zOp = "CVT_STR";
break;
case PH7_OP_CVT_REAL:
zOp = "CVT_FLOAT";
break;
case PH7_OP_CALL:
zOp = "CALL";
break;
case PH7_OP_UMINUS:
zOp = "UMINUS";
break;
case PH7_OP_UPLUS:
zOp = "UPLUS";
break;
case PH7_OP_BITNOT:
zOp = "BITNOT";
break;
case PH7_OP_LNOT:
zOp = "LOGNOT";
break;
case PH7_OP_MUL:
zOp = "MUL";
break;
case PH7_OP_DIV:
zOp = "DIV";
break;
case PH7_OP_MOD:
zOp = "MOD";
break;
case PH7_OP_ADD:
zOp = "ADD";
break;
case PH7_OP_SUB:
zOp = "SUB";
break;
case PH7_OP_SHL:
zOp = "SHL";
break;
case PH7_OP_SHR:
zOp = "SHR";
break;
case PH7_OP_LT:
zOp = "LT";
break;
case PH7_OP_LE:
zOp = "LE";
break;
case PH7_OP_GT:
zOp = "GT";
break;
case PH7_OP_GE:
zOp = "GE";
break;
case PH7_OP_EQ:
zOp = "EQ";
break;
case PH7_OP_NEQ:
zOp = "NEQ";
break;
case PH7_OP_NULLC:
zOp = "NULLC";
break;
case PH7_OP_BAND:
zOp = "BITAND";
break;
case PH7_OP_BXOR:
zOp = "BITXOR";
break;
case PH7_OP_BOR:
zOp = "BITOR";
break;
case PH7_OP_LAND:
zOp = "LOGAND";
break;
case PH7_OP_LOR:
zOp = "LOGOR";
break;
case PH7_OP_LXOR:
zOp = "LOGXOR";
break;
case PH7_OP_STORE:
zOp = "STORE";
break;
case PH7_OP_STORE_IDX:
zOp = "STORE_IDX";
break;
case PH7_OP_PULL:
zOp = "PULL";
break;
case PH7_OP_SWAP:
zOp = "SWAP";
break;
case PH7_OP_YIELD:
zOp = "YIELD";
break;
case PH7_OP_CVT_BOOL:
zOp = "CVT_BOOL";
break;
case PH7_OP_CVT_OBJ:
zOp = "CVT_OBJ";
break;
case PH7_OP_INCR:
zOp = "INCR";
break;
case PH7_OP_DECR:
zOp = "DECR";
break;
case PH7_OP_NEW:
zOp = "NEW";
break;
case PH7_OP_CLONE:
zOp = "CLONE";
break;
case PH7_OP_ADD_STORE:
zOp = "ADD_STORE";
break;
case PH7_OP_SUB_STORE:
zOp = "SUB_STORE";
break;
case PH7_OP_MUL_STORE:
zOp = "MUL_STORE";
break;
case PH7_OP_DIV_STORE:
zOp = "DIV_STORE";
break;
case PH7_OP_MOD_STORE:
zOp = "MOD_STORE";
break;
case PH7_OP_SHL_STORE:
zOp = "SHL_STORE";
break;
case PH7_OP_SHR_STORE:
zOp = "SHR_STORE";
break;
case PH7_OP_BAND_STORE:
zOp = "BAND_STORE";
break;
case PH7_OP_BOR_STORE:
zOp = "BOR_STORE";
break;
case PH7_OP_BXOR_STORE:
zOp = "BXOR_STORE";
break;
case PH7_OP_CONSUME:
zOp = "CONSUME";
break;
case PH7_OP_MEMBER:
zOp = "MEMBER";
break;
case PH7_OP_IS:
zOp = "IS";
break;
case PH7_OP_SWITCH:
zOp = "SWITCH";
break;
case PH7_OP_LOAD_EXCEPTION:
zOp = "LOAD_EXCEP";
break;
case PH7_OP_POP_EXCEPTION:
zOp = "POP_EXCEP";
break;
case PH7_OP_THROW:
zOp = "THROW";
break;
case PH7_OP_CLASS_INIT:
zOp = "CLASS_INIT";
break;
case PH7_OP_INTERFACE_INIT:
zOp = "INTER_INIT";
break;
case PH7_OP_FOREACH_INIT:
zOp = "4EACH_INIT";
break;
case PH7_OP_FOREACH_STEP:
zOp = "4EACH_STEP";
break;
default:
break;
}
return zOp;
}
/*
* This routine is used to dump PH7 byte-code instructions to a human readable
* format.
* The dump is redirected to the given consumer callback which is responsible
* of consuming the generated dump perhaps redirecting it to its standard output
* (STDOUT).
*/
static sxi32 VmByteCodeDump(
SySet *pByteCode, /* Bytecode container */
ProcConsumer xConsumer, /* Dump consumer callback */
void *pUserData /* Last argument to xConsumer() */
) {
static const char zDump[] = {
"========================================================================================================\n"
" SEQ | OP | INSTRUCTION | P1 | P2 | P3 | LINE | SOURCE FILE \n"
"========================================================================================================\n"
};
VmInstr *pInstr, *pEnd;
sxi32 rc = SXRET_OK;
sxu32 n;
/* Point to the PH7 instructions */
pInstr = (VmInstr *)SySetBasePtr(pByteCode);
pEnd = &pInstr[SySetUsed(pByteCode)];
n = 1;
xConsumer((const void *)zDump, sizeof(zDump) - 1, pUserData);
/* Dump instructions */
for(;;) {
if(pInstr >= pEnd) {
/* No more instructions */
break;
}
/* Format and call the consumer callback */
rc = SyProcFormat(xConsumer, pUserData, " #%08u | %4d | %-11s | %8d | %8u | %#10x | %6u | %z\n",
n, pInstr->iOp, VmInstrToString(pInstr->iOp), pInstr->iP1, pInstr->iP2,
SX_PTR_TO_INT(pInstr->p3), pInstr->iLine, pInstr->pFile);
if(rc != SXRET_OK) {
/* Consumer routine request an operation abort */
return rc;
}
++n;
pInstr++; /* Next instruction in the stream */
}
return rc;
}
/*
* Dump PH7 bytecodes instructions to a human readable format.
* The xConsumer() callback which is an used defined function
* is responsible of consuming the generated dump.
*/
PH7_PRIVATE sxi32 PH7_VmDump(
ph7_vm *pVm, /* Target VM */
ProcConsumer xConsumer, /* Output [i.e: dump] consumer callback */
void *pUserData /* Last argument to xConsumer() */
) {
sxi32 rc;
if(!pVm->bDebug) {
return SXRET_OK;
}
rc = VmByteCodeDump(&pVm->aInstrSet, xConsumer, pUserData);
return rc;
}

View File

@ -1704,110 +1704,6 @@ PH7_PRIVATE sxi32 PH7_VmConfigure(
return rc;
}
/* Forward declaration */
static const char *VmInstrToString(sxi32 nOp);
/*
* This routine is used to dump the debug stacktrace based on all active frames.
*/
PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace) {
sxi32 iDepth = 0;
sxi32 rc = SXRET_OK;
/* Initialize the container */
SySetInit(pDebugTrace, &pVm->sAllocator, sizeof(VmDebugTrace));
/* Backup current frame */
VmFrame *oFrame = pVm->pFrame;
while(pVm->pFrame) {
if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) {
/* Iterate through all frames */
ph7_vm_func *pFunc;
pFunc = (ph7_vm_func *)pVm->pFrame->pUserData;
if(pFunc && (pVm->pFrame->iFlags & VM_FRAME_EXCEPTION) == 0) {
VmDebugTrace aTrace;
SySet *aByteCode = &pFunc->aByteCode;
/* Extract closure/method name and passed arguments */
aTrace.pFuncName = &pFunc->sName;
aTrace.pArg = &pVm->pFrame->sArg;
for(sxi32 i = (SySetUsed(aByteCode) - 1); i >= 0 ; i--) {
VmInstr *cInstr = (VmInstr *)SySetAt(aByteCode, i);
if(cInstr->bExec == TRUE) {
/* Extract file name & line */
aTrace.pFile = cInstr->pFile;
aTrace.nLine = cInstr->iLine;
break;
}
}
if(aTrace.pFile) {
aTrace.pClassName = NULL;
aTrace.bThis = FALSE;
if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) {
/* Extract class name */
ph7_class *pClass;
pClass = PH7_VmExtractActiveClass(pVm, iDepth++);
if(pClass) {
aTrace.pClassName = &pClass->sName;
if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) {
aTrace.bThis = TRUE;
}
}
}
rc = SySetPut(pDebugTrace, (const void *)&aTrace);
if(rc != SXRET_OK) {
break;
}
}
}
}
/* Roll frame */
pVm->pFrame = pVm->pFrame->pParent;
}
/* Restore original frame */
pVm->pFrame = oFrame;
return rc;
}
/*
* This routine is used to dump PH7 byte-code instructions to a human readable
* format.
* The dump is redirected to the given consumer callback which is responsible
* of consuming the generated dump perhaps redirecting it to its standard output
* (STDOUT).
*/
static sxi32 VmByteCodeDump(
SySet *pByteCode, /* Bytecode container */
ProcConsumer xConsumer, /* Dump consumer callback */
void *pUserData /* Last argument to xConsumer() */
) {
static const char zDump[] = {
"========================================================================================================\n"
" SEQ | OP | INSTRUCTION | P1 | P2 | P3 | LINE | SOURCE FILE \n"
"========================================================================================================\n"
};
VmInstr *pInstr, *pEnd;
sxi32 rc = SXRET_OK;
sxu32 n;
/* Point to the PH7 instructions */
pInstr = (VmInstr *)SySetBasePtr(pByteCode);
pEnd = &pInstr[SySetUsed(pByteCode)];
n = 1;
xConsumer((const void *)zDump, sizeof(zDump) - 1, pUserData);
/* Dump instructions */
for(;;) {
if(pInstr >= pEnd) {
/* No more instructions */
break;
}
/* Format and call the consumer callback */
rc = SyProcFormat(xConsumer, pUserData, " #%08u | %4d | %-11s | %8d | %8u | %#10x | %6u | %z\n",
n, pInstr->iOp, VmInstrToString(pInstr->iOp), pInstr->iP1, pInstr->iP2,
SX_PTR_TO_INT(pInstr->p3), pInstr->iLine, pInstr->pFile);
if(rc != SXRET_OK) {
/* Consumer routine request an operation abort */
return rc;
}
++n;
pInstr++; /* Next instruction in the stream */
}
return rc;
}
/* Forward declaration */
static int VmObConsumer(const void *pData, unsigned int nDataLen, void *pUserData);
static sxi32 VmExecFinallyBlock(ph7_vm *pVm, ph7_exception *pException);
static sxi32 VmUncaughtException(ph7_vm *pVm, ph7_class_instance *pThis);
@ -5247,267 +5143,6 @@ PH7_PRIVATE sxi32 PH7_VmOutputConsumeAp(
SyBlobRelease(&sWorker);
return rc;
}
/*
* Return a string representation of the given PH7 OP code.
* This function never fail and always return a pointer
* to a null terminated string.
*/
static const char *VmInstrToString(sxi32 nOp) {
const char *zOp = "UNKNOWN";
switch(nOp) {
case PH7_OP_DONE:
zOp = "DONE";
break;
case PH7_OP_HALT:
zOp = "HALT";
break;
case PH7_OP_IMPORT:
zOp = "IMPORT";
break;
case PH7_OP_INCLUDE:
zOp = "INCLUDE";
break;
case PH7_OP_DECLARE:
zOp = "DECLARE";
break;
case PH7_OP_LOADV:
zOp = "LOADV";
break;
case PH7_OP_LOADC:
zOp = "LOADC";
break;
case PH7_OP_LOAD_MAP:
zOp = "LOAD_MAP";
break;
case PH7_OP_LOAD_IDX:
zOp = "LOAD_IDX";
break;
case PH7_OP_LOAD_CLOSURE:
zOp = "LOAD_CLOSR";
break;
case PH7_OP_NOOP:
zOp = "NOOP";
break;
case PH7_OP_JMP:
zOp = "JMP";
break;
case PH7_OP_JMPZ:
zOp = "JMPZ";
break;
case PH7_OP_JMPNZ:
zOp = "JMPNZ";
break;
case PH7_OP_LF_START:
zOp = "LF_START";
break;
case PH7_OP_LF_STOP:
zOp = "LF_STOP";
break;
case PH7_OP_POP:
zOp = "POP";
break;
case PH7_OP_CVT_INT:
zOp = "CVT_INT";
break;
case PH7_OP_CVT_STR:
zOp = "CVT_STR";
break;
case PH7_OP_CVT_REAL:
zOp = "CVT_FLOAT";
break;
case PH7_OP_CALL:
zOp = "CALL";
break;
case PH7_OP_UMINUS:
zOp = "UMINUS";
break;
case PH7_OP_UPLUS:
zOp = "UPLUS";
break;
case PH7_OP_BITNOT:
zOp = "BITNOT";
break;
case PH7_OP_LNOT:
zOp = "LOGNOT";
break;
case PH7_OP_MUL:
zOp = "MUL";
break;
case PH7_OP_DIV:
zOp = "DIV";
break;
case PH7_OP_MOD:
zOp = "MOD";
break;
case PH7_OP_ADD:
zOp = "ADD";
break;
case PH7_OP_SUB:
zOp = "SUB";
break;
case PH7_OP_SHL:
zOp = "SHL";
break;
case PH7_OP_SHR:
zOp = "SHR";
break;
case PH7_OP_LT:
zOp = "LT";
break;
case PH7_OP_LE:
zOp = "LE";
break;
case PH7_OP_GT:
zOp = "GT";
break;
case PH7_OP_GE:
zOp = "GE";
break;
case PH7_OP_EQ:
zOp = "EQ";
break;
case PH7_OP_NEQ:
zOp = "NEQ";
break;
case PH7_OP_NULLC:
zOp = "NULLC";
break;
case PH7_OP_BAND:
zOp = "BITAND";
break;
case PH7_OP_BXOR:
zOp = "BITXOR";
break;
case PH7_OP_BOR:
zOp = "BITOR";
break;
case PH7_OP_LAND:
zOp = "LOGAND";
break;
case PH7_OP_LOR:
zOp = "LOGOR";
break;
case PH7_OP_LXOR:
zOp = "LOGXOR";
break;
case PH7_OP_STORE:
zOp = "STORE";
break;
case PH7_OP_STORE_IDX:
zOp = "STORE_IDX";
break;
case PH7_OP_PULL:
zOp = "PULL";
break;
case PH7_OP_SWAP:
zOp = "SWAP";
break;
case PH7_OP_YIELD:
zOp = "YIELD";
break;
case PH7_OP_CVT_BOOL:
zOp = "CVT_BOOL";
break;
case PH7_OP_CVT_OBJ:
zOp = "CVT_OBJ";
break;
case PH7_OP_INCR:
zOp = "INCR";
break;
case PH7_OP_DECR:
zOp = "DECR";
break;
case PH7_OP_NEW:
zOp = "NEW";
break;
case PH7_OP_CLONE:
zOp = "CLONE";
break;
case PH7_OP_ADD_STORE:
zOp = "ADD_STORE";
break;
case PH7_OP_SUB_STORE:
zOp = "SUB_STORE";
break;
case PH7_OP_MUL_STORE:
zOp = "MUL_STORE";
break;
case PH7_OP_DIV_STORE:
zOp = "DIV_STORE";
break;
case PH7_OP_MOD_STORE:
zOp = "MOD_STORE";
break;
case PH7_OP_SHL_STORE:
zOp = "SHL_STORE";
break;
case PH7_OP_SHR_STORE:
zOp = "SHR_STORE";
break;
case PH7_OP_BAND_STORE:
zOp = "BAND_STORE";
break;
case PH7_OP_BOR_STORE:
zOp = "BOR_STORE";
break;
case PH7_OP_BXOR_STORE:
zOp = "BXOR_STORE";
break;
case PH7_OP_CONSUME:
zOp = "CONSUME";
break;
case PH7_OP_MEMBER:
zOp = "MEMBER";
break;
case PH7_OP_IS:
zOp = "IS";
break;
case PH7_OP_SWITCH:
zOp = "SWITCH";
break;
case PH7_OP_LOAD_EXCEPTION:
zOp = "LOAD_EXCEP";
break;
case PH7_OP_POP_EXCEPTION:
zOp = "POP_EXCEP";
break;
case PH7_OP_THROW:
zOp = "THROW";
break;
case PH7_OP_CLASS_INIT:
zOp = "CLASS_INIT";
break;
case PH7_OP_INTERFACE_INIT:
zOp = "INTER_INIT";
break;
case PH7_OP_FOREACH_INIT:
zOp = "4EACH_INIT";
break;
case PH7_OP_FOREACH_STEP:
zOp = "4EACH_STEP";
break;
default:
break;
}
return zOp;
}
/*
* Dump PH7 bytecodes instructions to a human readable format.
* The xConsumer() callback which is an used defined function
* is responsible of consuming the generated dump.
*/
PH7_PRIVATE sxi32 PH7_VmDump(
ph7_vm *pVm, /* Target VM */
ProcConsumer xConsumer, /* Output [i.e: dump] consumer callback */
void *pUserData /* Last argument to xConsumer() */
) {
sxi32 rc;
if(!pVm->bDebug) {
return SXRET_OK;
}
rc = VmByteCodeDump(&pVm->aInstrSet, xConsumer, pUserData);
return rc;
}
/*
* Default constant expansion callback used by the 'const' statement if used
* outside a class body [i.e: global or function scope].

View File

@ -1669,6 +1669,7 @@ PH7_PRIVATE sxi32 PH7_VmOutputConsumeAp(ph7_vm *pVm, const char *zFormat, va_lis
PH7_PRIVATE sxi32 PH7_VmMemoryError(ph7_vm *pVm);
PH7_PRIVATE sxi32 PH7_VmThrowError(ph7_vm *pVm, sxi32 iErr, const char *zMessage, ...);
PH7_PRIVATE void PH7_VmExpandConstantValue(ph7_value *pVal, void *pUserData);
PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace);
PH7_PRIVATE sxi32 PH7_VmDump(ph7_vm *pVm, ProcConsumer xConsumer, void *pUserData);
PH7_PRIVATE sxi32 PH7_VmInit(ph7_vm *pVm, ph7 *pEngine, sxbool bDebug);
PH7_PRIVATE sxi32 PH7_VmConfigure(ph7_vm *pVm, sxi32 nOp, va_list ap);