From 9d762a23506a9ebc1b632b896b70f9fc8ddbc188 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 15 Dec 2019 13:32:45 +0100 Subject: [PATCH] Move debug-related code into separate file. --- engine/debug.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++ engine/vm.c | 365 ---------------------------------------------- include/ph7int.h | 1 + 3 files changed, 374 insertions(+), 365 deletions(-) create mode 100644 engine/debug.c diff --git a/engine/debug.c b/engine/debug.c new file mode 100644 index 0000000..f4ba43f --- /dev/null +++ b/engine/debug.c @@ -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 + * Rafal Kupiec + */ +#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; +} diff --git a/engine/vm.c b/engine/vm.c index 0b62c6f..eda4d97 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -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]. diff --git a/include/ph7int.h b/include/ph7int.h index 9571052..becbb94 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -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);