From 1d5d8b7d199b90a36747a5cdd60cb7f9065abf3f Mon Sep 17 00:00:00 2001 From: Peter Wortmann Date: Tue, 21 Apr 2009 23:44:56 +0200 Subject: [PATCH 01/15] + Initial C4Aul debugging support --- engine/inc/C4Aul.h | 16 +- engine/inc/C4AulDebug.h | 68 ++++++ engine/inc/C4AulExec.h | 152 ++++++++++++ engine/inc/C4Game.h | 6 +- engine/src/C4Aul.cpp | 35 +++ engine/src/C4AulDebug.cpp | 329 ++++++++++++++++++++++++++ engine/src/C4AulExec.cpp | 324 ++++++++++--------------- engine/src/C4AulParse.cpp | 3 + engine/src/C4Config.cpp | 1 - engine/src/C4Game.cpp | 18 ++ engine/src/C4Log.cpp | 5 + engine/src/C4Script.cpp | 6 +- xcode/Clonk.xcodeproj/project.pbxproj | 8 + 13 files changed, 758 insertions(+), 213 deletions(-) create mode 100644 engine/inc/C4AulDebug.h create mode 100644 engine/inc/C4AulExec.h create mode 100644 engine/src/C4AulDebug.cpp diff --git a/engine/inc/C4Aul.h b/engine/inc/C4Aul.h index 4a494ffb1..3ff8ecaf5 100644 --- a/engine/inc/C4Aul.h +++ b/engine/inc/C4Aul.h @@ -42,6 +42,7 @@ class C4AulScriptFunc; class C4AulDefFunc; class C4AulScript; class C4AulScriptEngine; +class C4AulDebug; struct C4AulContext; struct C4AulBCC; @@ -198,6 +199,7 @@ enum C4AulBCCType AB_FOREACH_NEXT, // foreach: next element AB_RETURN, // return statement AB_ERR, // parse error at this position + AB_DEBUG, // debug break AB_EOFN, // end of function AB_EOF, // end of file }; @@ -248,13 +250,16 @@ struct C4AulScriptContext : public C4AulContext C4Value *Return; C4Value *Pars; C4Value *Vars; - C4AulScriptFunc *Func; + C4AulFunc *Func; bool TemporaryScript; C4ValueList NumVars; C4AulBCC *CPos; time_t tTime; // initialized only by profiler if active + C4AulScriptFunc *SFunc(); int ParCnt() const { return Vars - Pars; } + StdStrBuf Dump(StdStrBuf Dump = StdStrBuf("")); + StdStrBuf DumpVerbose(StdStrBuf Dump = StdStrBuf("")); void dump(StdStrBuf Dump = StdStrBuf("")); }; @@ -298,6 +303,8 @@ class C4AulFunc }; +inline C4AulScriptFunc *C4AulScriptContext::SFunc() { return Func->SFunc(); } + // script function class class C4AulScriptFunc : public C4AulFunc { @@ -351,7 +358,6 @@ class C4AulScriptFunc : public C4AulFunc friend class C4AulScript; }; - // defined function class class C4AulDefFunc : C4AulFunc { @@ -518,7 +524,6 @@ class C4AulScript friend class C4AulParseState; }; - // holds all C4AulScripts class C4AulScriptEngine : public C4AulScript { @@ -526,6 +531,7 @@ class C4AulScriptEngine : public C4AulScript C4AList itbl; // include table C4AList atbl; // append table C4AulFuncMap FuncLookUp; + C4AulDebug *pDebug; public: int warnCnt, errCnt; // number of warnings/errors @@ -568,6 +574,10 @@ class C4AulScriptEngine : public C4AulScript BOOL DenumerateVariablePointers(); void UnLink(); // called when a script is being reloaded (clears string table) + + bool InitDebug(uint16_t iPort, const char *szPassword, const char *szHost, bool fWait); + C4AulDebug *GetDebugger() const { return pDebug; } + // Compile scenario script data (without strings and constants) void CompileFunc(StdCompiler *pComp); diff --git a/engine/inc/C4AulDebug.h b/engine/inc/C4AulDebug.h new file mode 100644 index 000000000..506bdbabe --- /dev/null +++ b/engine/inc/C4AulDebug.h @@ -0,0 +1,68 @@ + +#ifndef C4AULDEBUG_H +#define C4AULDEBUG_H + +#include "C4Aul.h" +#include "C4NetIO.h" + +// manages a debugging interface +class C4AulDebug : public C4NetIOTCP, private C4NetIO::CBClass + { + public: + C4AulDebug(); + ~C4AulDebug(); + + private: + bool fInit, fConnected; + class C4AulExec *pExec; + C4NetIO::addr_t PeerAddr, AllowedAddr; + StdCopyStrBuf Password; + + enum DebugState + { + DS_Go, // execute until next break point + DS_Stop, // execution stopped + DS_Step, // executing until next step point + DS_StepOver, // executung until next step point on same level or above (or break point) + DS_StepOut // executing until next step point above (or break point) + }; + DebugState eState; + int iStepCallDepth; + + private: + + // Overridden + virtual void PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf); + virtual size_t UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr); + + // Callbacks + bool OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO); + void OnDisconn(const C4NetIO::addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason); + void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO); + + public: + bool isConnected() const { return fConnected; } + + void SetPassword(const char *szPassword) { Password = szPassword; } + bool SetAllowed(const char *szHost); + void SetEngine(class C4AulExec *pnExec) { pExec = pnExec; } + + bool Init(uint16_t iPort); + bool Close(); + + void OnLog(const char *szLine); + void DebugStep(C4AulBCC *pCPos); + void DebugStepIn(C4AulBCC *pCPos); + void DebugStepOut(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value *pRVal); + + private: + void StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx = NULL, C4Value *pRVal = NULL); + + StdStrBuf FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos); + + void ProcessLine(const StdStrBuf &Line); + + bool SendLine(const char *szType, const char *szData = NULL); + }; + +#endif \ No newline at end of file diff --git a/engine/inc/C4AulExec.h b/engine/inc/C4AulExec.h new file mode 100644 index 000000000..f4533d7a5 --- /dev/null +++ b/engine/inc/C4AulExec.h @@ -0,0 +1,152 @@ + +#ifndef C4AULEXEC_H +#define C4AULEXEC_H + +const int MAX_CONTEXT_STACK = 512; +const int MAX_VALUE_STACK = 1024; + +class C4AulExec + { + + public: + C4AulExec() + : pCurCtx(Contexts - 1), pCurVal(Values - 1), iTraceStart(-1) + { } + + private: + C4AulScriptContext Contexts[MAX_CONTEXT_STACK]; + C4Value Values[MAX_VALUE_STACK]; + + C4AulScriptContext *pCurCtx; + C4Value *pCurVal; + + int iTraceStart; + bool fProfiling; + time_t tDirectExecStart, tDirectExecTotal; // profiler time for DirectExec + C4AulScript *pProfiledScript; + + public: + C4Value Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value pPars[], bool fPassErrors, bool fTemporaryScript = false); + C4Value Exec(C4AulBCC *pCPos, bool fPassErrors); + + void StartTrace(); + void StartProfiling(C4AulScript *pScript); // resets profling times and starts recording the times + void StopProfiling(); // stop the profiler and displays results + void AbortProfiling() { fProfiling=false; } + inline void StartDirectExec() { if (fProfiling) tDirectExecStart = timeGetTime(); } + inline void StopDirectExec() { if (fProfiling) tDirectExecTotal += timeGetTime() - tDirectExecStart; } + + int GetContextDepth() const { return pCurCtx - Contexts + 1; } + C4AulScriptContext *GetContext(int iLevel) { return iLevel >= 0 && iLevel < GetContextDepth() ? Contexts + iLevel : NULL; } + + private: + + void PushContext(const C4AulScriptContext &rContext); + void PopContext(); + + void CheckOverflow(int iCnt) + { + if(ValueStackSize() + iCnt > MAX_VALUE_STACK) + throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack overflow!"); + } + + void PushString(C4String * Str) + { + CheckOverflow(1); + (++pCurVal)->SetString(Str); + } + + void PushArray(C4ValueArray * Array) + { + CheckOverflow(1); + (++pCurVal)->SetArray(Array); + } + + void PushValue(const C4Value &rVal) + { + CheckOverflow(1); + (++pCurVal)->Set(rVal); + } + + void PushValueRef(C4Value &rVal) + { + CheckOverflow(1); + (++pCurVal)->SetRef(&rVal); + } + + void PushNullVals(int iCnt) + { + CheckOverflow(iCnt); + pCurVal += iCnt; + } + + bool PopValue() + { + if(LocalValueStackSize() < 1) + throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); + (pCurVal--)->Set0(); + return true; + } + + void PopValues(int n) + { + if(LocalValueStackSize() < n) + throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); + while(n--) + (pCurVal--)->Set0(); + } + + void PopValuesUntil(C4Value *pUntilVal) + { + if(pUntilVal < Values - 1) + throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); + while(pCurVal > pUntilVal) + (pCurVal--)->Set0(); + } + + int ContextStackSize() const + { + return pCurCtx - Contexts + 1; + } + + int ValueStackSize() const + { + return pCurVal - Values + 1; + } + + int LocalValueStackSize() const + { + return ContextStackSize() + ? pCurVal - pCurCtx->Vars - pCurCtx->Func->SFunc()->VarNamed.iSize + 1 + : pCurVal - Values + 1; + } + + void CheckOpPars(int iOpID) + { + // Get parameters + C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal; + + // Typecheck parameters + if(!pPar1->ConvertTo(C4ScriptOpMap[iOpID].Type1)) + throw new C4AulExecError(pCurCtx->Obj, + FormatString("operator \"%s\" left side: got \"%s\", but expected \"%s\"!", + C4ScriptOpMap[iOpID].Identifier, pPar1->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); + if(!pPar2->ConvertTo(C4ScriptOpMap[iOpID].Type2)) + throw new C4AulExecError(pCurCtx->Obj, + FormatString("operator \"%s\" right side: got \"%s\", but expected \"%s\"!", + C4ScriptOpMap[iOpID].Identifier, pPar2->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type2)).getData()); + } + void CheckOpPar(int iOpID) + { + // Typecheck parameter + if(!pCurVal->ConvertTo(C4ScriptOpMap[iOpID].Type1)) + throw new C4AulExecError(pCurCtx->Obj, + FormatString("operator \"%s\": got \"%s\", but expected \"%s\"!", + C4ScriptOpMap[iOpID].Identifier, pCurVal->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); + } + C4AulBCC *Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4Object *pObj = NULL, C4Def *pDef = NULL); + }; + +extern C4AulExec AulExec; + +#endif // C4AULEXEC_H \ No newline at end of file diff --git a/engine/inc/C4Game.h b/engine/inc/C4Game.h index 32280dd1e..96e35d077 100644 --- a/engine/inc/C4Game.h +++ b/engine/inc/C4Game.h @@ -191,7 +191,11 @@ class C4Game bool DebugMode; // next mission to be played after this one StdCopyStrBuf NextMission, NextMissionText, NextMissionDesc; - + + private: + // debug settings + uint16_t DebugPort; StdStrBuf DebugPassword, DebugHost; bool DebugWait; + public: // Init and execution void Default(); diff --git a/engine/src/C4Aul.cpp b/engine/src/C4Aul.cpp index 2076d0451..6d3d07ada 100644 --- a/engine/src/C4Aul.cpp +++ b/engine/src/C4Aul.cpp @@ -18,8 +18,11 @@ #include #include +#include +#include #ifndef BIG_C4INCLUDE +#include #include #include #include @@ -421,6 +424,8 @@ C4AulScriptEngine::C4AulScriptEngine(): GlobalConstNames.Reset(); GlobalConsts.Reset(); GlobalConsts.SetNameList(&GlobalConstNames); + + pDebug = NULL; } @@ -428,6 +433,8 @@ C4AulScriptEngine::~C4AulScriptEngine() { Clear(); } void C4AulScriptEngine::Clear() { + // stop debugger + delete pDebug; pDebug = NULL; // clear inherited C4AulScript::Clear(); // clear own stuff @@ -490,6 +497,7 @@ BOOL C4AulScriptEngine::DenumerateVariablePointers() // runtime data only: don't denumerate consts return TRUE; } + void C4AulScriptEngine::CompileFunc(StdCompiler *pComp) { pComp->Value(mkNamingAdapt(Global, "Globals" , C4ValueList())); @@ -497,6 +505,33 @@ void C4AulScriptEngine::CompileFunc(StdCompiler *pComp) GlobalNamedDefault.SetNameList(&GlobalNamedNames); pComp->Value(mkNamingAdapt(GlobalNamed, "GlobalNamed" , GlobalNamedDefault)); } + +bool C4AulScriptEngine::InitDebug(uint16_t iPort, const char *szPassword, const char *szHost, bool fWait) + { + // Create debug object + if(!pDebug) pDebug = new C4AulDebug(); + // Initialize + pDebug->SetPassword(szPassword); + pDebug->SetAllowed(szHost); + pDebug->SetEngine(&AulExec); + if(!pDebug->Init(iPort)) + { LogFatal("C4Aul debugger failed to initialize!"); return false; } + // Log + LogF("C4Aul debugger initialized on port %d", iPort); + // Add to application + Application.Add(pDebug); + // Wait for connection + if(fWait) + { + Log("C4Aul debugger waiting for connection..."); + while(!pDebug->isConnected()) + if(!Application.ScheduleProcs()) + return false; + } + // Done + return true; + } + /*--- C4AulFuncMap ---*/ static const size_t CapacityInc = 1024; diff --git a/engine/src/C4AulDebug.cpp b/engine/src/C4AulDebug.cpp new file mode 100644 index 000000000..bbb469b3a --- /dev/null +++ b/engine/src/C4AulDebug.cpp @@ -0,0 +1,329 @@ + +#include "C4Include.h" + +#include "C4AulDebug.h" +#include "C4AulExec.h" + +#ifndef BIG_C4INCLUDE +#include "C4Control.h" +#include "C4Game.h" +#endif + +// *** C4AulDebug + +C4AulDebug::C4AulDebug() + : fInit(false), fConnected(false) + { + ZeroMem(&PeerAddr, sizeof PeerAddr); + } + +C4AulDebug::~C4AulDebug() + { + } + +void C4AulDebug::PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf) + { + // Enlarge buffer + int iSize = rPacket.getSize(), + iPos = rOutBuf.getSize(); + rOutBuf.Grow(iSize + 2); + // Write packet + rOutBuf.Write(rPacket, iPos); + // Terminate + uint8_t *pPos = getMBufPtr(rOutBuf, iPos + iSize); + *pPos = '\r'; *(pPos + 1) = '\n'; + } + +size_t C4AulDebug::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) + { + // Find line seperation + const char *pSep = reinterpret_cast(memchr(rInBuf.getData(), '\n', rInBuf.getSize())); + if(!pSep) + return 0; + // Check if it's windows-style seperation + int iSize = pSep - getBufPtr(rInBuf) + 1, + iLength = iSize - 1; + if(iLength && *(pSep - 1) == '\r') + iLength--; + // Copy the line + StdStrBuf Buf; Buf.Copy(getBufPtr(rInBuf), iLength); + // Password line? + if(fConnected) + ProcessLine(Buf); + else if(!Password.getSize() || Password == Buf) + { + fConnected = true; + SendLine("HLO", "This is " C4ENGINEINFOLONG ", " C4VERSION); + Log("C4Aul debugger connected successfully!"); + } + else + C4NetIOTCP::Close(PeerAddr); + // Consume line + return iSize; + } + +bool C4AulDebug::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO) + { + assert(pNetIO == this); + // Already have a connection? + if(fConnected) return false; + // Check address + if(AllowedAddr.sin_addr.s_addr) + if(AllowedAddr.sin_addr.s_addr != AddrPeer.sin_addr.s_addr || + (AllowedAddr.sin_port && AllowedAddr.sin_port != AddrPeer.sin_port)) + { + LogF("C4AulDebug blocked connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port)); + return false; + } + // Log + LogF("C4AulDebug got connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port)); + // Accept connection + PeerAddr = AddrPeer; + return true; + } + +void C4AulDebug::OnDisconn(const C4NetIO::addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason) + { + LogF("C4AulDebug lost connection (%s)", szReason); + fConnected = false; + eState = DS_Go; + ZeroMem(&PeerAddr, sizeof PeerAddr); + } + +void C4AulDebug::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) + { + // Won't get called + } + +bool C4AulDebug::SetAllowed(const char *szHost) + { + // Clear + ZeroMem(&AllowedAddr, sizeof(AllowedAddr)); + // No host? + if(!szHost || !*szHost) return true; + // Resolve the address + return ResolveAddress(szHost, &AllowedAddr, 0); + } + +bool C4AulDebug::Init(uint16_t iPort) + { + if(fInit) Close(); + if(iPort == P_NONE) return false; + + // Register self as callback for network events + C4NetIOTCP::SetCallback(this); + + // Start listening + if(!C4NetIOTCP::Init(iPort)) + return false; + + // Okay + fInit = true; + eState = DS_Go; + return true; + } + +bool C4AulDebug::Close() + { + if(!fInit) return true; + fInit = fConnected = false; + return C4NetIOTCP::Close(); + } + +void C4AulDebug::OnLog(const char *szLine) + { + if(!fConnected) return; + SendLine("LOG", szLine); + } + +void C4AulDebug::ProcessLine(const StdStrBuf &Line) + { + // Get command + StdStrBuf Cmd; + Cmd.CopyUntil(Line.getData(), ' '); + // Get data + const char *szData = Line.getPtr(Cmd.getLength()); + if(*szData) szData++; + // Identify command + const char *szCmd = Cmd.getData(); + bool fOkay = true; + const char *szAnswer = NULL; + if(SEqualNoCase(szCmd, "HELP")) + { + fOkay = false; szAnswer = "Yeah, like I'm going to explain that /here/"; + } + else if(SEqualNoCase(szCmd, "BYE") || SEqualNoCase(szCmd, "QUIT")) + C4NetIOTCP::Close(PeerAddr); + else if(SEqualNoCase(szCmd, "SAY")) + Game.Control.DoInput(CID_Message, new C4ControlMessage(C4CMT_Normal, szData), CDT_Direct); + else if(SEqualNoCase(szCmd, "CMD")) + Game.MessageInput.ProcessCommand(szData); + else if(SEqualNoCase(szCmd, "STP") || SEqualNoCase(szCmd, "S")) + eState = DS_Step; + else if(SEqualNoCase(szCmd, "GO") || SEqualNoCase(szCmd, "G")) + eState = DS_Go; + else if(SEqualNoCase(szCmd, "STO") || SEqualNoCase(szCmd, "O")) + eState = DS_StepOver; + else if(SEqualNoCase(szCmd, "STR") || SEqualNoCase(szCmd, "R")) + eState = DS_StepOut; + else if(SEqualNoCase(szCmd, "EXC") || SEqualNoCase(szCmd, "E")) + Game.Control.DoInput(CID_Script, new C4ControlScript(szData, C4ControlScript::SCOPE_Console, false), CDT_Decide); + else if(SEqualNoCase(szCmd, "PSE")) + if(Game.IsPaused()) + { + Game.Unpause(); + szAnswer = "Game unpaused."; + } + else + { + Game.Pause(); + szAnswer = "Game paused."; + } + else + { + fOkay = false; + szAnswer = "Can't do that"; + } + // Send answer + SendLine(fOkay ? "OK" : "ERR", szAnswer); + } + +bool C4AulDebug::SendLine(const char *szType, const char *szData) + { + StdStrBuf Line = szData ? FormatString("%s %s", szType, szData) : StdStrBuf(szType); + return Send(C4NetIOPacket(Line.getData(), Line.getSize(), false, PeerAddr)); + } + +void C4AulDebug::DebugStep(C4AulBCC *pCPos) + { + // Get top context + C4AulScriptContext *pCtx = pExec->GetContext(pExec->GetContextDepth() - 1); + + // Already stopped? Ignore. + // This means we are doing some calculation with suspended script engine. + // We do /not/ want to have recursive suspensions... + if(eState == DS_Stop) + return; + + // Have break point? + if(pCPos->Par.i) + eState = DS_Step; + + StepPoint(pCPos); + } + +void C4AulDebug::DebugStepIn(C4AulBCC *pCPos) + { + + } + +void C4AulDebug::DebugStepOut(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value *pRVal) + { + + // Ignore if already suspended, see above. + if(eState == DS_Stop) + return; + + // This counts as a regular step point + StepPoint(pCPos, pRetCtx, pRVal); + + } + +void C4AulDebug::StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value *pRVal) + { + + // Maybe got a command in the meantime? + Execute(0); + + // Get current script context + int iCallDepth = pExec->GetContextDepth(); + C4AulScriptContext *pCtx = pExec->GetContext(iCallDepth-1); + + // When we're stepping out of a script function, the context of the returning + // function hasn't been removed yet. + if(pCtx == pRetCtx) + { + iCallDepth--; + // Check if we are returning to a script function + if(pCtx->Return) + pCtx--; + else + pCtx = NULL; + } + + // Stepped out? + if(pRVal && eState != DS_Go && iCallDepth <= iStepCallDepth) + { + StdStrBuf FuncDump = pRetCtx->Dump(); + StdStrBuf ReturnDump = pRVal->GetDataString(); + SendLine("RET", FormatString("%s = %s", FuncDump.getData(), ReturnDump.getData()).getData()); + + // Ignore as step point if we didn't "really" step out + if(iCallDepth >= iStepCallDepth) return; + } + + // Stop? + switch(eState) + { + // Continue normally + case DS_Go: return; + + // Always stop + case DS_Stop: break; + case DS_Step: break; + + // Only stop for same level or above + case DS_StepOver: + if(iCallDepth > iStepCallDepth) + return; + break; + + // Only stop above + case DS_StepOut: + if(iCallDepth >= iStepCallDepth) + return; + break; + } + + // Let's stop here + eState = DS_Stop; + iStepCallDepth = iCallDepth; + Game.HaltCount++; + + // No valid stop position? Just continue + if(!pCtx) + { + Game.HaltCount--; + eState = DS_Step; + return; + } + + // Signal + if(pCPos && pCPos->bccType == AB_DEBUG && pCPos->Par.i) + SendLine("STP", FormatString("Stopped on breakpoint %d", pCPos->Par.i).getData()); + else + SendLine("STP", "Stepped"); + + // Position + SendLine("POS", FormatCodePos(pCtx, pCPos).getData()); + + // Suspend until we get some command + while(eState == DS_Stop) + if(!Application.ScheduleProcs()) + { + Close(); + return; + } + + // Do whatever we've been told. + Game.HaltCount--; + } + +StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos) + { + // Get position in script + const char *szScript = pCtx->SFunc()->pOrgScript->GetScript(); + int iLine = SGetLine(szScript, pCPos->SPos); + // Format + return FormatString("%s:%d", Config.AtRelativePath(pCtx->Func->Owner->ScriptName.getData()), iLine); + } diff --git a/engine/src/C4AulExec.cpp b/engine/src/C4AulExec.cpp index c6caca9d6..2888ab510 100644 --- a/engine/src/C4AulExec.cpp +++ b/engine/src/C4AulExec.cpp @@ -18,6 +18,8 @@ #include #include +#include +#include #ifndef BIG_C4INCLUDE #include @@ -26,6 +28,8 @@ #include #endif +C4AulExec AulExec; + C4AulExecError::C4AulExecError(C4Object *pObj, const char *szError) : cObj(pObj) { // direct error message string @@ -46,38 +50,35 @@ void C4AulExecError::show() #endif } -const int MAX_CONTEXT_STACK = 512; -const int MAX_VALUE_STACK = 1024; - -void C4AulScriptContext::dump(StdStrBuf Dump) - { +StdStrBuf C4AulScriptContext::Dump(StdStrBuf Dump) +{ bool fDirectExec = !*Func->Name; if(!fDirectExec) - { + { // Function name Dump.Append(Func->Name); // Parameters Dump.AppendChar('('); int iNullPars = 0; - for(int i = 0; i < C4AUL_MAX_Par; i++) + for(int i = 0; i < Func->GetParCount(); i++) if(Pars + i < Vars) if(!Pars[i]) iNullPars++; else - { + { if(i > iNullPars) Dump.AppendChar(','); // Insert missing null parameters while(iNullPars > 0) - { + { Dump.Append("0,"); iNullPars--; - } + } // Insert parameter Dump.Append(Pars[i].GetDataString()); - } + } Dump.AppendChar(')'); - } + } else Dump.Append(Func->Owner->ScriptName); // Context @@ -85,192 +86,26 @@ void C4AulScriptContext::dump(StdStrBuf Dump) Dump.AppendFormat(" (obj %s)", C4VObj(Obj).GetDataString().getData()); else if(Func->Owner->Def != NULL) Dump.AppendFormat(" (def %s)", Func->Owner->Def->Name.getData()); + return Dump; +} + +StdStrBuf C4AulScriptContext::DumpVerbose(StdStrBuf Dump) +{ + bool fDirectExec = !*Func->Name; + // Dump function and context + Dump = this->Dump(Dump); // Script - if(!fDirectExec && Func->Owner) + if(!fDirectExec && Func->Owner && SFunc()) Dump.AppendFormat(" (%s:%d)", - Func->pOrgScript->ScriptName.getData(), - SGetLine(Func->pOrgScript->GetScript(), CPos ? CPos->SPos : Func->Script)); - // Log it - DebugLog(Dump.getData()); - } + SFunc()->pOrgScript->ScriptName.getData(), + SGetLine(SFunc()->pOrgScript->GetScript(), CPos ? CPos->SPos : SFunc()->Script)); + return Dump; +} -class C4AulExec - { - - public: - C4AulExec() - : pCurCtx(Contexts - 1), pCurVal(Values - 1), iTraceStart(-1) - { } - - private: - C4AulScriptContext Contexts[MAX_CONTEXT_STACK]; - C4Value Values[MAX_VALUE_STACK]; - - C4AulScriptContext *pCurCtx; - C4Value *pCurVal; - - int iTraceStart; - bool fProfiling; - time_t tDirectExecStart, tDirectExecTotal; // profiler time for DirectExec - C4AulScript *pProfiledScript; - - public: - C4Value Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value pPars[], bool fPassErrors, bool fTemporaryScript = false); - C4Value Exec(C4AulBCC *pCPos, bool fPassErrors); - - void StartTrace(); - void StartProfiling(C4AulScript *pScript); // resets profling times and starts recording the times - void StopProfiling(); // stop the profiler and displays results - void AbortProfiling() { fProfiling=false; } - inline void StartDirectExec() { if (fProfiling) tDirectExecStart = timeGetTime(); } - inline void StopDirectExec() { if (fProfiling) tDirectExecTotal += timeGetTime() - tDirectExecStart; } - - private: - - void PushContext(const C4AulScriptContext &rContext) - { - if(pCurCtx >= Contexts + MAX_CONTEXT_STACK - 1) - throw new C4AulExecError(pCurCtx->Obj, "context stack overflow!"); - *++pCurCtx = rContext; - // Trace? - if(iTraceStart >= 0) - { - StdStrBuf Buf("T"); - Buf.AppendChars('>', ContextStackSize() - iTraceStart); - pCurCtx->dump(Buf); - } - // Profiler: Safe time to measure difference afterwards - if (fProfiling) pCurCtx->tTime = timeGetTime(); - } - - void PopContext() - { - if(pCurCtx < Contexts) - throw new C4AulExecError(pCurCtx->Obj, "context stack underflow!"); - // Profiler adding up times - if (fProfiling) - { - time_t dt = timeGetTime() - pCurCtx->tTime; - if (dt && pCurCtx->Func) - pCurCtx->Func->tProfileTime += dt; - } - // Trace done? - if(iTraceStart >= 0) - { - if(ContextStackSize() <= iTraceStart) - { - iTraceStart = -1; - } - } - if(pCurCtx->TemporaryScript) - delete pCurCtx->Func->Owner; - pCurCtx--; - } - - void CheckOverflow(int iCnt) - { - if(ValueStackSize() + iCnt > MAX_VALUE_STACK) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack overflow!"); - } - - void PushString(C4String * Str) - { - CheckOverflow(1); - (++pCurVal)->SetString(Str); - } - - void PushArray(C4ValueArray * Array) - { - CheckOverflow(1); - (++pCurVal)->SetArray(Array); - } - - void PushValue(const C4Value &rVal) - { - CheckOverflow(1); - (++pCurVal)->Set(rVal); - } - - void PushValueRef(C4Value &rVal) - { - CheckOverflow(1); - (++pCurVal)->SetRef(&rVal); - } - - void PushNullVals(int iCnt) - { - CheckOverflow(iCnt); - pCurVal += iCnt; - } - - bool PopValue() - { - if(LocalValueStackSize() < 1) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); - (pCurVal--)->Set0(); - return true; - } - - void PopValues(int n) - { - if(LocalValueStackSize() < n) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); - while(n--) - (pCurVal--)->Set0(); - } - - void PopValuesUntil(C4Value *pUntilVal) - { - if(pUntilVal < Values - 1) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); - while(pCurVal > pUntilVal) - (pCurVal--)->Set0(); - } - - int ContextStackSize() const - { - return pCurCtx - Contexts + 1; - } - - int ValueStackSize() const - { - return pCurVal - Values + 1; - } - - int LocalValueStackSize() const - { - return ContextStackSize() - ? pCurVal - pCurCtx->Vars - pCurCtx->Func->VarNamed.iSize + 1 - : pCurVal - Values + 1; - } - - void CheckOpPars(int iOpID) - { - // Get parameters - C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal; - - // Typecheck parameters - if(!pPar1->ConvertTo(C4ScriptOpMap[iOpID].Type1)) - throw new C4AulExecError(pCurCtx->Obj, - FormatString("operator \"%s\" left side: got \"%s\", but expected \"%s\"!", - C4ScriptOpMap[iOpID].Identifier, pPar1->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); - if(!pPar2->ConvertTo(C4ScriptOpMap[iOpID].Type2)) - throw new C4AulExecError(pCurCtx->Obj, - FormatString("operator \"%s\" right side: got \"%s\", but expected \"%s\"!", - C4ScriptOpMap[iOpID].Identifier, pPar2->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type2)).getData()); - } - void CheckOpPar(int iOpID) - { - // Typecheck parameter - if(!pCurVal->ConvertTo(C4ScriptOpMap[iOpID].Type1)) - throw new C4AulExecError(pCurCtx->Obj, - FormatString("operator \"%s\": got \"%s\", but expected \"%s\"!", - C4ScriptOpMap[iOpID].Identifier, pCurVal->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); - } - C4AulBCC *Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4Object *pObj = NULL, C4Def *pDef = NULL); - }; - -C4AulExec AulExec; +void C4AulScriptContext::dump(StdStrBuf Dump) +{ + DebugLog(DumpVerbose(Dump).getData()); +} C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value *pnPars, bool fPassErrors, bool fTemporaryScript) { @@ -312,6 +147,10 @@ C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value *pnPars C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) { + // Debugger pointer + C4AulDebug * const pDebug = Game.ScriptEngine.GetDebugger(); + pDebug->DebugStepIn(pCPos); + // Save start context C4AulScriptContext *pOldCtx = pCurCtx; @@ -821,7 +660,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) case AB_RETURN: { // Resolve reference - if(!pCurCtx->Func->SFunc()->bReturnRef) + C4AulFunc *pFunc = pCurCtx->Func; + if(!pFunc->SFunc()->bReturnRef) pCurVal->Deref(); // Trace @@ -832,8 +672,12 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) LogF("%s%s returned %s", Buf.getData(), pCurCtx->Func->Name, pCurVal->GetDataString().getData()); } - // External call? + // Notify debugger C4Value *pReturn = pCurCtx->Return; + if(pDebug) + pDebug->DebugStepOut(pReturn ? (pCurCtx-1)->CPos + 1 : NULL, pCurCtx, pCurVal); + + // External call? if(!pReturn) { // Get return value and stop executing. @@ -1011,6 +855,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) break; } + case AB_DEBUG: + if(pDebug) pDebug->DebugStep(pCPos); + break; + default: assert(false); } @@ -1094,6 +942,10 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 ctx.CPos = NULL; PushContext(ctx); + // Notify debugger + if(C4AulDebug *pDebug = Game.ScriptEngine.GetDebugger()) + pDebug->DebugStepIn(pSFunc->Code); + // Jump to code return pSFunc->Code; } @@ -1106,7 +958,6 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 CallCtx.Def = pDef; CallCtx.Caller = pCurCtx; - #ifdef DEBUGREC_SCRIPT if (Game.FrameCounter >= DEBUGREC_START_FRAME) { @@ -1139,20 +990,43 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 AddDbgRec(RCT_AulFunc, sCallText.getData(), sCallText.getLength()+1); } #endif + // Execute #ifdef _DEBUG C4AulScriptContext *pCtx = pCurCtx; -#endif - if(pReturn > pCurVal) - PushValue(pFunc->Exec(&CallCtx, pPars, true)); - else - pReturn->Set(pFunc->Exec(&CallCtx, pPars, true)); +#endif + C4Value RVal(pFunc->Exec(&CallCtx, pPars, true)); #ifdef _DEBUG assert(pCtx == pCurCtx); #endif - // Remove parameters from stack - PopValuesUntil(pReturn); + // Notify debugger + if(C4AulDebug *pDebug = Game.ScriptEngine.GetDebugger()) + { + // Make dummy context + C4AulScriptContext ctx; + ctx.Obj = pObj; + ctx.Def = pDef; + ctx.Caller = pCurCtx; + ctx.Return = pReturn; + ctx.Pars = pPars; + ctx.Vars = pPars + pFunc->GetParCount(); + ctx.Func = pFunc; + ctx.TemporaryScript = false; + ctx.CPos = NULL; + pDebug->DebugStepOut(pCurCtx->CPos + 1, &ctx, &RVal); + } + + // Save return value onto stack + if(pReturn > pCurVal) + PushValue(pFunc->Exec(&CallCtx, pPars, true)); + else + { + pReturn->Set(pFunc->Exec(&CallCtx, pPars, true)); + + // Remove parameters from stack + PopValuesUntil(pReturn); + } // Continue return NULL; @@ -1198,6 +1072,46 @@ void C4AulExec::StopProfiling() Profiler.Show(); } +void C4AulExec::PushContext(const C4AulScriptContext &rContext) +{ + if(pCurCtx >= Contexts + MAX_CONTEXT_STACK - 1) + throw new C4AulExecError(pCurCtx->Obj, "context stack overflow!"); + *++pCurCtx = rContext; + // Trace? + if(iTraceStart >= 0) + { + StdStrBuf Buf("T"); + Buf.AppendChars('>', ContextStackSize() - iTraceStart); + pCurCtx->dump(Buf); + } + // Profiler: Safe time to measure difference afterwards + if (fProfiling) pCurCtx->tTime = timeGetTime(); +} + +void C4AulExec::PopContext() +{ + if(pCurCtx < Contexts) + throw new C4AulExecError(pCurCtx->Obj, "context stack underflow!"); + // Profiler adding up times + if (fProfiling) + { + time_t dt = timeGetTime() - pCurCtx->tTime; + if (dt && pCurCtx->Func) + pCurCtx->SFunc()->tProfileTime += dt; + } + // Trace done? + if(iTraceStart >= 0) + { + if(ContextStackSize() <= iTraceStart) + { + iTraceStart = -1; + } + } + if(pCurCtx->TemporaryScript) + delete pCurCtx->Func->Owner; + pCurCtx--; +} + void C4AulProfiler::StartProfiling(C4AulScript *pScript) { AulExec.StartProfiling(pScript); diff --git a/engine/src/C4AulParse.cpp b/engine/src/C4AulParse.cpp index 175898a51..f139a4d82 100644 --- a/engine/src/C4AulParse.cpp +++ b/engine/src/C4AulParse.cpp @@ -1102,6 +1102,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X) case AB_EOF: case AB_JUMP: case AB_CALLNS: + case AB_DEBUG: break; case AB_STACK: @@ -1777,6 +1778,7 @@ void C4AulParseState::Parse_Function() C4AulBCC * CPos = a->GetCodeByPos(Max(a->GetCodePos() - 1,0)); if (!CPos || CPos->bccType != AB_RETURN || fJump) { + AddBCC(AB_DEBUG); AddBCC(AB_INT); AddBCC(AB_RETURN); } @@ -1819,6 +1821,7 @@ void C4AulParseState::Parse_Block() } void C4AulParseState::Parse_Statement() { + AddBCC(AB_DEBUG); switch (TokenType) { // do we have a block start? diff --git a/engine/src/C4Config.cpp b/engine/src/C4Config.cpp index e75ee6846..420e48d48 100644 --- a/engine/src/C4Config.cpp +++ b/engine/src/C4Config.cpp @@ -835,7 +835,6 @@ const char* C4Config::AtDataReadPath(const char *szFilename, bool fPreferWorkdir const char* C4Config::AtDataReadPathCore(const char *szFilename, bool fPreferWorkdir) { - const char *szPath; if (fPreferWorkdir && FileExists(szFilename)) { SCopy(GetWorkingDirectory(),AtPathFilename,_MAX_PATH-1); diff --git a/engine/src/C4Game.cpp b/engine/src/C4Game.cpp index e3952394c..011a08ff0 100644 --- a/engine/src/C4Game.cpp +++ b/engine/src/C4Game.cpp @@ -1706,6 +1706,10 @@ void C4Game::Default() pNetworkStatistics = NULL; iMusicLevel = 100; PlayList.Clear(); + DebugPort = 0; + DebugPassword.Clear(); + DebugHost.Clear(); + DebugWait = false; } void C4Game::Evaluate() @@ -2475,6 +2479,11 @@ BOOL C4Game::LinkScriptEngine() // Set name list for globals ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames); + // Activate debugger if requested + if(DebugPort) + if(!ScriptEngine.InitDebug(DebugPort, DebugPassword.getData(), DebugHost.getData(), DebugWait)) + return false; + return TRUE; } @@ -2967,6 +2976,15 @@ void C4Game::ParseCommandLine(const char *szCmdLine) // additional read-only data path if (SEqual2NoCase(szParameter, "/data:")) Config.General.AddAdditionalDataPath(szParameter + 6); + // debug options + if (SEqual2NoCase(szParameter, "/debug:")) + DebugPort = atoi(szParameter + 7); + if (SEqual2NoCase(szParameter, "/debugpass:")) + DebugPassword = szParameter + 11; + if (SEqual2NoCase(szParameter, "/debughost:")) + DebugHost = szParameter + 11; + if (SEqual2NoCase(szParameter, "/debugwait")) + DebugWait = true; #ifdef _DEBUG // debug configs if (SEqualNoCase(szParameter, "/host")) diff --git a/engine/src/C4Log.cpp b/engine/src/C4Log.cpp index f53b4e577..8f9e6bfa2 100644 --- a/engine/src/C4Log.cpp +++ b/engine/src/C4Log.cpp @@ -19,6 +19,7 @@ #include #include +#include #ifndef BIG_C4INCLUDE #include @@ -149,6 +150,10 @@ bool Log(const char *szMessage) if (iDisableLog) return true; // security if(!szMessage) return false; + + // Pass on to debugger + if(C4AulDebug *pDebug = Game.ScriptEngine.GetDebugger()) + pDebug->OnLog(szMessage); // Pass on to console Console.Out(szMessage); // pass on to lobby diff --git a/engine/src/C4Script.cpp b/engine/src/C4Script.cpp index 961ca091b..94b1dae3b 100644 --- a/engine/src/C4Script.cpp +++ b/engine/src/C4Script.cpp @@ -1405,7 +1405,7 @@ static long FnGetBase(C4AulContext *cthr, C4Object *pObj) static C4ID FnGetMenu(C4AulContext *cthr, C4Object *pObj) { - if (!pObj) pObj=cthr->Obj; if (!pObj) return C4ID(-1); + if (!pObj) pObj=cthr->Obj; if (!pObj) return C4ID(0); if (pObj->Menu && pObj->Menu->IsActive()) return pObj->Menu->GetIdentification(); return C4MN_None; @@ -4637,7 +4637,7 @@ static C4Value FnEval(C4AulContext *cthr, C4Value *strScript_C4V) // execute script in the same object enum C4AulScript::Strict Strict = C4AulScript::MAXSTRICT; if (cthr->Caller) - Strict = cthr->Caller->Func->pOrgScript->Strict; + Strict = cthr->Caller->SFunc()->pOrgScript->Strict; if (cthr->Obj) return cthr->Obj->Def->Script.DirectExec(cthr->Obj, FnStringPar(strScript_C4V->getStr()), "eval", true, Strict); else if (cthr->Def) @@ -4715,7 +4715,7 @@ static C4Value FnVarN(C4AulContext *cthr, C4Value *strName_C4V) if(!cthr->Caller) return C4VNull; // find variable - int32_t iID = cthr->Caller->Func->VarNamed.GetItemNr(strName); + int32_t iID = cthr->Caller->SFunc()->VarNamed.GetItemNr(strName); if(iID < 0) return C4VNull; diff --git a/xcode/Clonk.xcodeproj/project.pbxproj b/xcode/Clonk.xcodeproj/project.pbxproj index 74bd7cdc0..65a29e6a3 100644 --- a/xcode/Clonk.xcodeproj/project.pbxproj +++ b/xcode/Clonk.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ AFFAA14E0C2A896200444B95 /* C4ChatDlg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFFAA14B0C2A896200444B95 /* C4ChatDlg.cpp */; }; AFFAA14F0C2A896200444B95 /* C4InteractiveThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFFAA14C0C2A896200444B95 /* C4InteractiveThread.cpp */; }; AFFAA1500C2A896200444B95 /* C4Network2IRC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFFAA14D0C2A896200444B95 /* C4Network2IRC.cpp */; }; + D0AEFAD70FBF8EC400E2229D /* C4AulDebug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0AEFAD60FBF8EC400E2229D /* C4AulDebug.cpp */; }; D406269A0BB9440C00815E5D /* c4group_ng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D40626990BB9440C00815E5D /* c4group_ng.cpp */; }; D40626A00BB9477A00815E5D /* C4Config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D439CADC0B8CB129001D508B /* C4Config.cpp */; }; D40626A10BB9477A00815E5D /* C4Group.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D439CAF80B8CB12A001D508B /* C4Group.cpp */; }; @@ -284,6 +285,9 @@ AFFAA14B0C2A896200444B95 /* C4ChatDlg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = C4ChatDlg.cpp; sourceTree = ""; }; AFFAA14C0C2A896200444B95 /* C4InteractiveThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = C4InteractiveThread.cpp; sourceTree = ""; }; AFFAA14D0C2A896200444B95 /* C4Network2IRC.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = C4Network2IRC.cpp; sourceTree = ""; }; + D0AEFAA10FBF8E5500E2229D /* C4AulDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = C4AulDebug.h; sourceTree = ""; }; + D0AEFAA20FBF8E5500E2229D /* C4AulExec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = C4AulExec.h; sourceTree = ""; }; + D0AEFAD60FBF8EC400E2229D /* C4AulDebug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C4AulDebug.cpp; sourceTree = ""; }; D40626910BB9418400815E5D /* c4group */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = c4group; sourceTree = BUILT_PRODUCTS_DIR; }; D40626990BB9440C00815E5D /* c4group_ng.cpp */ = {isa = PBXFileReference; fileEncoding = 12; lastKnownFileType = sourcecode.cpp.cpp; name = c4group_ng.cpp; path = ../group/c4group_ng.cpp; sourceTree = SOURCE_ROOT; }; D40626AA0BB947A700815E5D /* C4Update.cpp */ = {isa = PBXFileReference; fileEncoding = 12; lastKnownFileType = sourcecode.cpp.cpp; path = C4Update.cpp; sourceTree = ""; }; @@ -886,6 +890,7 @@ D439CAD10B8CB129001D508B /* src */ = { isa = PBXGroup; children = ( + D0AEFAD60FBF8EC400E2229D /* C4AulDebug.cpp */, 3562890E0DA62F9000FB1482 /* C4MainMenu.cpp */, 3562890F0DA62F9000FB1482 /* C4ObjectMenu.cpp */, 3588FB750DA0FFD2001544C0 /* C4FileSelDlg.cpp */, @@ -1068,6 +1073,8 @@ D45B48A40D6B333A001A7AE2 /* inc */ = { isa = PBXGroup; children = ( + D0AEFAA10FBF8E5500E2229D /* C4AulDebug.h */, + D0AEFAA20FBF8E5500E2229D /* C4AulExec.h */, 356289130DA62FA600FB1482 /* C4MainMenu.h */, 356288E60DA62CAD00FB1482 /* C4ObjectMenu.h */, 3588FB730DA0FFBE001544C0 /* C4FileSelDlg.h */, @@ -1515,6 +1522,7 @@ 356289100DA62F9000FB1482 /* C4MainMenu.cpp in Sources */, 356289110DA62F9000FB1482 /* C4ObjectMenu.cpp in Sources */, 3514CB3A0DBCCE5F00534809 /* OpenURL.cpp in Sources */, + D0AEFAD70FBF8EC400E2229D /* C4AulDebug.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From d7322328350472048b512dace5c7721e4c573304 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Wed, 13 Jan 2010 18:13:40 +0100 Subject: [PATCH 03/15] Uncomment some asserts that prevent the debugger from working on OSX --- src/network/C4NetIO.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/C4NetIO.cpp b/src/network/C4NetIO.cpp index 034f7e87e..04e37f1d0 100644 --- a/src/network/C4NetIO.cpp +++ b/src/network/C4NetIO.cpp @@ -422,7 +422,7 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd * fds) // (mt-safe) if(ret == 0) return true; // flush pipe - assert(fdvec[cfd].fd == Pipe[0]); + //assert(fdvec[cfd].fd == Pipe[0]); if(fdvec[cfd].events & fdvec[cfd].revents) { char c; @@ -446,7 +446,7 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd * fds) // (mt-safe) if(wsaEvents.lNetworkEvents & FD_ACCEPT) #else ++cfd; - assert(fds[cfd].fd == lsock); + //assert(fds[cfd].fd == lsock); // a connection waiting for accept? if(fds[cfd].events & fds[cfd].revents) #endif @@ -480,7 +480,7 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd * fds) // (mt-safe) #else // got connection? ++cfd; - assert(fds[cfd].fd == pWait->sock); + //assert(fds[cfd].fd == pWait->sock); if(fds[cfd].events & fds[cfd].revents) #endif { @@ -535,7 +535,7 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd * fds) // (mt-safe) #else // something to read from socket? ++cfd; - assert(fds[cfd].fd == sock); + //assert(fds[cfd].fd == sock); if(POLLIN & fds[cfd].revents) #endif for(;;) @@ -587,7 +587,7 @@ bool C4NetIOTCP::Execute(int iMaxTime, pollfd * fds) // (mt-safe) #ifdef STDSCHEDULER_USE_EVENTS if(wsaEvents.lNetworkEvents & FD_WRITE) #else - assert(fds[cfd].fd == sock); + //assert(fds[cfd].fd == sock); if(POLLOUT & fds[cfd].revents) #endif // send remaining data From 6333f0e6bae0693b052751b48fa946dace22ec07 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Wed, 13 Jan 2010 18:42:15 +0100 Subject: [PATCH 04/15] Add a NULL check in C4AulScriptContext::ReturnDump and restore put AB_DEBUG chunk before AB_RETURN --- src/script/C4AulExec.cpp | 2 ++ src/script/C4AulParse.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index 2cd5fb0f8..9598e5464 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -54,6 +54,8 @@ const int MAX_VALUE_STACK = 1024; StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump) { + if (!Func) + return StdStrBuf(""); bool fDirectExec = !*Func->Name; if(!fDirectExec) { diff --git a/src/script/C4AulParse.cpp b/src/script/C4AulParse.cpp index 3e70da0cd..60a66ee10 100644 --- a/src/script/C4AulParse.cpp +++ b/src/script/C4AulParse.cpp @@ -1678,6 +1678,7 @@ void C4AulParseState::Parse_Function() Fn = 0; return; */ + AddBCC(AB_DEBUG); AddBCC(AB_NIL); AddBCC(AB_RETURN); } From 250d42fbff81a6a6476758a328caf268103a0d20 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Wed, 13 Jan 2010 19:20:42 +0100 Subject: [PATCH 05/15] Fix C4AulScriptContext::dump so it does not call itself -.- --- src/script/C4AulExec.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index 9598e5464..0f4081b1b 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -95,13 +95,14 @@ StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump) Dump.AppendFormat(" (%s:%d)", Func->pOrgScript->ScriptName.getData(), SGetLine(Func->pOrgScript->GetScript(), CPos ? CPos->SPos : Func->Script)); - // Log it + // Return it return Dump; } void C4AulScriptContext::dump(StdStrBuf Dump) { - dump(ReturnDump(Dump)); + // Log it + DebugLog(ReturnDump(Dump).getData()); } class C4AulExec From 03881cec3f2ca91e4fc367e4c9fdea0d3e45c396 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Wed, 13 Jan 2010 19:26:03 +0100 Subject: [PATCH 06/15] Add C4AulDebug.cpp (was moved from gui) --- src/script/C4AulDebug.cpp | 328 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 src/script/C4AulDebug.cpp diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp new file mode 100644 index 000000000..a7aa91a22 --- /dev/null +++ b/src/script/C4AulDebug.cpp @@ -0,0 +1,328 @@ + +#include +#include +#include +#include +#include + +#include "C4AulDebug.h" +#include "C4AulExec.h" + +// *** C4AulDebug + +C4AulDebug::C4AulDebug() + : fInit(false), fConnected(false) + { + ZeroMem(&PeerAddr, sizeof PeerAddr); + } + +C4AulDebug::~C4AulDebug() + { + } + +void C4AulDebug::PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf) + { + // Enlarge buffer + int iSize = rPacket.getSize(), + iPos = rOutBuf.getSize(); + rOutBuf.Grow(iSize + 2); + // Write packet + rOutBuf.Write(rPacket, iPos); + // Terminate + uint8_t *pPos = getMBufPtr(rOutBuf, iPos + iSize); + *pPos = '\r'; *(pPos + 1) = '\n'; + } + +size_t C4AulDebug::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::addr_t &addr) + { + // Find line seperation + const char *pSep = reinterpret_cast(memchr(rInBuf.getData(), '\n', rInBuf.getSize())); + if(!pSep) + return 0; + // Check if it's windows-style seperation + int iSize = pSep - getBufPtr(rInBuf) + 1, + iLength = iSize - 1; + if(iLength && *(pSep - 1) == '\r') + iLength--; + // Copy the line + StdStrBuf Buf; Buf.Copy(getBufPtr(rInBuf), iLength); + // Password line? + if(fConnected) + ProcessLine(Buf); + else if(!Password.getSize() || Password == Buf) + { + fConnected = true; + SendLine("HLO", "This is " C4ENGINEINFOLONG ", " C4VERSION); + Log("C4Aul debugger connected successfully!"); + } + else + C4NetIOTCP::Close(PeerAddr); + // Consume line + return iSize; + } + +bool C4AulDebug::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO) + { + assert(pNetIO == this); + // Already have a connection? + if(fConnected) return false; + // Check address + if(AllowedAddr.sin_addr.s_addr) + if(AllowedAddr.sin_addr.s_addr != AddrPeer.sin_addr.s_addr || + (AllowedAddr.sin_port && AllowedAddr.sin_port != AddrPeer.sin_port)) + { + LogF("C4AulDebug blocked connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port)); + return false; + } + // Log + LogF("C4AulDebug got connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port)); + // Accept connection + PeerAddr = AddrPeer; + return true; + } + +void C4AulDebug::OnDisconn(const C4NetIO::addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason) + { + LogF("C4AulDebug lost connection (%s)", szReason); + fConnected = false; + eState = DS_Go; + ZeroMem(&PeerAddr, sizeof PeerAddr); + } + +void C4AulDebug::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) + { + // Won't get called + } + +bool C4AulDebug::SetAllowed(const char *szHost) + { + // Clear + ZeroMem(&AllowedAddr, sizeof(AllowedAddr)); + // No host? + if(!szHost || !*szHost) return true; + // Resolve the address + return ResolveAddress(szHost, &AllowedAddr, 0); + } + +bool C4AulDebug::Init(uint16_t iPort) + { + if(fInit) Close(); + if(iPort == P_NONE) return false; + + // Register self as callback for network events + C4NetIOTCP::SetCallback(this); + + // Start listening + if(!C4NetIOTCP::Init(iPort)) + return false; + + // Okay + fInit = true; + eState = DS_Go; + return true; + } + +bool C4AulDebug::Close() + { + if(!fInit) return true; + fInit = fConnected = false; + return C4NetIOTCP::Close(); + } + +void C4AulDebug::OnLog(const char *szLine) + { + if(!fConnected) return; + SendLine("LOG", szLine); + } + +void C4AulDebug::ProcessLine(const StdStrBuf &Line) + { + // Get command + StdStrBuf Cmd; + Cmd.CopyUntil(Line.getData(), ' '); + // Get data + const char *szData = Line.getPtr(Cmd.getLength()); + if(*szData) szData++; + // Identify command + const char *szCmd = Cmd.getData(); + bool fOkay = true; + const char *szAnswer = NULL; + if(SEqualNoCase(szCmd, "HELP")) + { + fOkay = false; szAnswer = "Yeah, like I'm going to explain that /here/"; + } + else if(SEqualNoCase(szCmd, "BYE") || SEqualNoCase(szCmd, "QUIT")) + C4NetIOTCP::Close(PeerAddr); + else if(SEqualNoCase(szCmd, "SAY")) + ::Control.DoInput(CID_Message, new C4ControlMessage(C4CMT_Normal, szData), CDT_Direct); + else if(SEqualNoCase(szCmd, "CMD")) + ::MessageInput.ProcessCommand(szData); + else if(SEqualNoCase(szCmd, "STP") || SEqualNoCase(szCmd, "S")) + eState = DS_Step; + else if(SEqualNoCase(szCmd, "GO") || SEqualNoCase(szCmd, "G")) + eState = DS_Go; + else if(SEqualNoCase(szCmd, "STO") || SEqualNoCase(szCmd, "O")) + eState = DS_StepOver; + else if(SEqualNoCase(szCmd, "STR") || SEqualNoCase(szCmd, "R")) + eState = DS_StepOut; + else if(SEqualNoCase(szCmd, "EXC") || SEqualNoCase(szCmd, "E")) + ::Control.DoInput(CID_Script, new C4ControlScript(szData, C4ControlScript::SCOPE_Console, false), CDT_Decide); + else if(SEqualNoCase(szCmd, "PSE")) + if(Game.IsPaused()) + { + Game.Unpause(); + szAnswer = "Game unpaused."; + } + else + { + Game.Pause(); + szAnswer = "Game paused."; + } + else + { + fOkay = false; + szAnswer = "Can't do that"; + } + // Send answer + SendLine(fOkay ? "OK" : "ERR", szAnswer); + } + +bool C4AulDebug::SendLine(const char *szType, const char *szData) + { + StdStrBuf Line = szData ? FormatString("%s %s", szType, szData) : StdStrBuf(szType); + return Send(C4NetIOPacket(Line.getData(), Line.getSize(), false, PeerAddr)); + } + +void C4AulDebug::DebugStep(C4AulBCC *pCPos) + { + // Get top context + C4AulScriptContext *pCtx = pExec->GetContext(pExec->GetContextDepth() - 1); + + // Already stopped? Ignore. + // This means we are doing some calculation with suspended script engine. + // We do /not/ want to have recursive suspensions... + if(eState == DS_Stop) + return; + + // Have break point? + if(pCPos->Par.i) + eState = DS_Step; + + StepPoint(pCPos); + } + +void C4AulDebug::DebugStepIn(C4AulBCC *pCPos) + { + + } + +void C4AulDebug::DebugStepOut(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value *pRVal) + { + + // Ignore if already suspended, see above. + if(eState == DS_Stop) + return; + + // This counts as a regular step point + StepPoint(pCPos, pRetCtx, pRVal); + + } + +void C4AulDebug::StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value *pRVal) + { + + // Maybe got a command in the meantime? + Execute(0); + + // Get current script context + int iCallDepth = pExec->GetContextDepth(); + C4AulScriptContext *pCtx = pExec->GetContext(iCallDepth-1); + + // When we're stepping out of a script function, the context of the returning + // function hasn't been removed yet. + if(pCtx == pRetCtx) + { + iCallDepth--; + // Check if we are returning to a script function + if(pCtx->Return) + pCtx--; + else + pCtx = NULL; + } + + // Stepped out? + if(pRVal && eState != DS_Go && iCallDepth <= iStepCallDepth) + { + StdStrBuf FuncDump = pRetCtx->ReturnDump(); + StdStrBuf ReturnDump = pRVal->GetDataString(); + SendLine("RET", FormatString("%s = %s", FuncDump.getData(), ReturnDump.getData()).getData()); + + // Ignore as step point if we didn't "really" step out + if(iCallDepth >= iStepCallDepth) return; + } + + // Stop? + switch(eState) + { + // Continue normally + case DS_Go: return; + + // Always stop + case DS_Stop: break; + case DS_Step: break; + + // Only stop for same level or above + case DS_StepOver: + if(iCallDepth > iStepCallDepth) + return; + break; + + // Only stop above + case DS_StepOut: + if(iCallDepth >= iStepCallDepth) + return; + break; + } + + // Let's stop here + eState = DS_Stop; + iStepCallDepth = iCallDepth; + Game.HaltCount++; + + // No valid stop position? Just continue + if(!pCtx) + { + Game.HaltCount--; + eState = DS_Step; + return; + } + + // Signal + if(pCPos && pCPos->bccType == AB_DEBUG && pCPos->Par.i) + SendLine("STP", FormatString("Stopped on breakpoint %d", pCPos->Par.i).getData()); + else + SendLine("STP", "Stepped"); + + // Position + SendLine("POS", FormatCodePos(pCtx, pCPos).getData()); + + // Suspend until we get some command + while(eState == DS_Stop) + if(!Application.ScheduleProcs()) + { + Close(); + return; + } + + // Do whatever we've been told. + Game.HaltCount--; + } + +StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos) + { + // Get position in script + const char *szScript = pCtx->Func->pOrgScript->GetScript(); + int iLine = SGetLine(szScript, pCPos->SPos); + // Format + return FormatString("%s:%d", Config.AtRelativePath(pCtx->Func->Owner->ScriptName.getData()), iLine); + } From 5fb1c7847de13525385bda862a43e1c59d416f87 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Thu, 14 Jan 2010 23:31:38 +0100 Subject: [PATCH 07/15] Fix some merge issues and put C4AulExec class definition into C4AulExec.h --- src/script/C4Aul.h | 2 +- src/script/C4AulExec.cpp | 213 +++------------------------------------ src/script/C4AulExec.h | 61 +++++++++-- 3 files changed, 65 insertions(+), 211 deletions(-) diff --git a/src/script/C4Aul.h b/src/script/C4Aul.h index 54396c166..a51826cf0 100644 --- a/src/script/C4Aul.h +++ b/src/script/C4Aul.h @@ -579,7 +579,7 @@ class C4AulScriptEngine : public C4AulScript void UnLink(); // called when a script is being reloaded (clears string table) bool InitDebug(uint16_t iPort, const char *szPassword, const char *szHost, bool fWait); - C4AulDebug *GetDebugger() const { return pDebug; } + inline C4AulDebug *GetDebugger() const { return pDebug; } // Compile scenario script data (without strings and constants) void CompileFunc(StdCompiler *pComp); diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index 0f4081b1b..3782a5012 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -31,6 +31,10 @@ #include #include +#include + +C4AulExec AulExec; + C4AulExecError::C4AulExecError(C4Object *pObj, const char *szError) : cObj(pObj) { // direct error message string @@ -49,9 +53,6 @@ void C4AulExecError::show() ::Messages.New(C4GM_Global,sMessage,NULL,ANY_OWNER); } -const int MAX_CONTEXT_STACK = 512; -const int MAX_VALUE_STACK = 1024; - StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump) { if (!Func) @@ -105,190 +106,6 @@ void C4AulScriptContext::dump(StdStrBuf Dump) DebugLog(ReturnDump(Dump).getData()); } -class C4AulExec - { - - public: - C4AulExec() - : pCurCtx(Contexts - 1), pCurVal(Values - 1), iTraceStart(-1) - { } - - private: - C4AulScriptContext Contexts[MAX_CONTEXT_STACK]; - C4Value Values[MAX_VALUE_STACK]; - - C4AulScriptContext *pCurCtx; - C4Value *pCurVal; - - int iTraceStart; - bool fProfiling; - time_t tDirectExecStart, tDirectExecTotal; // profiler time for DirectExec - C4AulScript *pProfiledScript; - - public: - C4Value Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value pPars[], bool fPassErrors, bool fTemporaryScript = false); - C4Value Exec(C4AulBCC *pCPos, bool fPassErrors); - - void StartTrace(); - void StartProfiling(C4AulScript *pScript); // resets profling times and starts recording the times - void StopProfiling(); // stop the profiler and displays results - void AbortProfiling() { fProfiling=false; } - inline void StartDirectExec() { if (fProfiling) tDirectExecStart = timeGetTime(); } - inline void StopDirectExec() { if (fProfiling) tDirectExecTotal += timeGetTime() - tDirectExecStart; } - - private: - - void PushContext(const C4AulScriptContext &rContext) - { - if(pCurCtx >= Contexts + MAX_CONTEXT_STACK - 1) - throw new C4AulExecError(pCurCtx->Obj, "context stack overflow!"); - *++pCurCtx = rContext; - // Trace? - if(iTraceStart >= 0) - { - StdStrBuf Buf("T"); - Buf.AppendChars('>', ContextStackSize() - iTraceStart); - pCurCtx->dump(Buf); - } - // Profiler: Safe time to measure difference afterwards - if (fProfiling) pCurCtx->tTime = timeGetTime(); - } - - void PopContext() - { - if(pCurCtx < Contexts) - throw new C4AulExecError(pCurCtx->Obj, "context stack underflow!"); - // Profiler adding up times - if (fProfiling) - { - time_t dt = timeGetTime() - pCurCtx->tTime; - if (dt && pCurCtx->Func) - pCurCtx->Func->tProfileTime += dt; - } - // Trace done? - if(iTraceStart >= 0) - { - if(ContextStackSize() <= iTraceStart) - { - iTraceStart = -1; - } - } - if(pCurCtx->TemporaryScript) - delete pCurCtx->Func->Owner; - pCurCtx--; - } - - void CheckOverflow(int iCnt) - { - if(ValueStackSize() + iCnt > MAX_VALUE_STACK) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack overflow!"); - } - - void PushString(C4String * Str) - { - CheckOverflow(1); - (++pCurVal)->SetString(Str); - } - - void PushArray(C4ValueArray * Array) - { - CheckOverflow(1); - (++pCurVal)->SetArray(Array); - } - - void PushPropList(C4PropList * PropList) - { - CheckOverflow(1); - (++pCurVal)->SetPropList(PropList); - } - - void PushValue(const C4Value &rVal) - { - CheckOverflow(1); - (++pCurVal)->Set(rVal); - } - - void PushValueRef(C4Value &rVal) - { - CheckOverflow(1); - (++pCurVal)->SetRef(&rVal); - } - - void PushNullVals(int iCnt) - { - CheckOverflow(iCnt); - pCurVal += iCnt; - } - - bool PopValue() - { - if(LocalValueStackSize() < 1) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); - (pCurVal--)->Set0(); - return true; - } - - void PopValues(int n) - { - if(LocalValueStackSize() < n) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); - while(n--) - (pCurVal--)->Set0(); - } - - void PopValuesUntil(C4Value *pUntilVal) - { - if(pUntilVal < Values - 1) - throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack underflow!"); - while(pCurVal > pUntilVal) - (pCurVal--)->Set0(); - } - - int ContextStackSize() const - { - return pCurCtx - Contexts + 1; - } - - int ValueStackSize() const - { - return pCurVal - Values + 1; - } - - int LocalValueStackSize() const - { - return ContextStackSize() - ? pCurVal - pCurCtx->Vars - pCurCtx->Func->VarNamed.iSize + 1 - : pCurVal - Values + 1; - } - - void CheckOpPars(int iOpID) - { - // Get parameters - C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal; - - // Typecheck parameters - if(!pPar1->ConvertTo(C4ScriptOpMap[iOpID].Type1)) - throw new C4AulExecError(pCurCtx->Obj, - FormatString("operator \"%s\" left side: got \"%s\", but expected \"%s\"!", - C4ScriptOpMap[iOpID].Identifier, pPar1->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); - if(!pPar2->ConvertTo(C4ScriptOpMap[iOpID].Type2)) - throw new C4AulExecError(pCurCtx->Obj, - FormatString("operator \"%s\" right side: got \"%s\", but expected \"%s\"!", - C4ScriptOpMap[iOpID].Identifier, pPar2->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type2)).getData()); - } - void CheckOpPar(int iOpID) - { - // Typecheck parameter - if(!pCurVal->ConvertTo(C4ScriptOpMap[iOpID].Type1)) - throw new C4AulExecError(pCurCtx->Obj, - FormatString("operator \"%s\": got \"%s\", but expected \"%s\"!", - C4ScriptOpMap[iOpID].Identifier, pCurVal->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); - } - C4AulBCC *Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4Object *pObj = NULL, C4Def *pDef = NULL); - }; - -C4AulExec AulExec; - C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value *pnPars, bool fPassErrors, bool fTemporaryScript) { @@ -857,8 +674,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) case AB_RETURN: { // Resolve reference - C4AulFunc *pFunc = pCurCtx->Func; - if(!pFunc->SFunc()->bReturnRef) + if(!pCurCtx->Func->SFunc()->bReturnRef) pCurVal->Deref(); // Trace @@ -1182,7 +998,10 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 #ifdef _DEBUG C4AulScriptContext *pCtx = pCurCtx; #endif - C4Value RVal(pFunc->Exec(&CallCtx, pPars, true)); + if(pReturn > pCurVal) + PushValue(pFunc->Exec(&CallCtx, pPars, true)); + else + pReturn->Set(pFunc->Exec(&CallCtx, pPars, true)); #ifdef _DEBUG assert(pCtx == pCurCtx); #endif @@ -1201,19 +1020,11 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 ctx.Func = pSFunc; ctx.TemporaryScript = false; ctx.CPos = NULL; - pDebug->DebugStepOut(pCurCtx->CPos + 1, &ctx, &RVal); + pDebug->DebugStepOut(pCurCtx->CPos + 1, &ctx, pReturn); } - // Save return value onto stack - if(pReturn > pCurVal) - PushValue(pFunc->Exec(&CallCtx, pPars, true)); - else - { - pReturn->Set(pFunc->Exec(&CallCtx, pPars, true)); - - // Remove parameters from stack - PopValuesUntil(pReturn); - } + // Remove parameters from stack + PopValuesUntil(pReturn); // Continue return NULL; diff --git a/src/script/C4AulExec.h b/src/script/C4AulExec.h index f4533d7a5..444f1d462 100644 --- a/src/script/C4AulExec.h +++ b/src/script/C4AulExec.h @@ -35,32 +35,75 @@ class C4AulExec void AbortProfiling() { fProfiling=false; } inline void StartDirectExec() { if (fProfiling) tDirectExecStart = timeGetTime(); } inline void StopDirectExec() { if (fProfiling) tDirectExecTotal += timeGetTime() - tDirectExecStart; } - + int GetContextDepth() const { return pCurCtx - Contexts + 1; } C4AulScriptContext *GetContext(int iLevel) { return iLevel >= 0 && iLevel < GetContextDepth() ? Contexts + iLevel : NULL; } private: - void PushContext(const C4AulScriptContext &rContext); - void PopContext(); + void PushContext(const C4AulScriptContext &rContext) + { + if(pCurCtx >= Contexts + MAX_CONTEXT_STACK - 1) + throw new C4AulExecError(pCurCtx->Obj, "context stack overflow!"); + *++pCurCtx = rContext; + // Trace? + if(iTraceStart >= 0) + { + StdStrBuf Buf("T"); + Buf.AppendChars('>', ContextStackSize() - iTraceStart); + pCurCtx->dump(Buf); + } + // Profiler: Safe time to measure difference afterwards + if (fProfiling) pCurCtx->tTime = timeGetTime(); + } + + void PopContext() + { + if(pCurCtx < Contexts) + throw new C4AulExecError(pCurCtx->Obj, "context stack underflow!"); + // Profiler adding up times + if (fProfiling) + { + time_t dt = timeGetTime() - pCurCtx->tTime; + if (dt && pCurCtx->Func) + pCurCtx->Func->tProfileTime += dt; + } + // Trace done? + if(iTraceStart >= 0) + { + if(ContextStackSize() <= iTraceStart) + { + iTraceStart = -1; + } + } + if(pCurCtx->TemporaryScript) + delete pCurCtx->Func->Owner; + pCurCtx--; + } void CheckOverflow(int iCnt) { if(ValueStackSize() + iCnt > MAX_VALUE_STACK) throw new C4AulExecError(pCurCtx->Obj, "internal error: value stack overflow!"); } - + void PushString(C4String * Str) { CheckOverflow(1); (++pCurVal)->SetString(Str); } - + void PushArray(C4ValueArray * Array) { CheckOverflow(1); (++pCurVal)->SetArray(Array); } + + void PushPropList(C4PropList * PropList) + { + CheckOverflow(1); + (++pCurVal)->SetPropList(PropList); + } void PushValue(const C4Value &rVal) { @@ -117,7 +160,7 @@ class C4AulExec int LocalValueStackSize() const { return ContextStackSize() - ? pCurVal - pCurCtx->Vars - pCurCtx->Func->SFunc()->VarNamed.iSize + 1 + ? pCurVal - pCurCtx->Vars - pCurCtx->Func->VarNamed.iSize + 1 : pCurVal - Values + 1; } @@ -128,11 +171,11 @@ class C4AulExec // Typecheck parameters if(!pPar1->ConvertTo(C4ScriptOpMap[iOpID].Type1)) - throw new C4AulExecError(pCurCtx->Obj, + throw new C4AulExecError(pCurCtx->Obj, FormatString("operator \"%s\" left side: got \"%s\", but expected \"%s\"!", C4ScriptOpMap[iOpID].Identifier, pPar1->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); if(!pPar2->ConvertTo(C4ScriptOpMap[iOpID].Type2)) - throw new C4AulExecError(pCurCtx->Obj, + throw new C4AulExecError(pCurCtx->Obj, FormatString("operator \"%s\" right side: got \"%s\", but expected \"%s\"!", C4ScriptOpMap[iOpID].Identifier, pPar2->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type2)).getData()); } @@ -140,7 +183,7 @@ class C4AulExec { // Typecheck parameter if(!pCurVal->ConvertTo(C4ScriptOpMap[iOpID].Type1)) - throw new C4AulExecError(pCurCtx->Obj, + throw new C4AulExecError(pCurCtx->Obj, FormatString("operator \"%s\": got \"%s\", but expected \"%s\"!", C4ScriptOpMap[iOpID].Identifier, pCurVal->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData()); } From db281e3d102f71b6fff35c853242a63924f8a2da Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Fri, 15 Jan 2010 01:47:20 +0100 Subject: [PATCH 08/15] Add C4AulDebug command to toggle breakpoint (TBR) --- src/script/C4Aul.h | 3 ++ src/script/C4AulDebug.cpp | 67 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/script/C4Aul.h b/src/script/C4Aul.h index a51826cf0..46a73c7e8 100644 --- a/src/script/C4Aul.h +++ b/src/script/C4Aul.h @@ -439,6 +439,7 @@ class C4AulScript #ifdef _MSC_VER friend class C4AulScript; #endif + friend class C4AulDebug; public: C4AulScript(); // constructor virtual ~C4AulScript(); // destructor @@ -533,6 +534,7 @@ class C4AulScript // holds all C4AulScripts class C4AulScriptEngine : public C4AulScript { + protected: C4AList itbl; // include table C4AList atbl; // append table @@ -586,6 +588,7 @@ class C4AulScriptEngine : public C4AulScript friend class C4AulFunc; friend class C4AulParseState; + friend class C4AulDebug; }; extern C4AulScriptEngine ScriptEngine; diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index a7aa91a22..cb6952a4e 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "C4AulDebug.h" #include "C4AulExec.h" @@ -178,6 +179,72 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line) Game.Pause(); szAnswer = "Game paused."; } + else if (SEqualNoCase(szCmd, "LST")) + { + for (C4AulScript* script = ScriptEngine.Child0; script; script = script->Next) { + DebugLog(Config.AtRelativePath(script->ScriptName.getData())); + } + } + + // toggle breakpoint + else if (SEqualNoCase(szCmd, "TBR")) + { + StdStrBuf scriptPath; + scriptPath.CopyUntil(szData, ':'); + const char* lineStart = szData+1+scriptPath.getLength(); + int line = strtol(szData+1+scriptPath.getLength(), const_cast(&lineStart), 10); + + C4AulScript* script; + for (script = ScriptEngine.Child0; script; script = script->Next) + { + if (SEqualNoCase(Config.AtRelativePath(script->ScriptName.getData()), scriptPath.getData())) + break; + } + + if (script) + { + C4AulBCC* foundDebugChunk = NULL; + const char* scriptText = script->GetScript(); + for (C4AulBCC* chunk = script->Code; chunk; chunk++) + { + switch (chunk->bccType) { + case AB_DEBUG: + int lineOfThisOne; + if ((lineOfThisOne = SGetLine(scriptText, chunk->SPos)) == line) + { + foundDebugChunk = chunk; + goto Done; + } + /*else { + DebugLogF("Debug chunk at %d", lineOfThisOne); + }*/ + + break; + case AB_EOF: + goto Done; + default: + break; + } + } + Done: + if (foundDebugChunk) + { + foundDebugChunk->Par.i = !foundDebugChunk->Par.i; // activate breakpoint + } + else + { + szAnswer = "Can't set breakpoint (wrong line?)"; + fOkay = false; + } + } + else + { + fOkay = false; + szAnswer = "Can't find script"; + } + + + } else { fOkay = false; From cee326dd57de1f2414cf6708044f2f98cf01c0fa Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Fri, 15 Jan 2010 05:46:16 +0100 Subject: [PATCH 09/15] Debugger: Stack frame support (not finished) --- src/script/C4AulDebug.cpp | 37 +++++++++++++++++++++++++++++++++---- src/script/C4AulDebug.h | 5 +++++ src/script/C4AulExec.cpp | 2 +- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index cb6952a4e..224fc462a 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -18,8 +18,10 @@ C4AulDebug::C4AulDebug() } C4AulDebug::~C4AulDebug() - { - } +{ + for (std::list::iterator it = StackTrace.begin(); it != StackTrace.end(); it++) + {delete *it;} +} void C4AulDebug::PackPacket(const C4NetIOPacket &rPacket, StdBuf &rOutBuf) { @@ -182,7 +184,7 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line) else if (SEqualNoCase(szCmd, "LST")) { for (C4AulScript* script = ScriptEngine.Child0; script; script = script->Next) { - DebugLog(Config.AtRelativePath(script->ScriptName.getData())); + SendLine(Config.AtRelativePath(script->ScriptName.getData())); } } @@ -244,6 +246,15 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line) } + } + else if (SEqualNoCase(szCmd, "SST")) + { + std::list::iterator it = StackTrace.begin(); + for (it++; it != StackTrace.end(); it++) + { + SendLine("AT", (*it)->getData()); + } + SendLine("EST"); } else { @@ -371,7 +382,8 @@ void C4AulDebug::StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value SendLine("STP", "Stepped"); // Position - SendLine("POS", FormatCodePos(pCtx, pCPos).getData()); + ObtainStackTrace(pCtx, pCPos); + SendLine("POS", StackTrace.front()->getData()); // Suspend until we get some command while(eState == DS_Stop) @@ -385,6 +397,23 @@ void C4AulDebug::StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value Game.HaltCount--; } +void C4AulDebug::ObtainStackTrace(C4AulScriptContext* pCtx, C4AulBCC* pCPos) +{ + for (std::list::iterator it = StackTrace.begin(); it != StackTrace.end(); it++) + {delete *it;} + StackTrace.clear(); + for (int ctxNum = pExec->GetContextDepth()-1; ctxNum >= 0; ctxNum--) + { + C4AulScriptContext* c = pExec->GetContext(ctxNum); + C4AulBCC* _cpos = c == pCtx ? pCPos : c->CPos; + if (_cpos) + { + StdStrBuf* format = new StdStrBuf(FormatCodePos(c, _cpos)); + StackTrace.push_back(format); + } + } +} + StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos) { // Get position in script diff --git a/src/script/C4AulDebug.h b/src/script/C4AulDebug.h index 506bdbabe..75b245d5c 100644 --- a/src/script/C4AulDebug.h +++ b/src/script/C4AulDebug.h @@ -28,6 +28,11 @@ class C4AulDebug : public C4NetIOTCP, private C4NetIO::CBClass }; DebugState eState; int iStepCallDepth; + + // temporary stuff + std::list StackTrace; + + void ObtainStackTrace(C4AulScriptContext* pCtx, C4AulBCC* pCPos); private: diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index 3782a5012..33eda2544 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -1020,7 +1020,7 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 ctx.Func = pSFunc; ctx.TemporaryScript = false; ctx.CPos = NULL; - pDebug->DebugStepOut(pCurCtx->CPos + 1, &ctx, pReturn); + pDebug->DebugStepOut(pCurCtx->CPos + 1, pCurCtx, pReturn); } // Remove parameters from stack From 98dfe3dc1a1bb548d14384c396a1373c8b161c9d Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Fri, 15 Jan 2010 15:31:51 +0100 Subject: [PATCH 10/15] Debugger: Return correct script path (pOrgScript) --- src/script/C4AulDebug.cpp | 4 ++-- src/script/C4AulExec.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index 224fc462a..32c2acebf 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -313,7 +313,7 @@ void C4AulDebug::StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value Execute(0); // Get current script context - int iCallDepth = pExec->GetContextDepth(); + int iCallDepth = pExec->GetContextDepth(); C4AulScriptContext *pCtx = pExec->GetContext(iCallDepth-1); // When we're stepping out of a script function, the context of the returning @@ -420,5 +420,5 @@ StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos) const char *szScript = pCtx->Func->pOrgScript->GetScript(); int iLine = SGetLine(szScript, pCPos->SPos); // Format - return FormatString("%s:%d", Config.AtRelativePath(pCtx->Func->Owner->ScriptName.getData()), iLine); + return FormatString("%s:%d", Config.AtRelativePath(pCtx->Func->pOrgScript->ScriptName.getData()), iLine); } diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index 33eda2544..9e43a0354 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -148,7 +148,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) // Debugger pointer C4AulDebug * const pDebug = ::ScriptEngine.GetDebugger(); - pDebug->DebugStepIn(pCPos); + if (pDebug) + pDebug->DebugStepIn(pCPos); // Save start context C4AulScriptContext *pOldCtx = pCurCtx; From a519a5f352f847496484515a737844fabe8c2888 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Sat, 16 Jan 2010 02:32:53 +0100 Subject: [PATCH 11/15] Debugger: Send scenario-relative paths --- src/script/C4AulDebug.cpp | 16 +++++++++++++--- src/script/C4AulDebug.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index 32c2acebf..d1640e716 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -184,7 +184,7 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line) else if (SEqualNoCase(szCmd, "LST")) { for (C4AulScript* script = ScriptEngine.Child0; script; script = script->Next) { - SendLine(Config.AtRelativePath(script->ScriptName.getData())); + SendLine(RelativePath(script->ScriptName)); } } @@ -199,7 +199,7 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line) C4AulScript* script; for (script = ScriptEngine.Child0; script; script = script->Next) { - if (SEqualNoCase(Config.AtRelativePath(script->ScriptName.getData()), scriptPath.getData())) + if (SEqualNoCase(RelativePath(script->ScriptName), scriptPath.getData())) break; } @@ -397,6 +397,16 @@ void C4AulDebug::StepPoint(C4AulBCC *pCPos, C4AulScriptContext *pRetCtx, C4Value Game.HaltCount--; } +const char* C4AulDebug::RelativePath(StdStrBuf &path) +{ + const char* p = path.getData(); + const char* result = Config.AtRelativePath(p); + if (p != result) + return result; + // try scenario-relative path + return GetRelativePathS(p, ::Game.ScenarioFile.GetName()); +} + void C4AulDebug::ObtainStackTrace(C4AulScriptContext* pCtx, C4AulBCC* pCPos) { for (std::list::iterator it = StackTrace.begin(); it != StackTrace.end(); it++) @@ -420,5 +430,5 @@ StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos) const char *szScript = pCtx->Func->pOrgScript->GetScript(); int iLine = SGetLine(szScript, pCPos->SPos); // Format - return FormatString("%s:%d", Config.AtRelativePath(pCtx->Func->pOrgScript->ScriptName.getData()), iLine); + return FormatString("%s:%d", RelativePath(pCtx->Func->pOrgScript->ScriptName), iLine); } diff --git a/src/script/C4AulDebug.h b/src/script/C4AulDebug.h index 75b245d5c..2f6707544 100644 --- a/src/script/C4AulDebug.h +++ b/src/script/C4AulDebug.h @@ -33,6 +33,7 @@ class C4AulDebug : public C4NetIOTCP, private C4NetIO::CBClass std::list StackTrace; void ObtainStackTrace(C4AulScriptContext* pCtx, C4AulBCC* pCPos); + const char* RelativePath(StdStrBuf &path); private: From 7966e59e18845fe282b181ed585d8f24267fa648 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Sat, 16 Jan 2010 05:24:10 +0100 Subject: [PATCH 12/15] Debugger: Not scenario-relative but relative to the scenario's container --- src/script/C4AulDebug.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index d1640e716..0f2daa945 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -403,8 +403,10 @@ const char* C4AulDebug::RelativePath(StdStrBuf &path) const char* result = Config.AtRelativePath(p); if (p != result) return result; - // try scenario-relative path - return GetRelativePathS(p, ::Game.ScenarioFile.GetName()); + // try path relative to scenario container + StdStrBuf scenarioContainerPath; + GetParentPath(::Game.ScenarioFile.GetName(), &scenarioContainerPath); + return GetRelativePathS(p, scenarioContainerPath.getData()); } void C4AulDebug::ObtainStackTrace(C4AulScriptContext* pCtx, C4AulBCC* pCPos) From 9d565fb3fd298491b5145a558e8ad01bb47550a3 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Thu, 21 Jan 2010 16:22:33 +0100 Subject: [PATCH 13/15] Debugger: Add VAR command to query the value of a variable --- src/script/C4AulDebug.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index 0f2daa945..1eb8622bf 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -256,6 +256,25 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line) } SendLine("EST"); } + else if (SEqualNoCase(szCmd, "VAR")) + { + C4Value *val = NULL; + int varIndex; + C4AulScriptContext* pCtx = pExec->GetContext(pExec->GetContextDepth() - 1); + if (pCtx) + { + if ((varIndex = pCtx->Func->ParNamed.GetItemNr(szData)) != -1) + { + val = &pCtx->Pars[varIndex]; + } + else if ((varIndex = pCtx->Func->VarNamed.GetItemNr(szData)) != 1) + { + val = &pCtx->Vars[varIndex]; + } + } + StdStrBuf output = FormatString("%s=%s", szData, val ? val->GetDataString().getData() : "Unknown"); + SendLine("VAR", output.getData()); + } else { fOkay = false; From f3e83b339ef15abeceb4e75016128fc17bc13092 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Fri, 19 Feb 2010 16:01:58 +0100 Subject: [PATCH 14/15] Xcode: Add C4AulDebug.cpp --- xcode/Clonk.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xcode/Clonk.xcodeproj/project.pbxproj b/xcode/Clonk.xcodeproj/project.pbxproj index 63a9dc9eb..46a9b8f12 100644 --- a/xcode/Clonk.xcodeproj/project.pbxproj +++ b/xcode/Clonk.xcodeproj/project.pbxproj @@ -201,6 +201,7 @@ 5804A5E810C4BBC600A26AD0 /* C4Globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58CBBCB710BDF19400FBA25E /* C4Globals.cpp */; }; 5830903A10E11D2200F1AECF /* C4PlayerControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5830903910E11D2200F1AECF /* C4PlayerControl.cpp */; }; 583F3F53110A7E6D00C5E281 /* C4MeshAnimation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 583F3F52110A7E6D00C5E281 /* C4MeshAnimation.cpp */; }; + 58437DEE112EDF2200DFE775 /* C4AulDebug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58437DED112EDF2200DFE775 /* C4AulDebug.cpp */; }; 5862E1191032E57A002CAE9E /* C4Application.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5862DF3B1032E57A002CAE9E /* C4Application.cpp */; }; 5862E11A1032E57A002CAE9E /* C4FullScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5862DF3D1032E57A002CAE9E /* C4FullScreen.cpp */; }; 5862E11B1032E57A002CAE9E /* C4Game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5862DF3F1032E57A002CAE9E /* C4Game.cpp */; }; @@ -501,6 +502,7 @@ 5830903910E11D2200F1AECF /* C4PlayerControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C4PlayerControl.cpp; sourceTree = ""; }; 583F3F51110A7E6D00C5E281 /* C4MeshAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = C4MeshAnimation.h; sourceTree = ""; }; 583F3F52110A7E6D00C5E281 /* C4MeshAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C4MeshAnimation.cpp; sourceTree = ""; }; + 58437DED112EDF2200DFE775 /* C4AulDebug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C4AulDebug.cpp; sourceTree = ""; }; 58508E1C103482EF00533E7D /* StdMacApp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StdMacApp.mm; sourceTree = ""; }; 5862DF3B1032E57A002CAE9E /* C4Application.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C4Application.cpp; sourceTree = ""; }; 5862DF3C1032E57A002CAE9E /* C4Application.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = C4Application.h; sourceTree = ""; }; @@ -1810,6 +1812,7 @@ 5862E1021032E57A002CAE9E /* script */ = { isa = PBXGroup; children = ( + 58437DED112EDF2200DFE775 /* C4AulDebug.cpp */, 588FCF9D103637B700BCF686 /* C4StringTable.h */, 588FCF9E103637B700BCF686 /* C4StringTable.cpp */, 5862E1031032E57A002CAE9E /* C4AList.cpp */, @@ -2402,6 +2405,7 @@ 58E9D4B710F2B267005760F5 /* tinyxmlerror.cpp in Sources */, 58E9D4B810F2B267005760F5 /* tinyxmlparser.cpp in Sources */, 583F3F53110A7E6D00C5E281 /* C4MeshAnimation.cpp in Sources */, + 58437DEE112EDF2200DFE775 /* C4AulDebug.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 2bb528b5d4fc93f199f2f5d61a0cae25a32118c1 Mon Sep 17 00:00:00 2001 From: Martin Plicht Date: Tue, 23 Feb 2010 19:29:26 +0100 Subject: [PATCH 15/15] Define NOAULDEBUG to compile without C4AulDebug --- src/lib/C4Log.cpp | 2 ++ src/script/C4Aul.cpp | 6 ++++++ src/script/C4Aul.h | 4 ++++ src/script/C4AulDebug.cpp | 3 +++ src/script/C4AulDebug.h | 3 +++ src/script/C4AulExec.cpp | 10 ++++++++++ 6 files changed, 28 insertions(+) diff --git a/src/lib/C4Log.cpp b/src/lib/C4Log.cpp index f4c99b311..793182408 100644 --- a/src/lib/C4Log.cpp +++ b/src/lib/C4Log.cpp @@ -160,9 +160,11 @@ bool Log(const char *szMessage) // security if(!szMessage) return false; +#ifndef NOAULDEBUG // Pass on to debugger if(C4AulDebug *pDebug = ::ScriptEngine.GetDebugger()) pDebug->OnLog(szMessage); +#endif // Pass on to console Console.Out(szMessage); // pass on to lobby diff --git a/src/script/C4Aul.cpp b/src/script/C4Aul.cpp index 13bfac4f2..f471dba85 100644 --- a/src/script/C4Aul.cpp +++ b/src/script/C4Aul.cpp @@ -444,7 +444,9 @@ C4AulScriptEngine::C4AulScriptEngine(): GlobalConsts.Reset(); GlobalConsts.SetNameList(&GlobalConstNames); +#ifndef NOAULDEBUG pDebug = NULL; +#endif } @@ -452,8 +454,10 @@ C4AulScriptEngine::~C4AulScriptEngine() { Clear(); } void C4AulScriptEngine::Clear() { +#ifndef NOAULDEBUG // stop debugger delete pDebug; pDebug = NULL; +#endif // clear inherited C4AulScript::Clear(); // clear own stuff @@ -524,6 +528,7 @@ void C4AulScriptEngine::CompileFunc(StdCompiler *pComp) bool C4AulScriptEngine::InitDebug(uint16_t iPort, const char *szPassword, const char *szHost, bool fWait) { +#ifndef NOAULDEBUG // Create debug object if(!pDebug) pDebug = new C4AulDebug(); // Initialize @@ -544,6 +549,7 @@ bool C4AulScriptEngine::InitDebug(uint16_t iPort, const char *szPassword, const if(!Application.ScheduleProcs()) return false; } +#endif // Done return true; } diff --git a/src/script/C4Aul.h b/src/script/C4Aul.h index b5981a7f6..00447b26a 100644 --- a/src/script/C4Aul.h +++ b/src/script/C4Aul.h @@ -540,7 +540,9 @@ class C4AulScriptEngine : public C4AulScript C4AList itbl; // include table C4AList atbl; // append table C4AulFuncMap FuncLookUp; +#ifndef NOAULDEBUG C4AulDebug *pDebug; +#endif public: int warnCnt, errCnt; // number of warnings/errors @@ -583,7 +585,9 @@ class C4AulScriptEngine : public C4AulScript void UnLink(); // called when a script is being reloaded (clears string table) bool InitDebug(uint16_t iPort, const char *szPassword, const char *szHost, bool fWait); +#ifndef NOAULDEBUG inline C4AulDebug *GetDebugger() const { return pDebug; } +#endif // Compile scenario script data (without strings and constants) void CompileFunc(StdCompiler *pComp); diff --git a/src/script/C4AulDebug.cpp b/src/script/C4AulDebug.cpp index 1eb8622bf..c4578bb45 100644 --- a/src/script/C4AulDebug.cpp +++ b/src/script/C4AulDebug.cpp @@ -1,3 +1,4 @@ +#ifndef NOAULDEBUG #include #include @@ -453,3 +454,5 @@ StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos) // Format return FormatString("%s:%d", RelativePath(pCtx->Func->pOrgScript->ScriptName), iLine); } + +#endif \ No newline at end of file diff --git a/src/script/C4AulDebug.h b/src/script/C4AulDebug.h index 2f6707544..6a895b096 100644 --- a/src/script/C4AulDebug.h +++ b/src/script/C4AulDebug.h @@ -2,6 +2,8 @@ #ifndef C4AULDEBUG_H #define C4AULDEBUG_H +#ifndef NOAULDEBUG + #include "C4Aul.h" #include "C4NetIO.h" @@ -71,4 +73,5 @@ class C4AulDebug : public C4NetIOTCP, private C4NetIO::CBClass bool SendLine(const char *szType, const char *szData = NULL); }; +#endif #endif \ No newline at end of file diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index 500cc5ee1..ea49bd7b1 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -151,10 +151,12 @@ C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4Object *pObj, C4Value *pnPars C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) { +#ifndef NOAULDEBUG // Debugger pointer C4AulDebug * const pDebug = ::ScriptEngine.GetDebugger(); if (pDebug) pDebug->DebugStepIn(pCPos); +#endif // Save start context C4AulScriptContext *pOldCtx = pCurCtx; @@ -691,10 +693,12 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) LogF("%s%s returned %s", Buf.getData(), pCurCtx->Func->Name, pCurVal->GetDataString().getData()); } +#ifndef NOAULDEBUG // Notify debugger C4Value *pReturn = pCurCtx->Return; if(pDebug) pDebug->DebugStepOut(pReturn ? (pCurCtx-1)->CPos + 1 : NULL, pCurCtx, pCurVal); +#endif // External call? if(!pReturn) @@ -865,7 +869,9 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) } case AB_DEBUG: +#ifndef NOAULDEBUG if(pDebug) pDebug->DebugStep(pCPos); +#endif break; default: @@ -951,9 +957,11 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 ctx.CPos = NULL; PushContext(ctx); +#ifndef NOAULDEBUG // Notify debugger if(C4AulDebug *pDebug = ::ScriptEngine.GetDebugger()) pDebug->DebugStepIn(pSFunc->Code); +#endif // Jump to code return pSFunc->Code; @@ -1012,6 +1020,7 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 assert(pCtx == pCurCtx); #endif +#ifndef NOAULDEBUG // Notify debugger if(C4AulDebug *pDebug = ::ScriptEngine.GetDebugger()) { @@ -1028,6 +1037,7 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 ctx.CPos = NULL; pDebug->DebugStepOut(pCurCtx->CPos + 1, pCurCtx, pReturn); } +#endif // Remove parameters from stack PopValuesUntil(pReturn);